diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst new file mode 100644 index 0000000000000000000000000000000000000000..c37cae49ec77ad6ebb25568c1605f1fee5313cfb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..f54bb5ca1a59f2696ed5273a531aff9088754da0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA @@ -0,0 +1,113 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.2 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/jinja/ +Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe (>=2.0) +Provides-Extra: i18n +Requires-Dist: Babel (>=2.7) ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + <ul> + {% for user in users %} + <li><a href="{{ user.url }}">{{ user.username }}</a></li> + {% endfor %} + </ul> + {% endblock %} + + +Donate +------ + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://jinja.palletsprojects.com/ +- Changes: https://jinja.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Jinja2/ +- Source Code: https://github.com/pallets/jinja/ +- Issue Tracker: https://github.com/pallets/jinja/issues/ +- Website: https://palletsprojects.com/p/jinja/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..af42ee3ceecffa3bd594d778fb9f930d60e490e0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD @@ -0,0 +1,58 @@ +Jinja2-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.1.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.1.2.dist-info/METADATA,sha256=PZ6v2SIidMNixR7MRUX9f7ZWsPwtXanknqiZUmRbh4U,3539 +Jinja2-3.1.2.dist-info/RECORD,, +Jinja2-3.1.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Jinja2-3.1.2.dist-info/entry_points.txt,sha256=zRd62fbqIyfUpsRtU7EVIFyiu1tPwfgO7EvPErnxgTE,59 +Jinja2-3.1.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=8vGduD8ytwgD6GDSqpYc2m3aU-T7PKOAddvVXgGr_Fs,1927 +jinja2/__pycache__/__init__.cpython-310.pyc,, +jinja2/__pycache__/_identifier.cpython-310.pyc,, +jinja2/__pycache__/async_utils.cpython-310.pyc,, +jinja2/__pycache__/bccache.cpython-310.pyc,, +jinja2/__pycache__/compiler.cpython-310.pyc,, +jinja2/__pycache__/constants.cpython-310.pyc,, +jinja2/__pycache__/debug.cpython-310.pyc,, +jinja2/__pycache__/defaults.cpython-310.pyc,, +jinja2/__pycache__/environment.cpython-310.pyc,, +jinja2/__pycache__/exceptions.cpython-310.pyc,, +jinja2/__pycache__/ext.cpython-310.pyc,, +jinja2/__pycache__/filters.cpython-310.pyc,, +jinja2/__pycache__/idtracking.cpython-310.pyc,, +jinja2/__pycache__/lexer.cpython-310.pyc,, +jinja2/__pycache__/loaders.cpython-310.pyc,, +jinja2/__pycache__/meta.cpython-310.pyc,, +jinja2/__pycache__/nativetypes.cpython-310.pyc,, +jinja2/__pycache__/nodes.cpython-310.pyc,, +jinja2/__pycache__/optimizer.cpython-310.pyc,, +jinja2/__pycache__/parser.cpython-310.pyc,, +jinja2/__pycache__/runtime.cpython-310.pyc,, +jinja2/__pycache__/sandbox.cpython-310.pyc,, +jinja2/__pycache__/tests.cpython-310.pyc,, +jinja2/__pycache__/utils.cpython-310.pyc,, +jinja2/__pycache__/visitor.cpython-310.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=dHlbTeaxFPtAOQEYOGYh_PHcDT0rsDaUJAFDl_0XtTg,2472 +jinja2/bccache.py,sha256=mhz5xtLxCcHRAa56azOhphIAe19u1we0ojifNMClDio,14061 +jinja2/compiler.py,sha256=Gs-N8ThJ7OWK4-reKoO8Wh1ZXz95MVphBKNVf75qBr8,72172 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=6uHIcc7ZblqOMdx_uYNKqRnnwAF0_nzbyeMP9FFtuh4,61349 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=ivr3P7LKbddiXDVez20EflcO3q2aHQwz9P_PgWGHVqE,31502 +jinja2/filters.py,sha256=9js1V-h2RlyW90IhLiBGLM2U-k6SCy2F4BUUMgB3K9Q,53509 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=DW2nX9zk-6MWp65YR2bqqj0xqCvLtD-u9NWT8AnFRxQ,29726 +jinja2/loaders.py,sha256=BfptfvTVpClUd-leMkHczdyPNYFzp_n7PKOJ98iyHOg,23207 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=DXgORDPRmVWgy034H0xL8eF7qYoK3DrMxs-935d0Fzk,4226 +jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=nHd-DFHbiygvfaPtm9rcQXJChZG7DPsWfiEsqfwKerY,39595 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=5CmD5BjbEJxSiDNTFBeKCaq8qU4aYD2v6q2EluyExms,33476 +jinja2/sandbox.py,sha256=Y0xZeXQnH6EX5VjaV2YixESxoepnRbW_3UeQosaBU3M,14584 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=u9jXESxGn8ATZNVolwmkjUVu4SA-tLgV0W7PcSfPfdQ,23965 +jinja2/visitor.py,sha256=MH14C6yq24G_KVtWzjwaI7Wg14PCJIYlWW1kpkxYak0,3568 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..becc9a66ea739ba941d48a749e248761cc6e658a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b9666c8ea311ea0f0cfe7bed861aaa5469f92bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract[i18n] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f7afbf3bf54b346092be6a72070fcbd305ead1e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst new file mode 100644 index 0000000000000000000000000000000000000000..9d227a0cc43c3268d15722b763bd94ad298645a1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..4a34999794616c5aff897a55e028149c7312d894 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/METADATA @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.1.2 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("<script>alert(document.cookie);</script>") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("<strong>Hello</strong>") + Markup('<strong>hello</strong>') + + >>> escape(Markup("<strong>Hello</strong>")) + Markup('<strong>hello</strong>') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello <em>{name}</em>") + >>> template.format(name='"World"') + Markup('Hello <em>"World"</em>') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Website: https://palletsprojects.com/p/markupsafe/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..7234b909c9cde6626090f9504a9b87507b322b49 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.1.2.dist-info/LICENSE.rst,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503 +MarkupSafe-2.1.2.dist-info/METADATA,sha256=ssoeAqYVQV6nsxhzPCWhxmqKxt6n3UYhQgIK6jsKcQA,3320 +MarkupSafe-2.1.2.dist-info/RECORD,, +MarkupSafe-2.1.2.dist-info/WHEEL,sha256=rneS2j8QNmAwdNKHN86s6-qP7AMcWZgqiEoH3bdbh_Y,102 +MarkupSafe-2.1.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=EzD_fL7cQoePn5mS9RLGLMxz7ApdZSTxpgcDStgPYxA,9601 +markupsafe/__pycache__/__init__.cpython-310.pyc,, +markupsafe/__pycache__/_native.cpython-310.pyc,, +markupsafe/_native.py,sha256=_Q7UsXCOvgdonCgqG3l5asANI6eo50EKnDM-mlwEC5M,1776 +markupsafe/_speedups.c,sha256=n3jzzaJwXcoN8nTFyA53f3vSqsWK2vujI-v6QYifjhQ,7403 +markupsafe/_speedups.cp310-win_amd64.pyd,sha256=68o1KFTrqum2P404A3vwjfGNUlJi2EOZaKkL1QWSoNw,15872 +markupsafe/_speedups.pyi,sha256=f5QtwIOP0eLrxh2v5p6SmaYmlcHIGIfmz0DovaqL0OU,238 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..fa053d439497e398f2d6cebf599bc56633363a8b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: false +Tag: cp310-cp310-win_amd64 + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..75bf729258f9daef77370b6df1a57940f90fc23f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/MarkupSafe-2.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/AUTHORS.rst b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/AUTHORS.rst new file mode 100644 index 0000000000000000000000000000000000000000..88e2b6ad752425c0c372874e5b3b7695408e7ee3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/AUTHORS.rst @@ -0,0 +1,7 @@ +Authors +======= + +``pyjwt`` is currently written and maintained by `Jose Padilla <https://github.com/jpadilla>`_. +Originally written and maintained by `Jeff Lindsay <https://github.com/progrium>`_. + +A full list of contributors can be found on GitHub’s `overview <https://github.com/jpadilla/pyjwt/graphs/contributors>`_. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..fd0ecbc889c067a562b3a745c9d2d7934f87d64b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2022 José Padilla + +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/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..5b6ebd5b4bc91894aef9c5a31864d946ae0365b5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/METADATA @@ -0,0 +1,106 @@ +Metadata-Version: 2.1 +Name: PyJWT +Version: 2.6.0 +Summary: JSON Web Token implementation in Python +Home-page: https://github.com/jpadilla/pyjwt +Author: Jose Padilla +Author-email: hello@jpadilla.com +License: MIT +Keywords: json,jwt,security,signing,token,web +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +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: Topic :: Utilities +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Provides-Extra: crypto +Requires-Dist: cryptography (>=3.4.0) ; extra == 'crypto' +Provides-Extra: dev +Requires-Dist: sphinx (<5.0.0,>=4.5.0) ; extra == 'dev' +Requires-Dist: sphinx-rtd-theme ; extra == 'dev' +Requires-Dist: zope.interface ; extra == 'dev' +Requires-Dist: cryptography (>=3.4.0) ; extra == 'dev' +Requires-Dist: pytest (<7.0.0,>=6.0.0) ; extra == 'dev' +Requires-Dist: coverage[toml] (==5.0.4) ; extra == 'dev' +Requires-Dist: pre-commit ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: sphinx (<5.0.0,>=4.5.0) ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme ; extra == 'docs' +Requires-Dist: zope.interface ; extra == 'docs' +Provides-Extra: tests +Requires-Dist: pytest (<7.0.0,>=6.0.0) ; extra == 'tests' +Requires-Dist: coverage[toml] (==5.0.4) ; extra == 'tests' + +PyJWT +===== + +.. image:: https://github.com/jpadilla/pyjwt/workflows/CI/badge.svg + :target: https://github.com/jpadilla/pyjwt/actions?query=workflow%3ACI + +.. image:: https://img.shields.io/pypi/v/pyjwt.svg + :target: https://pypi.python.org/pypi/pyjwt + +.. image:: https://codecov.io/gh/jpadilla/pyjwt/branch/master/graph/badge.svg + :target: https://codecov.io/gh/jpadilla/pyjwt + +.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=stable + :target: https://pyjwt.readthedocs.io/en/stable/ + +A Python implementation of `RFC 7519 <https://tools.ietf.org/html/rfc7519>`_. Original implementation was written by `@progrium <https://github.com/progrium>`_. + +Sponsor +------- + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/developers <https://auth0.com/developers?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=pyjwt&utm_content=auth>`_. | ++--------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +.. |auth0-logo| image:: https://user-images.githubusercontent.com/83319/31722733-de95bbde-b3ea-11e7-96bf-4f4e8f915588.png + +Installing +---------- + +Install with **pip**: + +.. code-block:: console + + $ pip install PyJWT + + +Usage +----- + +.. code-block:: pycon + + >>> import jwt + >>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256") + >>> print(encoded) + eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg + >>> jwt.decode(encoded, "secret", algorithms=["HS256"]) + {'some': 'payload'} + +Documentation +------------- + +View the full docs online at https://pyjwt.readthedocs.io/en/stable/ + + +Tests +----- + +You can run tests from the project root after cloning with: + +.. code-block:: console + + $ tox + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..3d8c5b51a0e40f0fe1ff44c811deb1a2abee876d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/RECORD @@ -0,0 +1,30 @@ +PyJWT-2.6.0.dist-info/AUTHORS.rst,sha256=klzkNGECnu2_VY7At89_xLBF3vUSDruXk3xwgUBxzwc,322 +PyJWT-2.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +PyJWT-2.6.0.dist-info/LICENSE,sha256=eXp6ICMdTEM-nxkR2xcx0GtYKLmPSZgZoDT3wPVvXOU,1085 +PyJWT-2.6.0.dist-info/METADATA,sha256=Iasec6QZsKlag4TjoRR4lccU-UU34WK_Hl59nAATb7o,4022 +PyJWT-2.6.0.dist-info/RECORD,, +PyJWT-2.6.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +PyJWT-2.6.0.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4 +jwt/__init__.py,sha256=I8kynnaGqKsQir76-2FT8PuADpc687kQN9jNC-e1cTo,1604 +jwt/__pycache__/__init__.cpython-310.pyc,, +jwt/__pycache__/algorithms.cpython-310.pyc,, +jwt/__pycache__/api_jwk.cpython-310.pyc,, +jwt/__pycache__/api_jws.cpython-310.pyc,, +jwt/__pycache__/api_jwt.cpython-310.pyc,, +jwt/__pycache__/exceptions.cpython-310.pyc,, +jwt/__pycache__/help.cpython-310.pyc,, +jwt/__pycache__/jwk_set_cache.cpython-310.pyc,, +jwt/__pycache__/jwks_client.cpython-310.pyc,, +jwt/__pycache__/utils.cpython-310.pyc,, +jwt/__pycache__/warnings.cpython-310.pyc,, +jwt/algorithms.py,sha256=32ov3-9gMRYI8-Sa22XF75k2FnWdxYIchyYX8l6eUGg,23688 +jwt/api_jwk.py,sha256=Danth6DCDsY0DZU-fjlB8PgZf0n6hkM8yqIhNbVY71g,3653 +jwt/api_jws.py,sha256=tVND7_p9TqZR-M_Zffm60dH2ZMYOjVzp67SeVS0rCZY,10653 +jwt/api_jwt.py,sha256=qIAQyCM_kqmZQMnS59LHrXPf5jAwSnWkUwCci6SOgmk,10059 +jwt/exceptions.py,sha256=zp928DrdRwmf4NYV-zTubHkb1XqPaj12st5Si9LLDLs,963 +jwt/help.py,sha256=0nnE54eLZhdZD7EKvIizVLesiz6vJBp-iATHkhWjZ9Y,1692 +jwt/jwk_set_cache.py,sha256=-fVgU0rP3llOlz1VUh1Z48nxOSZPJMBPZ3YalgQj9Qg,944 +jwt/jwks_client.py,sha256=0Lexl-hTYm50VRo0UuFZYvtDlmgY_V08Z8etNxIc9d0,3553 +jwt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jwt/utils.py,sha256=hAUeYuVeg2wwPwwbV95_7F1ZbDMZGXq5_H_pl4rALmE,3973 +jwt/warnings.py,sha256=50XWOnyNsIaqzUJTk6XHNiIDykiL763GYA92MjTKmok,59 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..385faab0525ccdbfd1070a8bebcca3ac8617236e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..27ccc9bc3a9ca1cd3dab3b2530e67b3309fde50a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/PyJWT-2.6.0.dist-info/top_level.txt @@ -0,0 +1 @@ +jwt diff --git a/Latest_Group_Project/.venv/Lib/site-packages/__pycache__/itypes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/__pycache__/itypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a4056d774592dcad692f2f27c2ccd7f3890111e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/__pycache__/itypes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/_cffi_backend.cp310-win_amd64.pyd b/Latest_Group_Project/.venv/Lib/site-packages/_cffi_backend.cp310-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..b4cfe5120de1803b278c8216854e3888868af2db Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/_cffi_backend.cp310-win_amd64.pyd differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..29225eee9edcd72c6a354550a5a3bedf1932b2ef --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/LICENSE @@ -0,0 +1,26 @@ + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation is licensed as follows: + + The MIT License + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..538e679147a3703f146b646ccfff989516e5565e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/METADATA @@ -0,0 +1,34 @@ +Metadata-Version: 2.1 +Name: cffi +Version: 1.15.1 +Summary: Foreign Function Interface for Python calling C code. +Home-page: http://cffi.readthedocs.org +Author: Armin Rigo, Maciej Fijalkowski +Author-email: python-cffi@googlegroups.com +License: MIT +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.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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: License :: OSI Approved :: MIT License +License-File: LICENSE +Requires-Dist: pycparser + + +CFFI +==== + +Foreign Function Interface for Python calling C code. +Please see the `Documentation <http://cffi.readthedocs.org/>`_. + +Contact +------- + +`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..0d200dbe9f11871e16d3342b7a8021817fa2bc1d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/RECORD @@ -0,0 +1,44 @@ +_cffi_backend.cp310-win_amd64.pyd,sha256=IJPn5PU1mzjwgZve-DFP2jMqFCfyLgmvxBbh7dWRD-E,181248 +cffi-1.15.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cffi-1.15.1.dist-info/LICENSE,sha256=esEZUOct9bRcUXFqeyLnuzSzJNZ_Bl4pOBUt1HLEgV8,1320 +cffi-1.15.1.dist-info/METADATA,sha256=KP4G3WmavRgDGwD2b8Y_eDsM1YeV6ckcG6Alz3-D8VY,1144 +cffi-1.15.1.dist-info/RECORD,, +cffi-1.15.1.dist-info/WHEEL,sha256=W26pYN7HLsBT1jrDSL9udgf_mdNKJmYmL23sIP-FcgM,102 +cffi-1.15.1.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 +cffi-1.15.1.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi/__init__.py,sha256=uABQQ4lgzvhAvVhd1_ZA_oSO9T-O93qMod-rs0Ihjb8,527 +cffi/__pycache__/__init__.cpython-310.pyc,, +cffi/__pycache__/api.cpython-310.pyc,, +cffi/__pycache__/backend_ctypes.cpython-310.pyc,, +cffi/__pycache__/cffi_opcode.cpython-310.pyc,, +cffi/__pycache__/commontypes.cpython-310.pyc,, +cffi/__pycache__/cparser.cpython-310.pyc,, +cffi/__pycache__/error.cpython-310.pyc,, +cffi/__pycache__/ffiplatform.cpython-310.pyc,, +cffi/__pycache__/lock.cpython-310.pyc,, +cffi/__pycache__/model.cpython-310.pyc,, +cffi/__pycache__/pkgconfig.cpython-310.pyc,, +cffi/__pycache__/recompiler.cpython-310.pyc,, +cffi/__pycache__/setuptools_ext.cpython-310.pyc,, +cffi/__pycache__/vengine_cpy.cpython-310.pyc,, +cffi/__pycache__/vengine_gen.cpython-310.pyc,, +cffi/__pycache__/verifier.cpython-310.pyc,, +cffi/_cffi_errors.h,sha256=G0bGOb-6SNIO0UY8KEN3cM40Yd1JuR5bETQ8Ni5PxWY,4057 +cffi/_cffi_include.h,sha256=H7cgdZR-POwmUFrIup4jOGzmje8YoQHhN99gVFg7w08,15185 +cffi/_embedding.h,sha256=zo5hCU0uCLgUeTOPdfXbXc5ABXjOffCMHyfUKBjCQ5E,18208 +cffi/api.py,sha256=Xs_dAN5x1ehfnn_F9ZTdA3Ce0bmPrqeIOkO4Ya1tfbQ,43029 +cffi/backend_ctypes.py,sha256=BHN3q2giL2_Y8wMDST2CIcc_qoMrs65qV9Ob5JvxBZ4,43575 +cffi/cffi_opcode.py,sha256=57P2NHLZkuTWueZybu5iosWljb6ocQmUXzGrCplrnyE,5911 +cffi/commontypes.py,sha256=mEZD4g0qtadnv6O6CEXvMQaJ1K6SRbG5S1h4YvVZHOU,2769 +cffi/cparser.py,sha256=CwVk2V3ATYlCoywG6zN35w6UQ7zj2EWX68KjoJp2Mzk,45237 +cffi/error.py,sha256=Bka7fSV22aIglTQDPIDfpnxTc1aWZLMQdQOJY-h_PUA,908 +cffi/ffiplatform.py,sha256=qioydJeC63dEvrQ3ht5_BPmSs7wzzzuWnZAJtfhic7I,4173 +cffi/lock.py,sha256=vnbsel7392Ib8gGBifIfAfc7MHteSwd3nP725pvc25Q,777 +cffi/model.py,sha256=HRD0WEYHF2Vr6RjS-4wyncElrZxU2256zY0fbMkSKec,22385 +cffi/parse_c_type.h,sha256=fKYNqWNX5f9kZNNhbXcRLTOlpRGRhh8eCLyHmTXIZnQ,6157 +cffi/pkgconfig.py,sha256=9zDcDf0XKIJaxFHLg7e-W8-Xb8Yq5hdhqH7kLg-ugRo,4495 +cffi/recompiler.py,sha256=lV6Hz-F1RXPk8YjafaIe3a-UNNVfLIeEQk0FwmXqg3s,66179 +cffi/setuptools_ext.py,sha256=8y14TOlRAkgdczmwtPOahyFXJHNyIqhLjUHMYQmjOHs,9150 +cffi/vengine_cpy.py,sha256=ukugKCIsURxJzHxlxS265tGjQfPTFDbThwsqBrwKh-A,44396 +cffi/vengine_gen.py,sha256=mykUhLFJIcV6AyQ5cMJ3n_7dbqw0a9WEjXW0E-WfgiI,27359 +cffi/verifier.py,sha256=AZuuR7MxjMYZc8IsZjGsF8mdGajCsOY60AZLwZZ_Z2Y,11560 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..93f1ef46a53243ebdb9cf912be89bdc94a9e7ada --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp310-cp310-win_amd64 + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/entry_points.txt b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/entry_points.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b0274f2333a8cfadbe2d13922c47d0138e48141 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..f64577957eb0d893196994ae517759f3fa8e48dd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi-1.15.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..90e2e6559da7b0e973285198d676f643e03baa69 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__init__.py @@ -0,0 +1,14 @@ +__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', + 'FFIError'] + +from .api import FFI +from .error import CDefError, FFIError, VerificationError, VerificationMissing +from .error import PkgConfigError + +__version__ = "1.15.1" +__version_info__ = (1, 15, 1) + +# The verifier module file names are based on the CRC32 of a string that +# contains the following version number. It may be older than __version__ +# if nothing is clearly incompatible. +__version_verifier_modules__ = "0.8.6" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d6ed8cf145ab8b8a1f146966e65abbcb1eeefbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/api.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/api.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e88b88b0cc83d3389f33d1aaabf2615fb384f8f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/api.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1eddcc8f60cb87edd34df24e40fd7324018f64ff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccc6395d24ec8ff1ea643078fe7ae7c4a4fd7e33 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbf7ebcc0385ae2d48194fd7efcdf76f6c1b9129 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e507bda03b5e7c9f7af2b37d5cc8d2f0221a9535 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/error.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/error.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..037a69428570c60d5287ff10e032dbb124e43a29 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/error.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d16cd1c8ca813813077f4e847e5f26589c8cec0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/lock.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/lock.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ca5083250f67e7d3422596c199e45916870182a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/lock.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/model.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/model.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..950095c57dde0e344591f56c1cfec078d46c010f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/model.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7dfa4871afe649e5140ce99017c76aca1ef3ecf5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19d7dba0900d96eceec427ec071bf38c5d907516 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c556513e761805f6781cc398d5c9f2c6d9d54c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31fa8f6779c369d20148fc8ea2287cc5be1aaa84 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..954eb3c2def7dd59f445d0ec660bc9467ee70127 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..261a0f3112249df343bb0c5c59411150acd98a43 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_errors.h b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..158e0590346a9a8b2ab047ac1bd23bcb3af21398 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_errors.h @@ -0,0 +1,149 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ + PyObject *result = NULL; + PyObject *x, *m, *bi; + + if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, + (void *)1, NULL) != NULL) + return (PyObject *)1; + + m = PyImport_AddModule("_cffi_error_capture"); + if (m == NULL) + goto error; + + result = PyModule_GetDict(m); + if (result == NULL) + goto error; + +#if PY_MAJOR_VERSION >= 3 + bi = PyImport_ImportModule("builtins"); +#else + bi = PyImport_ImportModule("__builtin__"); +#endif + if (bi == NULL) + goto error; + PyDict_SetItemString(result, "__builtins__", bi); + Py_DECREF(bi); + + x = PyRun_String( + "import sys\n" + "class FileLike:\n" + " def write(self, x):\n" + " try:\n" + " of.write(x)\n" + " except: pass\n" + " self.buf += x\n" + " def flush(self):\n" + " pass\n" + "fl = FileLike()\n" + "fl.buf = ''\n" + "of = sys.stderr\n" + "sys.stderr = fl\n" + "def done():\n" + " sys.stderr = of\n" + " return fl.buf\n", /* make sure the returned value stays alive */ + Py_file_input, + result, result); + Py_XDECREF(x); + + error: + if (PyErr_Occurred()) + { + PyErr_WriteUnraisable(Py_None); + PyErr_Clear(); + } + return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ + Sleep(666); /* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); +#else + MessageBoxA(NULL, (char *)_cffi_bootstrap_text, + "Python-CFFI error", + MB_OK | MB_ICONERROR); +#endif + _cffi_bootstrap_text = NULL; + return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ + PyObject *s; + void *text; + + if (ecap == (PyObject *)1) + return; + + if (ecap == NULL) + goto error; + + s = PyRun_String("done()", Py_eval_input, ecap, ecap); + if (s == NULL) + goto error; + + /* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 + text = PyUnicode_AsWideCharString(s, NULL); +#else + text = PyString_AsString(s); +#endif + + _cffi_bootstrap_text = text; + + if (text != NULL) + { + HANDLE h; + h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); + if (h != NULL) + CloseHandle(h); + } + /* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ + Py_DECREF(s); + PyErr_Clear(); + return; + + error: + _cffi_bootstrap_text = NULL; + PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_include.h b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_include.h new file mode 100644 index 0000000000000000000000000000000000000000..e4c0a672405298ddb3dcb2e2ca6da9eea3d2e162 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_cffi_include.h @@ -0,0 +1,385 @@ +#define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. + + The implementation is messy (issue #350): on Windows, with _MSC_VER, + we have to define Py_LIMITED_API even before including pyconfig.h. + In that case, we guess what pyconfig.h will do to the macros above, + and check our guess after the #include. + + Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv + version >= 16.0.0. With older versions of either, you don't get a + copy of PYTHON3.DLL in the virtualenv. We can't check the version of + CPython *before* we even include pyconfig.h. ffi.set_source() puts + a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is + running on Windows < 3.5, as an attempt at fixing it, but that's + arguably wrong because it may not be the target version of Python. + Still better than nothing I guess. As another workaround, you can + remove the definition of Py_LIMITED_API here. + + See also 'py_limited_api' in cffi/setuptools_ext.py. +*/ +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) +# ifdef _MSC_VER +# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# include <pyconfig.h> + /* sanity-check: Py_LIMITED_API will cause crashes if any of these + are also defined. Normally, the Python file PC/pyconfig.h does not + cause any of these to be defined, with the exception that _DEBUG + causes Py_DEBUG. Double-check that. */ +# ifdef Py_LIMITED_API +# if defined(Py_DEBUG) +# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" +# endif +# if defined(Py_TRACE_REFS) +# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" +# endif +# if defined(Py_REF_DEBUG) +# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" +# endif +# endif +# else +# include <pyconfig.h> +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# endif +#endif + +#include <Python.h> +#ifdef __cplusplus +extern "C" { +#endif +#include <stddef.h> +#include "parse_c_type.h" + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include <malloc.h> /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include <stdint.h> +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include <stdint.h> +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include <alloca.h> +# endif +#endif + +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif + +#ifdef __cplusplus +# ifndef _Bool + typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ +# endif +#endif + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + not used any more +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ + PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) +#define _CFFI_CPIDX 25 +#define _cffi_call_python \ + ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) +#define _cffi_to_c_wchar3216_t \ + ((int(*)(PyObject *))_cffi_exports[26]) +#define _cffi_from_c_wchar3216_t \ + ((PyObject *(*)(int))_cffi_exports[27]) +#define _CFFI_NUM_EXPORTS 28 + +struct _cffi_ctypedescr; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; + +#define _cffi_type(index) ( \ + assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ + (struct _cffi_ctypedescr *)_cffi_types[index]) + +static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, + const struct _cffi_type_context_s *ctx) +{ + PyObject *module, *o_arg, *new_module; + void *raw[] = { + (void *)module_name, + (void *)version, + (void *)_cffi_exports, + (void *)ctx, + }; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + o_arg = PyLong_FromVoidPtr((void *)raw); + if (o_arg == NULL) + goto failure; + + new_module = PyObject_CallMethod( + module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); + + Py_DECREF(o_arg); + Py_DECREF(module); + return new_module; + + failure: + Py_XDECREF(module); + return NULL; +} + + +#ifdef HAVE_WCHAR_H +typedef wchar_t _cffi_wchar_t; +#else +typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ +#endif + +_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 2) + return (uint16_t)_cffi_to_c_wchar_t(o); + else + return (uint16_t)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) +{ + if (sizeof(_cffi_wchar_t) == 2) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 4) + return (int)_cffi_to_c_wchar_t(o); + else + return (int)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) +{ + if (sizeof(_cffi_wchar_t) == 4) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +_CFFI_UNUSED_FN static int +_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +_CFFI_UNUSED_FN static void +_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +/********** end CPython-specific section **********/ +#else +_CFFI_UNUSED_FN +static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); +# define _cffi_call_python _cffi_call_python_org +#endif + + +#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) + +#define _cffi_prim_int(size, sign) \ + ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ + (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ + (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ + (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ + _CFFI__UNKNOWN_PRIM) + +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + +#define _cffi_check_int(got, got_nonpos, expected) \ + ((got_nonpos) == (expected <= 0) && \ + (got) == (unsigned long long)expected) + +#ifdef MS_WIN32 +# define _cffi_stdcall __stdcall +#else +# define _cffi_stdcall /* nothing */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/_embedding.h b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_embedding.h new file mode 100644 index 0000000000000000000000000000000000000000..8e8df882d475b3672af183044602ce564ce0720c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/_embedding.h @@ -0,0 +1,528 @@ + +/***** Support code for embedding *****/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_WIN32) +# define CFFI_DLLEXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define CFFI_DLLEXPORT __attribute__((visibility("default"))) +#else +# define CFFI_DLLEXPORT /* nothing */ +#endif + + +/* There are two global variables of type _cffi_call_python_fnptr: + + * _cffi_call_python, which we declare just below, is the one called + by ``extern "Python"`` implementations. + + * _cffi_call_python_org, which on CPython is actually part of the + _cffi_exports[] array, is the function pointer copied from + _cffi_backend. If _cffi_start_python() fails, then this is set + to NULL; otherwise, it should never be NULL. + + After initialization is complete, both are equal. However, the + first one remains equal to &_cffi_start_and_call_python until the + very end of initialization, when we are (or should be) sure that + concurrent threads also see a completely initialized world, and + only then is it changed. +*/ +#undef _cffi_call_python +typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); +static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); +static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; + + +#ifndef _MSC_VER + /* --- Assuming a GCC not infinitely old --- */ +# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) +# define cffi_write_barrier() __sync_synchronize() +# if !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386) +# define cffi_read_barrier() __sync_synchronize() +# else +# define cffi_read_barrier() (void)0 +# endif +#else + /* --- Windows threads version --- */ +# include <Windows.h> +# define cffi_compare_and_swap(l,o,n) \ + (InterlockedCompareExchangePointer(l,n,o) == (o)) +# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) +# define cffi_read_barrier() (void)0 +static volatile LONG _cffi_dummy; +#endif + +#ifdef WITH_THREAD +# ifndef _MSC_VER +# include <pthread.h> + static pthread_mutex_t _cffi_embed_startup_lock; +# else + static CRITICAL_SECTION _cffi_embed_startup_lock; +# endif + static char _cffi_embed_startup_lock_ready = 0; +#endif + +static void _cffi_acquire_reentrant_mutex(void) +{ + static void *volatile lock = NULL; + + while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: pthread_mutex_init() should be very fast, and + this is only run at start-up anyway. */ + } + +#ifdef WITH_THREAD + if (!_cffi_embed_startup_lock_ready) { +# ifndef _MSC_VER + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_cffi_embed_startup_lock, &attr); +# else + InitializeCriticalSection(&_cffi_embed_startup_lock); +# endif + _cffi_embed_startup_lock_ready = 1; + } +#endif + + while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) + ; + +#ifndef _MSC_VER + pthread_mutex_lock(&_cffi_embed_startup_lock); +#else + EnterCriticalSection(&_cffi_embed_startup_lock); +#endif +} + +static void _cffi_release_reentrant_mutex(void) +{ +#ifndef _MSC_VER + pthread_mutex_unlock(&_cffi_embed_startup_lock); +#else + LeaveCriticalSection(&_cffi_embed_startup_lock); +#endif +} + + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + +#include "_cffi_errors.h" + + +#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ + +static void _cffi_py_initialize(void) +{ + /* XXX use initsigs=0, which "skips initialization registration of + signal handlers, which might be useful when Python is + embedded" according to the Python docs. But review and think + if it should be a user-controllable setting. + + XXX we should also give a way to write errors to a buffer + instead of to stderr. + + XXX if importing 'site' fails, CPython (any version) calls + exit(). Should we try to work around this behavior here? + */ + Py_InitializeEx(0); +} + +static int _cffi_initialize_python(void) +{ + /* This initializes Python, imports _cffi_backend, and then the + present .dll/.so is set up as a CPython C extension module. + */ + int result; + PyGILState_STATE state; + PyObject *pycode=NULL, *global_dict=NULL, *x; + PyObject *builtins; + + state = PyGILState_Ensure(); + + /* Call the initxxx() function from the present module. It will + create and initialize us as a CPython extension module, instead + of letting the startup Python code do it---it might reimport + the same .dll/.so and get maybe confused on some platforms. + It might also have troubles locating the .dll/.so again for all + I know. + */ + (void)_CFFI_PYTHON_STARTUP_FUNC(); + if (PyErr_Occurred()) + goto error; + + /* Now run the Python code provided to ffi.embedding_init_code(). + */ + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "<init code for '" _CFFI_MODULE_NAME "'>", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyDict_New(); + if (global_dict == NULL) + goto error; + builtins = PyEval_GetBuiltins(); + if (builtins == NULL) + goto error; + if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) + goto error; + x = PyEval_EvalCode( +#if PY_MAJOR_VERSION < 3 + (PyCodeObject *) +#endif + pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); + + /* Done! Now if we've been called from + _cffi_start_and_call_python() in an ``extern "Python"``, we can + only hope that the Python code did correctly set up the + corresponding @ffi.def_extern() function. Otherwise, the + general logic of ``extern "Python"`` functions (inside the + _cffi_backend module) will find that the reference is still + missing and print an error. + */ + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(global_dict); + PyGILState_Release(state); + return result; + + error:; + { + /* Print as much information as potentially useful. + Debugging load-time failures with embedding is not fun + */ + PyObject *ecap; + PyObject *exception, *v, *tb, *f, *modules, *mod; + PyErr_Fetch(&exception, &v, &tb); + ecap = _cffi_start_error_capture(); + f = PySys_GetObject((char *)"stderr"); + if (f != NULL && f != Py_None) { + PyFile_WriteString( + "Failed to initialize the Python-CFFI embedding logic:\n\n", f); + } + + if (exception != NULL) { + PyErr_NormalizeException(&exception, &v, &tb); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); + + if (f != NULL && f != Py_None) { + PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME + "\ncompiled with cffi version: 1.15.1" + "\n_cffi_backend module: ", f); + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, "_cffi_backend"); + if (mod == NULL) { + PyFile_WriteString("not loaded", f); + } + else { + v = PyObject_GetAttrString(mod, "__file__"); + PyFile_WriteObject(v, f, 0); + Py_XDECREF(v); + } + PyFile_WriteString("\nsys.path: ", f); + PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); + PyFile_WriteString("\n\n", f); + } + _cffi_stop_error_capture(ecap); + } + result = -1; + goto done; +} + +#if PY_VERSION_HEX < 0x03080000 +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ +#endif + +static int _cffi_carefully_make_gil(void) +{ + /* This does the basic initialization of Python. It can be called + completely concurrently from unrelated threads. It assumes + that we don't hold the GIL before (if it exists), and we don't + hold it afterwards. + + (What it really does used to be completely different in Python 2 + and Python 3, with the Python 2 solution avoiding the spin-lock + around the Py_InitializeEx() call. However, after recent changes + to CPython 2.7 (issue #358) it no longer works. So we use the + Python 3 solution everywhere.) + + This initializes Python by calling Py_InitializeEx(). + Important: this must not be called concurrently at all. + So we use a global variable as a simple spin lock. This global + variable must be from 'libpythonX.Y.so', not from this + cffi-based extension module, because it must be shared from + different cffi-based extension modules. + + In Python < 3.8, we choose + _PyParser_TokenNames[0] as a completely arbitrary pointer value + that is never written to. The default is to point to the + string "ENDMARKER". We change it temporarily to point to the + next character in that string. (Yes, I know it's REALLY + obscure.) + + In Python >= 3.8, this string array is no longer writable, so + instead we pick PyCapsuleType.tp_version_tag. We can't change + Python < 3.8 because someone might use a mixture of cffi + embedded modules, some of which were compiled before this file + changed. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x03080000 + char *volatile *lock = (char *volatile *)_PyParser_TokenNames; + char *old_value, *locked_value; + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = old_value + 1; + if (old_value[0] == 'E') { + assert(old_value[1] == 'N'); + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value[0] == 'N'); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# else + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = -42; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value == locked_value); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# endif +#endif + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); +#if PY_VERSION_HEX < 0x03070000 + PyEval_InitThreads(); +#endif + PyEval_SaveThread(); /* release the GIL */ + /* the returned tstate must be the one that has been stored into the + autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ + } + else { +#if PY_VERSION_HEX < 0x03070000 + /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ + PyGILState_STATE state = PyGILState_Ensure(); + PyEval_InitThreads(); + PyGILState_Release(state); +#endif + } + +#ifdef WITH_THREAD + /* release the lock */ + while (!cffi_compare_and_swap(lock, locked_value, old_value)) + ; +#endif + + return 0; +} + +/********** end CPython-specific section **********/ + + +#else + + +/********** PyPy-specific section **********/ + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ + +static struct _cffi_pypy_init_s { + const char *name; + void *func; /* function pointer */ + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_carefully_make_gil(const char *); +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static int _cffi_carefully_make_gil(void) +{ + return pypy_carefully_make_gil(_CFFI_MODULE_NAME); +} + +static int _cffi_initialize_python(void) +{ + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); +} + +/********** end PyPy-specific section **********/ + + +#endif + + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static _cffi_call_python_fnptr _cffi_start_python(void) +{ + /* Delicate logic to initialize Python. This function can be + called multiple times concurrently, e.g. when the process calls + its first ``extern "Python"`` functions in multiple threads at + once. It can also be called recursively, in which case we must + ignore it. We also have to consider what occurs if several + different cffi-based extensions reach this code in parallel + threads---it is a different copy of the code, then, and we + can't have any shared global variable unless it comes from + 'libpythonX.Y.so'. + + Idea: + + * _cffi_carefully_make_gil(): "carefully" call + PyEval_InitThreads() (possibly with Py_InitializeEx() first). + + * then we use a (local) custom lock to make sure that a call to this + cffi-based extension will wait if another call to the *same* + extension is running the initialization in another thread. + It is reentrant, so that a recursive call will not block, but + only one from a different thread. + + * then we grab the GIL and (Python 2) we call Py_InitializeEx(). + At this point, concurrent calls to Py_InitializeEx() are not + possible: we have the GIL. + + * do the rest of the specific initialization, which may + temporarily release the GIL but not the custom lock. + Only release the custom lock when we are done. + */ + static char called = 0; + + if (_cffi_carefully_make_gil() != 0) + return NULL; + + _cffi_acquire_reentrant_mutex(); + + /* Here the GIL exists, but we don't have it. We're only protected + from concurrency by the reentrant mutex. */ + + /* This file only initializes the embedded module once, the first + time this is called, even if there are subinterpreters. */ + if (!called) { + called = 1; /* invoke _cffi_initialize_python() only once, + but don't set '_cffi_call_python' right now, + otherwise concurrent threads won't call + this function at all (we need them to wait) */ + if (_cffi_initialize_python() == 0) { + /* now initialization is finished. Switch to the fast-path. */ + + /* We would like nobody to see the new value of + '_cffi_call_python' without also seeing the rest of the + data initialized. However, this is not possible. But + the new value of '_cffi_call_python' is the function + 'cffi_call_python()' from _cffi_backend. So: */ + cffi_write_barrier(); + /* ^^^ we put a write barrier here, and a corresponding + read barrier at the start of cffi_call_python(). This + ensures that after that read barrier, we see everything + done here before the write barrier. + */ + + assert(_cffi_call_python_org != NULL); + _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; + } + else { + /* initialization failed. Reset this to NULL, even if it was + already set to some other value. Future calls to + _cffi_start_python() are still forced to occur, and will + always return NULL from now on. */ + _cffi_call_python_org = NULL; + } + } + + _cffi_release_reentrant_mutex(); + + return (_cffi_call_python_fnptr)_cffi_call_python_org; +} + +static +void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + _cffi_call_python_fnptr fnptr; + int current_err = errno; +#ifdef _MSC_VER + int current_lasterr = GetLastError(); +#endif + fnptr = _cffi_start_python(); + if (fnptr == NULL) { + fprintf(stderr, "function %s() called, but initialization code " + "failed. Returning 0.\n", externpy->name); + memset(args, 0, externpy->size_of_result); + } +#ifdef _MSC_VER + SetLastError(current_lasterr); +#endif + errno = current_err; + + if (fnptr != NULL) + fnptr(externpy, args); +} + + +/* The cffi_start_python() function makes sure Python is initialized + and our cffi module is set up. It can be called manually from the + user C code. The same effect is obtained automatically from any + dll-exported ``extern "Python"`` function. This function returns + -1 if initialization failed, 0 if all is OK. */ +_CFFI_UNUSED_FN +static int cffi_start_python(void) +{ + if (_cffi_call_python == &_cffi_start_and_call_python) { + if (_cffi_start_python() == NULL) + return -1; + } + cffi_read_barrier(); + return 0; +} + +#undef cffi_compare_and_swap +#undef cffi_write_barrier +#undef cffi_read_barrier + +#ifdef __cplusplus +} +#endif diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/api.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/api.py new file mode 100644 index 0000000000000000000000000000000000000000..999a8aefc4af0b27120823116212b0afe8484aad --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/api.py @@ -0,0 +1,965 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + callable +except NameError: + # Python 3.1 + from collections import Callable + callable = lambda x: isinstance(x, Callable) + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI(object): + r''' + The main top-level class that you instantiate once, or once per module. + + Example usage: + + ffi = FFI() + ffi.cdef(""" + int printf(const char *, ...); + """) + + C = ffi.dlopen(None) # standard library + -or- + C = ffi.verify() # use a C compiler: verify the decl above is right + + C.printf("hello, %s!\n", ffi.new("char[]", "world")) + ''' + + def __init__(self, backend=None): + """Create an FFI instance. The 'backend' argument is used to + select a non-default backend, mostly for tests. + """ + if backend is None: + # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with + # _cffi_backend.so compiled. + import _cffi_backend as backend + from . import __version__ + if backend.__version__ != __version__: + # bad version! Try to be as explicit as possible. + if hasattr(backend, '__file__'): + # CPython + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( + __version__, __file__, + backend.__version__, backend.__file__)) + else: + # PyPy + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( + __version__, __file__, backend.__version__)) + # (If you insist you can also try to pass the option + # 'backend=backend_ctypes.CTypesBackend()', but don't + # rely on it! It's probably not going to work well.) + + from . import cparser + self._backend = backend + self._lock = allocate_lock() + self._parser = cparser.Parser() + self._cached_btypes = {} + self._parsed_types = types.ModuleType('parsed_types').__dict__ + self._new_types = types.ModuleType('new_types').__dict__ + self._function_caches = [] + self._libraries = [] + self._cdefsources = [] + self._included_ffis = [] + self._windows_unicode = None + self._init_once_cache = {} + self._cdef_version = None + self._embedding = None + self._typecache = model.get_typecache(backend) + if hasattr(backend, 'set_ffi'): + backend.set_ffi(self) + for name in list(backend.__dict__): + if name.startswith('RTLD_'): + setattr(self, name, getattr(backend, name)) + # + with self._lock: + self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) + if isinstance(backend, types.ModuleType): + # _cffi_backend: attach these constants to the class + if not hasattr(FFI, 'NULL'): + FFI.NULL = self.cast(self.BVoidP, 0) + FFI.CData, FFI.CType = backend._get_types() + else: + # ctypes backend: attach these constants to the instance + self.NULL = self.cast(self.BVoidP, 0) + self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer + + def cdef(self, csource, override=False, packed=False, pack=None): + """Parse the given C source. This registers all declared functions, + types, and global variables. The functions and global variables can + then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. + The types can be used in 'ffi.new()' and other functions. + If 'packed' is specified as True, all structs declared inside this + cdef are packed, i.e. laid out without any field alignment at all. + Alternatively, 'pack' can be a small integer, and requests for + alignment greater than that are ignored (pack=1 is equivalent to + packed=True). + """ + self._cdef(csource, override=override, packed=packed, pack=pack) + + def embedding_api(self, csource, packed=False, pack=None): + self._cdef(csource, packed=packed, pack=pack, dllexport=True) + if self._embedding is None: + self._embedding = '' + + def _cdef(self, csource, override=False, **options): + if not isinstance(csource, str): # unicode, on Python 2 + if not isinstance(csource, basestring): + raise TypeError("cdef() argument must be a string") + csource = csource.encode('ascii') + with self._lock: + self._cdef_version = object() + self._parser.parse(csource, override=override, **options) + self._cdefsources.append(csource) + if override: + for cache in self._function_caches: + cache.clear() + finishlist = self._parser._recomplete + if finishlist: + self._parser._recomplete = [] + for tp in finishlist: + tp.finish_backend_type(self, finishlist) + + def dlopen(self, name, flags=0): + """Load and return a dynamic library identified by 'name'. + The standard C library can be loaded by passing None. + Note that functions and types declared by 'ffi.cdef()' are not + linked to a particular library, just like C headers; in the + library we only look for the actual (untyped) symbols. + """ + if not (isinstance(name, basestring) or + name is None or + isinstance(name, self.CData)): + raise TypeError("dlopen(name): name must be a file name, None, " + "or an already-opened 'void *' handle") + with self._lock: + lib, function_cache = _make_ffi_library(self, name, flags) + self._function_caches.append(function_cache) + self._libraries.append(lib) + return lib + + def dlclose(self, lib): + """Close a library obtained with ffi.dlopen(). After this call, + access to functions or variables from the library will fail + (possibly with a segmentation fault). + """ + type(lib).__cffi_close__(lib) + + def _typeof_locked(self, cdecl): + # call me with the lock! + key = cdecl + if key in self._parsed_types: + return self._parsed_types[key] + # + if not isinstance(cdecl, str): # unicode, on Python 2 + cdecl = cdecl.encode('ascii') + # + type = self._parser.parse_type(cdecl) + really_a_function_type = type.is_raw_function + if really_a_function_type: + type = type.as_function_pointer() + btype = self._get_cached_btype(type) + result = btype, really_a_function_type + self._parsed_types[key] = result + return result + + def _typeof(self, cdecl, consider_function_as_funcptr=False): + # string -> ctype object + try: + result = self._parsed_types[cdecl] + except KeyError: + with self._lock: + result = self._typeof_locked(cdecl) + # + btype, really_a_function_type = result + if really_a_function_type and not consider_function_as_funcptr: + raise CDefError("the type %r is a function type, not a " + "pointer-to-function type" % (cdecl,)) + return btype + + def typeof(self, cdecl): + """Parse the C type given as a string and return the + corresponding <ctype> object. + It can also be used on 'cdata' instance to get its C type. + """ + if isinstance(cdecl, basestring): + return self._typeof(cdecl) + if isinstance(cdecl, self.CData): + return self._backend.typeof(cdecl) + if isinstance(cdecl, types.BuiltinFunctionType): + res = _builtin_function_type(cdecl) + if res is not None: + return res + if (isinstance(cdecl, types.FunctionType) + and hasattr(cdecl, '_cffi_base_type')): + with self._lock: + return self._get_cached_btype(cdecl._cffi_base_type) + raise TypeError(type(cdecl)) + + def sizeof(self, cdecl): + """Return the size in bytes of the argument. It can be a + string naming a C type, or a 'cdata' instance. + """ + if isinstance(cdecl, basestring): + BType = self._typeof(cdecl) + return self._backend.sizeof(BType) + else: + return self._backend.sizeof(cdecl) + + def alignof(self, cdecl): + """Return the natural alignment size in bytes of the C type + given as a string. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.alignof(cdecl) + + def offsetof(self, cdecl, *fields_or_indexes): + """Return the offset of the named field inside the given + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] + + def new(self, cdecl, init=None): + """Allocate an instance according to the specified C type and + return a pointer to it. The specified C type must be either a + pointer or an array: ``new('X *')`` allocates an X and returns + a pointer to it, whereas ``new('X[n]')`` allocates an array of + n X'es and returns an array referencing it (which works + mostly like a pointer, like in C). You can also use + ``new('X[]', n)`` to allocate an array of a non-constant + length n. + + The memory is initialized following the rules of declaring a + global variable in C: by default it is zero-initialized, but + an explicit initializer can be given which can be used to + fill all or part of the memory. + + When the returned <cdata> object goes out of scope, the memory + is freed. In other words the returned <cdata> object has + ownership of the value of type 'cdecl' that it points to. This + means that the raw data can be used as long as this object is + kept alive, but must not be used for a longer time. Be careful + about that when copying the pointer to the memory somewhere + else, e.g. into another structure. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.newp(cdecl, init) + + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + + def cast(self, cdecl, source): + """Similar to a C cast: returns an instance of the named C + type initialized with the given 'source'. The source is + casted between integers or pointers of any type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.cast(cdecl, source) + + def string(self, cdata, maxlen=-1): + """Return a Python string (or unicode string) from the 'cdata'. + If 'cdata' is a pointer or array of characters or bytes, returns + the null-terminated string. The returned string extends until + the first null character, or at most 'maxlen' characters. If + 'cdata' is an array then 'maxlen' defaults to its length. + + If 'cdata' is a pointer or array of wchar_t, returns a unicode + string following the same rules. + + If 'cdata' is a single character or byte or a wchar_t, returns + it as a string or unicode string. + + If 'cdata' is an enum, returns the value of the enumerator as a + string, or 'NUMBER' if the value is out of range. + """ + return self._backend.string(cdata, maxlen) + + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ + + def from_buffer(self, cdecl, python_buffer=_unspecified, + require_writable=False): + """Return a cdata of the given type pointing to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types + str or unicode (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + + The first argument is optional and default to 'char[]'. + """ + if python_buffer is _unspecified: + cdecl, python_buffer = self.BCharA, cdecl + elif isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.from_buffer(cdecl, python_buffer, + require_writable) + + def memmove(self, dest, src, n): + """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. + + Like the C function memmove(), the memory areas may overlap; + apart from that it behaves like the C function memcpy(). + + 'src' can be any cdata ptr or array, or any Python buffer object. + 'dest' can be any cdata ptr or array, or a writable Python buffer + object. The size to copy, 'n', is always measured in bytes. + + Unlike other methods, this one supports all Python buffer including + byte strings and bytearrays---but it still does not support + non-contiguous buffers. + """ + return self._backend.memmove(dest, src, n) + + def callback(self, cdecl, python_callable=None, error=None, onerror=None): + """Return a callback object or a decorator making such a + callback object. 'cdecl' must name a C function pointer type. + The callback invokes the specified 'python_callable' (which may + be provided either directly or via a decorator). Important: the + callback object must be manually kept alive for as long as the + callback may be invoked from the C level. + """ + def callback_decorator_wrap(python_callable): + if not callable(python_callable): + raise TypeError("the 'python_callable' argument " + "is not callable") + return self._backend.callback(cdecl, python_callable, + error, onerror) + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) + if python_callable is None: + return callback_decorator_wrap # decorator mode + else: + return callback_decorator_wrap(python_callable) # direct mode + + def getctype(self, cdecl, replace_with=''): + """Return a string giving the C type 'cdecl', which may be itself + a string or a <ctype> object. If 'replace_with' is given, it gives + extra text to append (or insert for more complicated C types), like + a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + replace_with = replace_with.strip() + if (replace_with.startswith('*') + and '&[' in self._backend.getcname(cdecl, '&')): + replace_with = '(%s)' % replace_with + elif replace_with and not replace_with[0] in '[(': + replace_with = ' ' + replace_with + return self._backend.getcname(cdecl, replace_with) + + def gc(self, cdata, destructor, size=0): + """Return a new cdata object that points to the same + data. Later, when this new cdata object is garbage-collected, + 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. + """ + return self._backend.gcp(cdata, destructor, size) + + def _get_cached_btype(self, type): + assert self._lock.acquire(False) is False + # call me with the lock! + try: + BType = self._cached_btypes[type] + except KeyError: + finishlist = [] + BType = type.get_cached_btype(self, finishlist) + for type in finishlist: + type.finish_backend_type(self, finishlist) + return BType + + def verify(self, source='', tmpdir=None, **kwargs): + """Verify that the current ffi signatures compile on this + machine, and return a dynamic library object. The dynamic + library can be used to call functions and access global + variables declared in this 'ffi'. The library is compiled + by the C compiler: it gives you C-level API compatibility + (including calling macros). This is unlike 'ffi.dlopen()', + which requires binary compatibility in the signatures. + """ + from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). + tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. + self.verifier = Verifier(self, source, tmpdir, **kwargs) + lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). + self._libraries.append(lib) + return lib + + def _get_errno(self): + return self._backend.get_errno() + def _set_errno(self, errno): + self._backend.set_errno(errno) + errno = property(_get_errno, _set_errno, None, + "the value of 'errno' from/to the C calls") + + def getwinerror(self, code=-1): + return self._backend.getwinerror(code) + + def _pointer_to(self, ctype): + with self._lock: + return model.pointer_cache(self, ctype) + + def addressof(self, cdata, *fields_or_indexes): + """Return the address of a <cdata 'struct-or-union'>. + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. + """ + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 + ctypeptr = self._pointer_to(ctype) + return self._backend.rawaddressof(ctypeptr, cdata, offset) + + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + + def include(self, ffi_to_include): + """Includes the typedefs, structs, unions and enums defined + in another FFI instance. Usage is similar to a #include in C, + where a part of the program might include types defined in + another part for its own usage. Note that the include() + method has no effect on functions, constants and global + variables, which must anyway be accessed directly from the + lib object returned by the original FFI instance. + """ + if not isinstance(ffi_to_include, FFI): + raise TypeError("ffi.include() expects an argument that is also of" + " type cffi.FFI, not %r" % ( + type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") + with ffi_to_include._lock: + with self._lock: + self._parser.include(ffi_to_include._parser) + self._cdefsources.append('[') + self._cdefsources.extend(ffi_to_include._cdefsources) + self._cdefsources.append(']') + self._included_ffis.append(ffi_to_include) + + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + + def release(self, x): + self._backend.release(x) + + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + + def _apply_embedding_fix(self, kwds): + # must include an argument like "-lpython2.7" for the compiler + def ensure(key, value): + lst = kwds.setdefault(key, []) + if value not in lst: + lst.append(value) + # + if '__pypy__' in sys.builtin_module_names: + import os + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' for installed + # systems. + if sys.version_info < (3,): + pythonlib = "pypy-c" + else: + pythonlib = "pypy3-c" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) + # On uninstalled pypy's, the libpypy-c is typically found in + # .../pypy/goal/. + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) + else: + if sys.platform == "win32": + template = "python%d%d" + if hasattr(sys, 'gettotalrefcount'): + template += '_d' + else: + try: + import sysconfig + except ImportError: # 2.6 + from distutils import sysconfig + template = "python%d.%d" + if sysconfig.get_config_var('DEBUG_EXT'): + template += sysconfig.get_config_var('DEBUG_EXT') + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + if hasattr(sys, 'abiflags'): + pythonlib += sys.abiflags + ensure('libraries', pythonlib) + if sys.platform == "win32": + ensure('extra_link_args', '/MANIFEST') + + def set_source(self, module_name, source, source_extension='.c', **kwds): + import os + if hasattr(self, '_assigned_source'): + raise ValueError("set_source() cannot be called several times " + "per ffi object") + if not isinstance(module_name, basestring): + raise TypeError("'module_name' must be a string") + if os.sep in module_name or (os.altsep and os.altsep in module_name): + raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") + self._assigned_source = (str(module_name), source, + source_extension, kwds) + + def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, + source_extension='.c', **kwds): + from . import pkgconfig + if not isinstance(pkgconfig_libs, list): + raise TypeError("the pkgconfig_libs argument must be a list " + "of package names") + kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) + pkgconfig.merge_flags(kwds, kwds2) + self.set_source(module_name, source, source_extension, **kwds) + + def distutils_extension(self, tmpdir='build', verbose=True): + from distutils.dir_util import mkpath + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored + return self.verifier.get_extension() + raise ValueError("set_source() must be called before" + " distutils_extension()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("distutils_extension() is only for C extension " + "modules, not for dlopen()-style pure Python " + "modules") + mkpath(tmpdir) + ext, updated = recompile(self, module_name, + source, tmpdir=tmpdir, extradir=tmpdir, + source_extension=source_extension, + call_c_compiler=False, **kwds) + if verbose: + if updated: + sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) + else: + sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) + return ext + + def emit_c_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("emit_c_code() is only for C extension modules, " + "not for dlopen()-style pure Python modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def emit_python_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is not None: + raise TypeError("emit_python_code() is only for dlopen()-style " + "pure Python modules, not for C extension modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): + """The 'target' argument gives the final file name of the + compiled DLL. Use '*' to force distutils' choice, suitable for + regular CPython C API modules. Use a file name ending in '.*' + to ask for the system's default extension for dynamic libraries + (.so/.dll/.dylib). + + The default is '*' when building a non-embedded C API extension, + and (module_name + '.*') when building an embedded library. + """ + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before compile()") + module_name, source, source_extension, kwds = self._assigned_source + return recompile(self, module_name, source, tmpdir=tmpdir, + target=target, source_extension=source_extension, + compiler_verbose=verbose, debug=debug, **kwds) + + def init_once(self, func, tag): + # Read _init_once_cache[tag], which is either (False, lock) if + # we're calling the function now in some thread, or (True, result). + # Don't call setdefault() in most cases, to avoid allocating and + # immediately freeing a lock; but still use setdefaut() to avoid + # races. + try: + x = self._init_once_cache[tag] + except KeyError: + x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) + # Common case: we got (True, result), so we return the result. + if x[0]: + return x[1] + # Else, it's a lock. Acquire it to serialize the following tests. + with x[1]: + # Read again from _init_once_cache the current status. + x = self._init_once_cache[tag] + if x[0]: + return x[1] + # Call the function and store the result back. + result = func() + self._init_once_cache[tag] = (True, result) + return result + + def embedding_init_code(self, pysource): + if self._embedding: + raise ValueError("embedding_init_code() can only be called once") + # fix 'pysource' before it gets dumped into the C file: + # - remove empty lines at the beginning, so it starts at "line 1" + # - dedent, if all non-empty lines are indented + # - check for SyntaxErrors + import re + match = re.match(r'\s*\n', pysource) + if match: + pysource = pysource[match.end():] + lines = pysource.splitlines() or [''] + prefix = re.match(r'\s*', lines[0]).group() + for i in range(1, len(lines)): + line = lines[i] + if line.rstrip(): + while not line.startswith(prefix): + prefix = prefix[:-1] + i = len(prefix) + lines = [line[i:]+'\n' for line in lines] + pysource = ''.join(lines) + # + compile(pysource, "cffi_init", "exec") + # + self._embedding = pysource + + def def_extern(self, *args, **kwds): + raise ValueError("ffi.def_extern() is only available on API-mode FFI " + "objects") + + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + + +def _load_backend_lib(backend, name, flags): + import os + if not isinstance(name, basestring): + if sys.platform != "win32" or name is not None: + return backend.load_library(name, flags) + name = "c" # Windows: load_library(None) fails, but this works + # on Python 2 (backward compatibility hack only) + first_error = None + if '.' in name or '/' in name or os.sep in name: + try: + return backend.load_library(name, flags) + except OSError as e: + first_error = e + import ctypes.util + path = ctypes.util.find_library(name) + if path is None: + if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): + raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") + msg = ("ctypes.util.find_library() did not manage " + "to locate a library called %r" % (name,)) + if first_error is not None: + msg = "%s. Additionally, %s" % (first_error, msg) + raise OSError(msg) + return backend.load_library(path, flags) + +def _make_ffi_library(ffi, libname, flags): + backend = ffi._backend + backendlib = _load_backend_lib(backend, libname, flags) + # + def accessor_function(name): + key = 'function ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + value = backendlib.load_function(BType, name) + library.__dict__[name] = value + # + def accessor_variable(name): + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + read_variable = backendlib.read_variable + write_variable = backendlib.write_variable + setattr(FFILibrary, name, property( + lambda self: read_variable(BType, name), + lambda self, value: write_variable(BType, name, value))) + # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # + def accessor_constant(name): + raise NotImplementedError("non-integer constant '%s' cannot be " + "accessed from a dlopen() library" % (name,)) + # + def accessor_int_constant(name): + library.__dict__[name] = ffi._parser._int_constants[name] + # + accessors = {} + accessors_version = [False] + addr_variables = {} + # + def update_accessors(): + if accessors_version[0] is ffi._cdef_version: + return + # + for key, (tp, _) in ffi._parser._declarations.items(): + if not isinstance(tp, model.EnumType): + tag, name = key.split(' ', 1) + if tag == 'function': + accessors[name] = accessor_function + elif tag == 'variable': + accessors[name] = accessor_variable + elif tag == 'constant': + accessors[name] = accessor_constant + else: + for i, enumname in enumerate(tp.enumerators): + def accessor_enum(name, tp=tp, i=i): + tp.check_not_partial() + library.__dict__[name] = tp.enumvalues[i] + accessors[enumname] = accessor_enum + for name in ffi._parser._int_constants: + accessors.setdefault(name, accessor_int_constant) + accessors_version[0] = ffi._cdef_version + # + def make_accessor(name): + with ffi._lock: + if name in library.__dict__ or name in FFILibrary.__dict__: + return # added by another thread while waiting for the lock + if name not in accessors: + update_accessors() + if name not in accessors: + raise AttributeError(name) + accessors[name](name) + # + class FFILibrary(object): + def __getattr__(self, name): + make_accessor(name) + return getattr(self, name) + def __setattr__(self, name, value): + try: + property = getattr(self.__class__, name) + except AttributeError: + make_accessor(name) + setattr(self, name, value) + else: + property.__set__(self, value) + def __dir__(self): + with ffi._lock: + update_accessors() + return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) + def __cffi_close__(self): + backendlib.close_lib() + self.__dict__.clear() + # + if isinstance(libname, basestring): + try: + if not isinstance(libname, str): # unicode, on Python 2 + libname = libname.encode('utf-8') + FFILibrary.__name__ = 'FFILibrary_%s' % libname + except UnicodeError: + pass + library = FFILibrary() + return library, library.__dict__ + +def _builtin_function_type(func): + # a hack to make at least ffi.typeof(builtin_function) work, + # if the builtin function was obtained by 'vengine_cpy'. + import sys + try: + module = sys.modules[func.__module__] + ffi = module._cffi_original_ffi + types_of_builtin_funcs = module._cffi_types_of_builtin_funcs + tp = types_of_builtin_funcs[func] + except (KeyError, AttributeError, TypeError): + return None + else: + with ffi._lock: + return ffi._get_cached_btype(tp) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/backend_ctypes.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/backend_ctypes.py new file mode 100644 index 0000000000000000000000000000000000000000..e7956a79cfb1c3d28a2ad22a40b261ae7dbbbb5f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/backend_ctypes.py @@ -0,0 +1,1121 @@ +import ctypes, ctypes.util, operator, sys +from . import model + +if sys.version_info < (3,): + bytechr = chr +else: + unicode = str + long = int + xrange = range + bytechr = lambda num: bytes([num]) + +class CTypesType(type): + pass + +class CTypesData(object): + __metaclass__ = CTypesType + __slots__ = ['__weakref__'] + __name__ = '<cdata>' + + def __init__(self, *args): + raise TypeError("cannot instantiate %r" % (self.__class__,)) + + @classmethod + def _newp(cls, init): + raise TypeError("expected a pointer or array ctype, got '%s'" + % (cls._get_c_name(),)) + + @staticmethod + def _to_ctypes(value): + raise TypeError + + @classmethod + def _arg_to_ctypes(cls, *value): + try: + ctype = cls._ctype + except AttributeError: + raise TypeError("cannot create an instance of %r" % (cls,)) + if value: + res = cls._to_ctypes(*value) + if not isinstance(res, ctype): + res = cls._ctype(res) + else: + res = cls._ctype() + return res + + @classmethod + def _create_ctype_obj(cls, init): + if init is None: + return cls._arg_to_ctypes() + else: + return cls._arg_to_ctypes(init) + + @staticmethod + def _from_ctypes(ctypes_value): + raise TypeError + + @classmethod + def _get_c_name(cls, replace_with=''): + return cls._reftypename.replace(' &', replace_with) + + @classmethod + def _fix_class(cls): + cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__module__ = 'ffi' + + def _get_own_repr(self): + raise NotImplementedError + + def _addr_repr(self, address): + if address == 0: + return 'NULL' + else: + if address < 0: + address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) + return '0x%x' % address + + def __repr__(self, c_name=None): + own = self._get_own_repr() + return '<cdata %r %s>' % (c_name or self._get_c_name(), own) + + def _convert_to_address(self, BClass): + if BClass is None: + raise TypeError("cannot convert %r to an address" % ( + self._get_c_name(),)) + else: + raise TypeError("cannot convert %r to %r" % ( + self._get_c_name(), BClass._get_c_name())) + + @classmethod + def _get_size(cls): + return ctypes.sizeof(cls._ctype) + + def _get_size_of_instance(self): + return ctypes.sizeof(self._ctype) + + @classmethod + def _cast_from(cls, source): + raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) + + def _cast_to_integer(self): + return self._convert_to_address(None) + + @classmethod + def _alignment(cls): + return ctypes.alignment(cls._ctype) + + def __iter__(self): + raise TypeError("cdata %r does not support iteration" % ( + self._get_c_name()),) + + def _make_cmp(name): + cmpfunc = getattr(operator, name) + def cmp(self, other): + v_is_ptr = not isinstance(self, CTypesGenericPrimitive) + w_is_ptr = (isinstance(other, CTypesData) and + not isinstance(other, CTypesGenericPrimitive)) + if v_is_ptr and w_is_ptr: + return cmpfunc(self._convert_to_address(None), + other._convert_to_address(None)) + elif v_is_ptr or w_is_ptr: + return NotImplemented + else: + if isinstance(self, CTypesGenericPrimitive): + self = self._value + if isinstance(other, CTypesGenericPrimitive): + other = other._value + return cmpfunc(self, other) + cmp.func_name = name + return cmp + + __eq__ = _make_cmp('__eq__') + __ne__ = _make_cmp('__ne__') + __lt__ = _make_cmp('__lt__') + __le__ = _make_cmp('__le__') + __gt__ = _make_cmp('__gt__') + __ge__ = _make_cmp('__ge__') + + def __hash__(self): + return hash(self._convert_to_address(None)) + + def _to_string(self, maxlen): + raise TypeError("string(): %r" % (self,)) + + +class CTypesGenericPrimitive(CTypesData): + __slots__ = [] + + def __hash__(self): + return hash(self._value) + + def _get_own_repr(self): + return repr(self._from_ctypes(self._value)) + + +class CTypesGenericArray(CTypesData): + __slots__ = [] + + @classmethod + def _newp(cls, init): + return cls(init) + + def __iter__(self): + for i in xrange(len(self)): + yield self[i] + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + +class CTypesGenericPtr(CTypesData): + __slots__ = ['_address', '_as_ctype_ptr'] + _automatic_casts = False + kind = "pointer" + + @classmethod + def _newp(cls, init): + return cls(init) + + @classmethod + def _cast_from(cls, source): + if source is None: + address = 0 + elif isinstance(source, CTypesData): + address = source._cast_to_integer() + elif isinstance(source, (int, long)): + address = source + else: + raise TypeError("bad type for cast to %r: %r" % + (cls, type(source).__name__)) + return cls._new_pointer_at(address) + + @classmethod + def _new_pointer_at(cls, address): + self = cls.__new__(cls) + self._address = address + self._as_ctype_ptr = ctypes.cast(address, cls._ctype) + return self + + def _get_own_repr(self): + try: + return self._addr_repr(self._address) + except AttributeError: + return '???' + + def _cast_to_integer(self): + return self._address + + def __nonzero__(self): + return bool(self._address) + __bool__ = __nonzero__ + + @classmethod + def _to_ctypes(cls, value): + if not isinstance(value, CTypesData): + raise TypeError("unexpected %s object" % type(value).__name__) + address = value._convert_to_address(cls) + return ctypes.cast(address, cls._ctype) + + @classmethod + def _from_ctypes(cls, ctypes_ptr): + address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 + return cls._new_pointer_at(address) + + @classmethod + def _initialize(cls, ctypes_ptr, value): + if value: + ctypes_ptr.contents = cls._to_ctypes(value).contents + + def _convert_to_address(self, BClass): + if (BClass in (self.__class__, None) or BClass._automatic_casts + or self._automatic_casts): + return self._address + else: + return CTypesData._convert_to_address(self, BClass) + + +class CTypesBaseStructOrUnion(CTypesData): + __slots__ = ['_blob'] + + @classmethod + def _create_ctype_obj(cls, init): + # may be overridden + raise TypeError("cannot instantiate opaque type %s" % (cls,)) + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + @classmethod + def _offsetof(cls, fieldname): + return getattr(cls._ctype, fieldname).offset + + def _convert_to_address(self, BClass): + if getattr(BClass, '_BItem', None) is self.__class__: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @classmethod + def _from_ctypes(cls, ctypes_struct_or_union): + self = cls.__new__(cls) + self._blob = ctypes_struct_or_union + return self + + @classmethod + def _to_ctypes(cls, value): + return value._blob + + def __repr__(self, c_name=None): + return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) + + +class CTypesBackend(object): + + PRIMITIVE_TYPES = { + 'char': ctypes.c_char, + 'short': ctypes.c_short, + 'int': ctypes.c_int, + 'long': ctypes.c_long, + 'long long': ctypes.c_longlong, + 'signed char': ctypes.c_byte, + 'unsigned char': ctypes.c_ubyte, + 'unsigned short': ctypes.c_ushort, + 'unsigned int': ctypes.c_uint, + 'unsigned long': ctypes.c_ulong, + 'unsigned long long': ctypes.c_ulonglong, + 'float': ctypes.c_float, + 'double': ctypes.c_double, + '_Bool': ctypes.c_bool, + } + + for _name in ['unsigned long long', 'unsigned long', + 'unsigned int', 'unsigned short', 'unsigned char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] + + for _name in ['long long', 'long', 'int', 'short', 'signed char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] + PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] + + + def __init__(self): + self.RTLD_LAZY = 0 # not supported anyway by ctypes + self.RTLD_NOW = 0 + self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL + self.RTLD_LOCAL = ctypes.RTLD_LOCAL + + def set_ffi(self, ffi): + self.ffi = ffi + + def _get_types(self): + return CTypesData, CTypesType + + def load_library(self, path, flags=0): + cdll = ctypes.CDLL(path, flags) + return CTypesLibrary(self, cdll) + + def new_void_type(self): + class CTypesVoid(CTypesData): + __slots__ = [] + _reftypename = 'void &' + @staticmethod + def _from_ctypes(novalue): + return None + @staticmethod + def _to_ctypes(novalue): + if novalue is not None: + raise TypeError("None expected, got %s object" % + (type(novalue).__name__,)) + return None + CTypesVoid._fix_class() + return CTypesVoid + + def new_primitive_type(self, name): + if name == 'wchar_t': + raise NotImplementedError(name) + ctype = self.PRIMITIVE_TYPES[name] + if name == 'char': + kind = 'char' + elif name in ('float', 'double'): + kind = 'float' + else: + if name in ('signed char', 'unsigned char'): + kind = 'byte' + elif name == '_Bool': + kind = 'bool' + else: + kind = 'int' + is_signed = (ctype(-1).value == -1) + # + def _cast_source_to_int(source): + if isinstance(source, (int, long, float)): + source = int(source) + elif isinstance(source, CTypesData): + source = source._cast_to_integer() + elif isinstance(source, bytes): + source = ord(source) + elif source is None: + source = 0 + else: + raise TypeError("bad type for cast to %r: %r" % + (CTypesPrimitive, type(source).__name__)) + return source + # + kind1 = kind + class CTypesPrimitive(CTypesGenericPrimitive): + __slots__ = ['_value'] + _ctype = ctype + _reftypename = '%s &' % name + kind = kind1 + + def __init__(self, value): + self._value = value + + @staticmethod + def _create_ctype_obj(init): + if init is None: + return ctype() + return ctype(CTypesPrimitive._to_ctypes(init)) + + if kind == 'int' or kind == 'byte': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = ctype(source).value # cast within range + return cls(source) + def __int__(self): + return self._value + + if kind == 'bool': + @classmethod + def _cast_from(cls, source): + if not isinstance(source, (int, long, float)): + source = _cast_source_to_int(source) + return cls(bool(source)) + def __int__(self): + return int(self._value) + + if kind == 'char': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = bytechr(source & 0xFF) + return cls(source) + def __int__(self): + return ord(self._value) + + if kind == 'float': + @classmethod + def _cast_from(cls, source): + if isinstance(source, float): + pass + elif isinstance(source, CTypesGenericPrimitive): + if hasattr(source, '__float__'): + source = float(source) + else: + source = int(source) + else: + source = _cast_source_to_int(source) + source = ctype(source).value # fix precision + return cls(source) + def __int__(self): + return int(self._value) + def __float__(self): + return self._value + + _cast_to_integer = __int__ + + if kind == 'int' or kind == 'byte' or kind == 'bool': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long)): + if isinstance(x, CTypesData): + x = int(x) + else: + raise TypeError("integer expected, got %s" % + type(x).__name__) + if ctype(x).value != x: + if not is_signed and x < 0: + raise OverflowError("%s: negative integer" % name) + else: + raise OverflowError("%s: integer out of bounds" + % name) + return x + + if kind == 'char': + @staticmethod + def _to_ctypes(x): + if isinstance(x, bytes) and len(x) == 1: + return x + if isinstance(x, CTypesPrimitive): # <CData <char>> + return x._value + raise TypeError("character expected, got %s" % + type(x).__name__) + def __nonzero__(self): + return ord(self._value) != 0 + else: + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + if kind == 'float': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long, float, CTypesData)): + raise TypeError("float expected, got %s" % + type(x).__name__) + return ctype(x).value + + @staticmethod + def _from_ctypes(value): + return getattr(value, 'value', value) + + @staticmethod + def _initialize(blob, init): + blob.value = CTypesPrimitive._to_ctypes(init) + + if kind == 'char': + def _to_string(self, maxlen): + return self._value + if kind == 'byte': + def _to_string(self, maxlen): + return chr(self._value & 0xff) + # + CTypesPrimitive._fix_class() + return CTypesPrimitive + + def new_pointer_type(self, BItem): + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'charp' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' + else: + kind = 'generic' + # + class CTypesPtr(CTypesGenericPtr): + __slots__ = ['_own'] + if kind == 'charp': + __slots__ += ['__as_strbuf'] + _BItem = BItem + if hasattr(BItem, '_ctype'): + _ctype = ctypes.POINTER(BItem._ctype) + _bitem_size = ctypes.sizeof(BItem._ctype) + else: + _ctype = ctypes.c_void_p + if issubclass(BItem, CTypesGenericArray): + _reftypename = BItem._get_c_name('(* &)') + else: + _reftypename = BItem._get_c_name(' * &') + + def __init__(self, init): + ctypeobj = BItem._create_ctype_obj(init) + if kind == 'charp': + self.__as_strbuf = ctypes.create_string_buffer( + ctypeobj.value + b'\x00') + self._as_ctype_ptr = ctypes.cast( + self.__as_strbuf, self._ctype) + else: + self._as_ctype_ptr = ctypes.pointer(ctypeobj) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own = True + + def __add__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address + + other * self._bitem_size) + else: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address - + other * self._bitem_size) + elif type(self) is type(other): + return (self._address - other._address) // self._bitem_size + else: + return NotImplemented + + def __getitem__(self, index): + if getattr(self, '_own', False) and index != 0: + raise IndexError + return BItem._from_ctypes(self._as_ctype_ptr[index]) + + def __setitem__(self, index, value): + self._as_ctype_ptr[index] = BItem._to_ctypes(value) + + if kind == 'charp' or kind == 'voidp': + @classmethod + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) + else: + return super(CTypesPtr, cls)._arg_to_ctypes(*value) + + if kind == 'charp' or kind == 'bytep': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = sys.maxsize + p = ctypes.cast(self._as_ctype_ptr, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % ( + ctypes.sizeof(self._as_ctype_ptr.contents),) + return super(CTypesPtr, self)._get_own_repr() + # + if (BItem is self.ffi._get_cached_btype(model.void_type) or + BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): + CTypesPtr._automatic_casts = True + # + CTypesPtr._fix_class() + return CTypesPtr + + def new_array_type(self, CTypesPtr, length): + if length is None: + brackets = ' &[]' + else: + brackets = ' &[%d]' % length + BItem = CTypesPtr._BItem + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'char' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'byte' + else: + kind = 'generic' + # + class CTypesArray(CTypesGenericArray): + __slots__ = ['_blob', '_own'] + if length is not None: + _ctype = BItem._ctype * length + else: + __slots__.append('_ctype') + _reftypename = BItem._get_c_name(brackets) + _declared_length = length + _CTPtr = CTypesPtr + + def __init__(self, init): + if length is None: + if isinstance(init, (int, long)): + len1 = init + init = None + elif kind == 'char' and isinstance(init, bytes): + len1 = len(init) + 1 # extra null + else: + init = tuple(init) + len1 = len(init) + self._ctype = BItem._ctype * len1 + self._blob = self._ctype() + self._own = True + if init is not None: + self._initialize(self._blob, init) + + @staticmethod + def _initialize(blob, init): + if isinstance(init, bytes): + init = [init[i:i+1] for i in range(len(init))] + else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) + init = tuple(init) + if len(init) > len(blob): + raise IndexError("too many initializers") + addr = ctypes.cast(blob, ctypes.c_void_p).value + PTR = ctypes.POINTER(BItem._ctype) + itemsize = ctypes.sizeof(BItem._ctype) + for i, value in enumerate(init): + p = ctypes.cast(addr + i * itemsize, PTR) + BItem._initialize(p.contents, value) + + def __len__(self): + return len(self._blob) + + def __getitem__(self, index): + if not (0 <= index < len(self._blob)): + raise IndexError + return BItem._from_ctypes(self._blob[index]) + + def __setitem__(self, index, value): + if not (0 <= index < len(self._blob)): + raise IndexError + self._blob[index] = BItem._to_ctypes(value) + + if kind == 'char' or kind == 'byte': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = len(self._blob) + p = ctypes.cast(self._blob, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % (ctypes.sizeof(self._blob),) + return super(CTypesArray, self)._get_own_repr() + + def _convert_to_address(self, BClass): + if BClass in (CTypesPtr, None) or BClass._automatic_casts: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @staticmethod + def _from_ctypes(ctypes_array): + self = CTypesArray.__new__(CTypesArray) + self._blob = ctypes_array + return self + + @staticmethod + def _arg_to_ctypes(value): + return CTypesPtr._arg_to_ctypes(value) + + def __add__(self, other): + if isinstance(other, (int, long)): + return CTypesPtr._new_pointer_at( + ctypes.addressof(self._blob) + + other * ctypes.sizeof(BItem._ctype)) + else: + return NotImplemented + + @classmethod + def _cast_from(cls, source): + raise NotImplementedError("casting to %r" % ( + cls._get_c_name(),)) + # + CTypesArray._fix_class() + return CTypesArray + + def _new_struct_or_union(self, kind, name, base_ctypes_class): + # + class struct_or_union(base_ctypes_class): + pass + struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind + # + class CTypesStructOrUnion(CTypesBaseStructOrUnion): + __slots__ = ['_blob'] + _ctype = struct_or_union + _reftypename = '%s &' % (name,) + _kind = kind = kind1 + # + CTypesStructOrUnion._fix_class() + return CTypesStructOrUnion + + def new_struct_type(self, name): + return self._new_struct_or_union('struct', name, ctypes.Structure) + + def new_union_type(self, name): + return self._new_struct_or_union('union', name, ctypes.Union) + + def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, + totalsize=-1, totalalignment=-1, sflags=0, + pack=0): + if totalsize >= 0 or totalalignment >= 0: + raise NotImplementedError("the ctypes backend of CFFI does not support " + "structures completed by verify(); please " + "compile and install the _cffi_backend module.") + struct_or_union = CTypesStructOrUnion._ctype + fnames = [fname for (fname, BField, bitsize) in fields] + btypes = [BField for (fname, BField, bitsize) in fields] + bitfields = [bitsize for (fname, BField, bitsize) in fields] + # + bfield_types = {} + cfields = [] + for (fname, BField, bitsize) in fields: + if bitsize < 0: + cfields.append((fname, BField._ctype)) + bfield_types[fname] = BField + else: + cfields.append((fname, BField._ctype, bitsize)) + bfield_types[fname] = Ellipsis + if sflags & 8: + struct_or_union._pack_ = 1 + elif pack: + struct_or_union._pack_ = pack + struct_or_union._fields_ = cfields + CTypesStructOrUnion._bfield_types = bfield_types + # + @staticmethod + def _create_ctype_obj(init): + result = struct_or_union() + if init is not None: + initialize(result, init) + return result + CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj + # + def initialize(blob, init): + if is_union: + if len(init) > 1: + raise ValueError("union initializer: %d items given, but " + "only one supported (use a dict if needed)" + % (len(init),)) + if not isinstance(init, dict): + if isinstance(init, (bytes, unicode)): + raise TypeError("union initializer: got a str") + init = tuple(init) + if len(init) > len(fnames): + raise ValueError("too many values for %s initializer" % + CTypesStructOrUnion._get_c_name()) + init = dict(zip(fnames, init)) + addr = ctypes.addressof(blob) + for fname, value in init.items(): + BField, bitsize = name2fieldtype[fname] + assert bitsize < 0, \ + "not implemented: initializer with bit fields" + offset = CTypesStructOrUnion._offsetof(fname) + PTR = ctypes.POINTER(BField._ctype) + p = ctypes.cast(addr + offset, PTR) + BField._initialize(p.contents, value) + is_union = CTypesStructOrUnion._kind == 'union' + name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) + # + for fname, BField, bitsize in fields: + if fname == '': + raise NotImplementedError("nested anonymous structs/unions") + if hasattr(CTypesStructOrUnion, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + if bitsize < 0: + def getter(self, fname=fname, BField=BField, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BField._from_ctypes(p.contents) + def setter(self, value, fname=fname, BField=BField): + setattr(self._blob, fname, BField._to_ctypes(value)) + # + if issubclass(BField, CTypesGenericArray): + setter = None + if BField._declared_length == 0: + def getter(self, fname=fname, BFieldPtr=BField._CTPtr, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BFieldPtr._from_ctypes(p) + # + else: + def getter(self, fname=fname, BField=BField): + return BField._from_ctypes(getattr(self._blob, fname)) + def setter(self, value, fname=fname, BField=BField): + # xxx obscure workaround + value = BField._to_ctypes(value) + oldvalue = getattr(self._blob, fname) + setattr(self._blob, fname, value) + if value != getattr(self._blob, fname): + setattr(self._blob, fname, oldvalue) + raise OverflowError("value too large for bitfield") + setattr(CTypesStructOrUnion, fname, property(getter, setter)) + # + CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) + for fname in fnames: + if hasattr(CTypesPtr, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + def getter(self, fname=fname): + return getattr(self[0], fname) + def setter(self, value, fname=fname): + setattr(self[0], fname, value) + setattr(CTypesPtr, fname, property(getter, setter)) + + def new_function_type(self, BArgs, BResult, has_varargs): + nameargs = [BArg._get_c_name() for BArg in BArgs] + if has_varargs: + nameargs.append('...') + nameargs = ', '.join(nameargs) + # + class CTypesFunctionPtr(CTypesGenericPtr): + __slots__ = ['_own_callback', '_name'] + _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), + *[BArg._ctype for BArg in BArgs], + use_errno=True) + _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) + + def __init__(self, init, error=None): + # create a callback to the Python callable init() + import traceback + assert not has_varargs, "varargs not supported for callbacks" + if getattr(BResult, '_ctype', None) is not None: + error = BResult._from_ctypes( + BResult._create_ctype_obj(error)) + else: + error = None + def callback(*args): + args2 = [] + for arg, BArg in zip(args, BArgs): + args2.append(BArg._from_ctypes(arg)) + try: + res2 = init(*args2) + res2 = BResult._to_ctypes(res2) + except: + traceback.print_exc() + res2 = error + if issubclass(BResult, CTypesGenericPtr): + if res2: + res2 = ctypes.cast(res2, ctypes.c_void_p).value + # .value: http://bugs.python.org/issue1574593 + else: + res2 = None + #print repr(res2) + return res2 + if issubclass(BResult, CTypesGenericPtr): + # The only pointers callbacks can return are void*s: + # http://bugs.python.org/issue5710 + callback_ctype = ctypes.CFUNCTYPE( + ctypes.c_void_p, + *[BArg._ctype for BArg in BArgs], + use_errno=True) + else: + callback_ctype = CTypesFunctionPtr._ctype + self._as_ctype_ptr = callback_ctype(callback) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own_callback = init + + @staticmethod + def _initialize(ctypes_ptr, value): + if value: + raise NotImplementedError("ctypes backend: not supported: " + "initializers for function pointers") + + def __repr__(self): + c_name = getattr(self, '_name', None) + if c_name: + i = self._reftypename.index('(* &)') + if self._reftypename[i-1] not in ' )*': + c_name = ' ' + c_name + c_name = self._reftypename.replace('(* &)', c_name) + return CTypesData.__repr__(self, c_name) + + def _get_own_repr(self): + if getattr(self, '_own_callback', None) is not None: + return 'calling %r' % (self._own_callback,) + return super(CTypesFunctionPtr, self)._get_own_repr() + + def __call__(self, *args): + if has_varargs: + assert len(args) >= len(BArgs) + extraargs = args[len(BArgs):] + args = args[:len(BArgs)] + else: + assert len(args) == len(BArgs) + ctypes_args = [] + for arg, BArg in zip(args, BArgs): + ctypes_args.append(BArg._arg_to_ctypes(arg)) + if has_varargs: + for i, arg in enumerate(extraargs): + if arg is None: + ctypes_args.append(ctypes.c_void_p(0)) # NULL + continue + if not isinstance(arg, CTypesData): + raise TypeError( + "argument %d passed in the variadic part " + "needs to be a cdata object (got %s)" % + (1 + len(BArgs) + i, type(arg).__name__)) + ctypes_args.append(arg._arg_to_ctypes(arg)) + result = self._as_ctype_ptr(*ctypes_args) + return BResult._from_ctypes(result) + # + CTypesFunctionPtr._fix_class() + return CTypesFunctionPtr + + def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): + assert isinstance(name, str) + reverse_mapping = dict(zip(reversed(enumvalues), + reversed(enumerators))) + # + class CTypesEnum(CTypesInt): + __slots__ = [] + _reftypename = '%s &' % name + + def _get_own_repr(self): + value = self._value + try: + return '%d: %s' % (value, reverse_mapping[value]) + except KeyError: + return str(value) + + def _to_string(self, maxlen): + value = self._value + try: + return reverse_mapping[value] + except KeyError: + return str(value) + # + CTypesEnum._fix_class() + return CTypesEnum + + def get_errno(self): + return ctypes.get_errno() + + def set_errno(self, value): + ctypes.set_errno(value) + + def string(self, b, maxlen=-1): + return b._to_string(maxlen) + + def buffer(self, bptr, size=-1): + raise NotImplementedError("buffer() with ctypes backend") + + def sizeof(self, cdata_or_BType): + if isinstance(cdata_or_BType, CTypesData): + return cdata_or_BType._get_size_of_instance() + else: + assert issubclass(cdata_or_BType, CTypesData) + return cdata_or_BType._get_size() + + def alignof(self, BType): + assert issubclass(BType, CTypesData) + return BType._alignment() + + def newp(self, BType, source): + if not issubclass(BType, CTypesData): + raise TypeError + return BType._newp(source) + + def cast(self, BType, source): + return BType._cast_from(source) + + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented + return BType(source, error) + + _weakref_cache_ref = None + + def gcp(self, cdata, destructor, size=0): + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref + + if destructor is None: + try: + del weak_cache[MyRef(cdata)] + except KeyError: + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + return None + + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) + return new_cdata + + typeof = type + + def getcname(self, BType, replace_with): + return BType._get_c_name(replace_with) + + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") + BField = BType._bfield_types[fieldname] + if BField is Ellipsis: + raise TypeError("not supported for bitfields") + return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) + + def rawaddressof(self, BTypePtr, cdata, offset=None): + if isinstance(cdata, CTypesBaseStructOrUnion): + ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) + elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): + ptr = type(cdata)._to_ctypes(cdata) + else: + raise TypeError("expected a <cdata 'struct-or-union'>") + if offset: + ptr = ctypes.cast( + ctypes.c_void_p( + ctypes.cast(ptr, ctypes.c_void_p).value + offset), + type(ptr)) + return BTypePtr._from_ctypes(ptr) + + +class CTypesLibrary(object): + + def __init__(self, backend, cdll): + self.backend = backend + self.cdll = cdll + + def load_function(self, BType, name): + c_func = getattr(self.cdll, name) + funcobj = BType._from_ctypes(c_func) + funcobj._name = name + return funcobj + + def read_variable(self, BType, name): + try: + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + except AttributeError as e: + raise NotImplementedError(e) + return BType._from_ctypes(ctypes_obj) + + def write_variable(self, BType, name, value): + new_ctypes_obj = BType._to_ctypes(value) + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + ctypes.memmove(ctypes.addressof(ctypes_obj), + ctypes.addressof(new_ctypes_obj), + ctypes.sizeof(BType._ctype)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/cffi_opcode.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/cffi_opcode.py new file mode 100644 index 0000000000000000000000000000000000000000..a0df98d1c743790f4047672abcae0d00f993a2ce --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp(object): + def __init__(self, op, arg): + self.op = op + self.arg = arg + + def as_c_expr(self): + if self.op is None: + assert isinstance(self.arg, str) + return '(_cffi_opcode_t)(%s)' % (self.arg,) + classname = CLASS_NAME[self.op] + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) + + def as_python_bytes(self): + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): + raise VerificationError("cannot emit to Python: %r" % (self.arg,)) + return format_four_bytes((self.arg << 8) | self.op) + + def __str__(self): + classname = CLASS_NAME.get(self.op, self.op) + return '(%s %s)' % (classname, self.arg) + +def format_four_bytes(num): + return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( + (num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + (num ) & 0xFF) + +OP_PRIMITIVE = 1 +OP_POINTER = 3 +OP_ARRAY = 5 +OP_OPEN_ARRAY = 7 +OP_STRUCT_UNION = 9 +OP_ENUM = 11 +OP_FUNCTION = 13 +OP_FUNCTION_END = 15 +OP_NOOP = 17 +OP_BITFIELD = 19 +OP_TYPENAME = 21 +OP_CPYTHON_BLTN_V = 23 # varargs +OP_CPYTHON_BLTN_N = 25 # noargs +OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 +OP_DLOPEN_FUNC = 35 +OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 +OP_EXTERN_PYTHON = 41 + +PRIM_VOID = 0 +PRIM_BOOL = 1 +PRIM_CHAR = 2 +PRIM_SCHAR = 3 +PRIM_UCHAR = 4 +PRIM_SHORT = 5 +PRIM_USHORT = 6 +PRIM_INT = 7 +PRIM_UINT = 8 +PRIM_LONG = 9 +PRIM_ULONG = 10 +PRIM_LONGLONG = 11 +PRIM_ULONGLONG = 12 +PRIM_FLOAT = 13 +PRIM_DOUBLE = 14 +PRIM_LONGDOUBLE = 15 + +PRIM_WCHAR = 16 +PRIM_INT8 = 17 +PRIM_UINT8 = 18 +PRIM_INT16 = 19 +PRIM_UINT16 = 20 +PRIM_INT32 = 21 +PRIM_UINT32 = 22 +PRIM_INT64 = 23 +PRIM_UINT64 = 24 +PRIM_INTPTR = 25 +PRIM_UINTPTR = 26 +PRIM_PTRDIFF = 27 +PRIM_SIZE = 28 +PRIM_SSIZE = 29 +PRIM_INT_LEAST8 = 30 +PRIM_UINT_LEAST8 = 31 +PRIM_INT_LEAST16 = 32 +PRIM_UINT_LEAST16 = 33 +PRIM_INT_LEAST32 = 34 +PRIM_UINT_LEAST32 = 35 +PRIM_INT_LEAST64 = 36 +PRIM_UINT_LEAST64 = 37 +PRIM_INT_FAST8 = 38 +PRIM_UINT_FAST8 = 39 +PRIM_INT_FAST16 = 40 +PRIM_UINT_FAST16 = 41 +PRIM_INT_FAST32 = 42 +PRIM_UINT_FAST32 = 43 +PRIM_INT_FAST64 = 44 +PRIM_UINT_FAST64 = 45 +PRIM_INTMAX = 46 +PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 +PRIM_CHAR16 = 50 +PRIM_CHAR32 = 51 + +_NUM_PRIM = 52 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 + +_IO_FILE_STRUCT = -1 + +PRIMITIVE_TO_INDEX = { + 'char': PRIM_CHAR, + 'short': PRIM_SHORT, + 'int': PRIM_INT, + 'long': PRIM_LONG, + 'long long': PRIM_LONGLONG, + 'signed char': PRIM_SCHAR, + 'unsigned char': PRIM_UCHAR, + 'unsigned short': PRIM_USHORT, + 'unsigned int': PRIM_UINT, + 'unsigned long': PRIM_ULONG, + 'unsigned long long': PRIM_ULONGLONG, + 'float': PRIM_FLOAT, + 'double': PRIM_DOUBLE, + 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, + '_Bool': PRIM_BOOL, + 'wchar_t': PRIM_WCHAR, + 'char16_t': PRIM_CHAR16, + 'char32_t': PRIM_CHAR32, + 'int8_t': PRIM_INT8, + 'uint8_t': PRIM_UINT8, + 'int16_t': PRIM_INT16, + 'uint16_t': PRIM_UINT16, + 'int32_t': PRIM_INT32, + 'uint32_t': PRIM_UINT32, + 'int64_t': PRIM_INT64, + 'uint64_t': PRIM_UINT64, + 'intptr_t': PRIM_INTPTR, + 'uintptr_t': PRIM_UINTPTR, + 'ptrdiff_t': PRIM_PTRDIFF, + 'size_t': PRIM_SIZE, + 'ssize_t': PRIM_SSIZE, + 'int_least8_t': PRIM_INT_LEAST8, + 'uint_least8_t': PRIM_UINT_LEAST8, + 'int_least16_t': PRIM_INT_LEAST16, + 'uint_least16_t': PRIM_UINT_LEAST16, + 'int_least32_t': PRIM_INT_LEAST32, + 'uint_least32_t': PRIM_UINT_LEAST32, + 'int_least64_t': PRIM_INT_LEAST64, + 'uint_least64_t': PRIM_UINT_LEAST64, + 'int_fast8_t': PRIM_INT_FAST8, + 'uint_fast8_t': PRIM_UINT_FAST8, + 'int_fast16_t': PRIM_INT_FAST16, + 'uint_fast16_t': PRIM_UINT_FAST16, + 'int_fast32_t': PRIM_INT_FAST32, + 'uint_fast32_t': PRIM_UINT_FAST32, + 'int_fast64_t': PRIM_INT_FAST64, + 'uint_fast64_t': PRIM_UINT_FAST64, + 'intmax_t': PRIM_INTMAX, + 'uintmax_t': PRIM_UINTMAX, + } + +F_UNION = 0x01 +F_CHECK_FIELDS = 0x02 +F_PACKED = 0x04 +F_EXTERNAL = 0x08 +F_OPAQUE = 0x10 + +G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) + for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', + 'F_EXTERNAL', 'F_OPAQUE']]) + +CLASS_NAME = {} +for _name, _value in list(globals().items()): + if _name.startswith('OP_') and isinstance(_value, int): + CLASS_NAME[_value] = _name[3:] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/commontypes.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/commontypes.py new file mode 100644 index 0000000000000000000000000000000000000000..8ec97c756a4b1023fd3963dd39b706f7c0e34373 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/commontypes.py @@ -0,0 +1,80 @@ +import sys +from . import model +from .error import FFIError + + +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above + +for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + if _type.endswith('_t'): + COMMON_TYPES[_type] = _type +del _type + +_CACHE = {} + +def resolve_common_type(parser, commontype): + try: + return _CACHE[commontype] + except KeyError: + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': + raise FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) + else: + if commontype == cdecl: + raise FFIError( + "Unsupported type: %r. Please look at " + "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " + "and file an issue if you think this type should really " + "be supported." % (commontype,)) + result, quals = parser.parse_type_and_quals(cdecl) # recursive + + assert isinstance(result, model.BaseTypeByIdentity) + _CACHE[commontype] = result, quals + return result, quals + + +# ____________________________________________________________ +# extra types for Windows (most of them are in commontypes.c) + + +def win_common_types(): + return { + "UNICODE_STRING": model.StructType( + "_UNICODE_STRING", + ["Length", + "MaximumLength", + "Buffer"], + [model.PrimitiveType("unsigned short"), + model.PrimitiveType("unsigned short"), + model.PointerType(model.PrimitiveType("wchar_t"))], + [-1, -1, -1]), + "PUNICODE_STRING": "UNICODE_STRING *", + "PCUNICODE_STRING": "const UNICODE_STRING *", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", + } + +if sys.platform == 'win32': + COMMON_TYPES.update(win_common_types()) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/cparser.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/cparser.py new file mode 100644 index 0000000000000000000000000000000000000000..74830e913f21409f536febddae7769d0364cd24b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/cparser.py @@ -0,0 +1,1006 @@ +from . import model +from .commontypes import COMMON_TYPES, resolve_common_type +from .error import FFIError, CDefError +try: + from . import _pycparser as pycparser +except ImportError: + import pycparser +import weakref, re, sys + +try: + if sys.version_info < (3,): + import thread as _thread + else: + import _thread + lock = _thread.allocate_lock() +except ImportError: + lock = None + +def _workaround_for_static_import_finders(): + # Issue #392: packaging tools like cx_Freeze can not find these + # because pycparser uses exec dynamic import. This is an obscure + # workaround. This function is never called. + import pycparser.yacctab + import pycparser.lextab + +CDEF_SOURCE_STRING = "<cdef source string>" +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) +_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) +_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") +_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") +_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") +_r_words = re.compile(r"\w+|\S") +_parser_cache = None +_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) +_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") +_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") +_r_cdecl = re.compile(r"\b__cdecl\b") +_r_extern_python = re.compile(r'\bextern\s*"' + r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") +_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" + r"\.\.\.") +_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") + +def _get_parser(): + global _parser_cache + if _parser_cache is None: + _parser_cache = pycparser.CParser() + return _parser_cache + +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + +def _preprocess_extern_python(csource): + # input: `extern "Python" int foo(int);` or + # `extern "Python" { int foo(int); }` + # output: + # void __cffi_extern_python_start; + # int foo(int); + # void __cffi_extern_python_stop; + # + # input: `extern "Python+C" int foo(int);` + # output: + # void __cffi_extern_python_plus_c_start; + # int foo(int); + # void __cffi_extern_python_stop; + parts = [] + while True: + match = _r_extern_python.search(csource) + if not match: + break + endpos = match.end() - 1 + #print + #print ''.join(parts)+csource + #print '=>' + parts.append(csource[:match.start()]) + if 'C' in match.group(1): + parts.append('void __cffi_extern_python_plus_c_start; ') + else: + parts.append('void __cffi_extern_python_start; ') + if csource[endpos] == '{': + # grouping variant + closing = csource.find('}', endpos) + if closing < 0: + raise CDefError("'extern \"Python\" {': no '}' found") + if csource.find('{', endpos + 1, closing) >= 0: + raise NotImplementedError("cannot use { } inside a block " + "'extern \"Python\" { ... }'") + parts.append(csource[endpos+1:closing]) + csource = csource[closing+1:] + else: + # non-grouping variant + semicolon = csource.find(';', endpos) + if semicolon < 0: + raise CDefError("'extern \"Python\": no ';' found") + parts.append(csource[endpos:semicolon+1]) + csource = csource[semicolon+1:] + parts.append(' void __cffi_extern_python_stop;') + #print ''.join(parts)+csource + #print + parts.append(csource) + return ''.join(parts) + +def _warn_for_string_literal(csource): + if '"' not in csource: + return + for line in csource.splitlines(): + if '"' in line and not line.lstrip().startswith('#'): + import warnings + warnings.warn("String literal found in cdef() or type source. " + "String literals are ignored here, but you should " + "remove them anyway because some character sequences " + "confuse pre-parsing.") + break + +def _warn_for_non_extern_non_static_global_variable(decl): + if not decl.storage: + import warnings + warnings.warn("Global variable '%s' in cdef(): for consistency " + "with C it should have a storage class specifier " + "(usually 'extern')" % (decl.name,)) + +def _remove_line_directives(csource): + # _r_line_directive matches whole lines, without the final \n, if they + # start with '#line' with some spacing allowed, or '#NUMBER'. This + # function stores them away and replaces them with exactly the string + # '#line@N', where N is the index in the list 'line_directives'. + line_directives = [] + def replace(m): + i = len(line_directives) + line_directives.append(m.group()) + return '#line@%d' % i + csource = _r_line_directive.sub(replace, csource) + return csource, line_directives + +def _put_back_line_directives(csource, line_directives): + def replace(m): + s = m.group() + if not s.startswith('#line@'): + raise AssertionError("unexpected #line directive " + "(should have been processed and removed") + return line_directives[int(s[6:])] + return _r_line_directive.sub(replace, csource) + +def _preprocess(csource): + # First, remove the lines of the form '#line N "filename"' because + # the "filename" part could confuse the rest + csource, line_directives = _remove_line_directives(csource) + # Remove comments. NOTE: this only work because the cdef() section + # should not contain any string literals (except in line directives)! + def replace_keeping_newlines(m): + return ' ' + m.group().count('\n') * '\n' + csource = _r_comment.sub(replace_keeping_newlines, csource) + # Remove the "#define FOO x" lines + macros = {} + for match in _r_define.finditer(csource): + macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() + macros[macroname] = macrovalue + csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # + # BIG HACK: replace WINAPI or __stdcall with "volatile const". + # It doesn't make sense for the return type of a function to be + # "volatile volatile const", so we abuse it to detect __stdcall... + # Hack number 2 is that "int(volatile *fptr)();" is not valid C + # syntax, so we place the "volatile" before the opening parenthesis. + csource = _r_stdcall2.sub(' volatile volatile const(', csource) + csource = _r_stdcall1.sub(' volatile volatile const ', csource) + csource = _r_cdecl.sub(' ', csource) + # + # Replace `extern "Python"` with start/end markers + csource = _preprocess_extern_python(csource) + # + # Now there should not be any string literal left; warn if we get one + _warn_for_string_literal(csource) + # + # Replace "[...]" with "[__dotdotdotarray__]" + csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) + # + # Replace "...}" with "__dotdotdotNUM__}". This construction should + # occur only at the end of enums; at the end of structs we have "...;}" + # and at the end of vararg functions "...);". Also replace "=...[,}]" + # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when + # giving an unknown value. + matches = list(_r_partial_enum.finditer(csource)) + for number, match in enumerate(reversed(matches)): + p = match.start() + if csource[p] == '=': + p2 = csource.find('...', p, match.end()) + assert p2 > p + csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, + csource[p2+3:]) + else: + assert csource[p:p+3] == '...' + csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, + csource[p+3:]) + # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" + csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) + # Replace "float ..." or "double..." with "__dotdotdotfloat__" + csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) + # Replace all remaining "..." with the same name, "__dotdotdot__", + # which is declared with a typedef for the purpose of C parsing. + csource = csource.replace('...', ' __dotdotdot__ ') + # Finally, put back the line directives + csource = _put_back_line_directives(csource, line_directives) + return csource, macros + +def _common_type_names(csource): + # Look in the source for what looks like usages of types from the + # list of common types. A "usage" is approximated here as the + # appearance of the word, minus a "definition" of the type, which + # is the last word in a "typedef" statement. Approximative only + # but should be fine for all the common types. + look_for_words = set(COMMON_TYPES) + look_for_words.add(';') + look_for_words.add(',') + look_for_words.add('(') + look_for_words.add(')') + look_for_words.add('typedef') + words_used = set() + is_typedef = False + paren = 0 + previous_word = '' + for word in _r_words.findall(csource): + if word in look_for_words: + if word == ';': + if is_typedef: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + is_typedef = False + elif word == 'typedef': + is_typedef = True + paren = 0 + elif word == '(': + paren += 1 + elif word == ')': + paren -= 1 + elif word == ',': + if is_typedef and paren == 0: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + else: # word in COMMON_TYPES + words_used.add(word) + previous_word = word + return words_used + + +class Parser(object): + + def __init__(self): + self._declarations = {} + self._included_declarations = set() + self._anonymous_counter = 0 + self._structnode2type = weakref.WeakKeyDictionary() + self._options = {} + self._int_constants = {} + self._recomplete = [] + self._uses_new_feature = None + + def _parse(self, csource): + csource, macros = _preprocess(csource) + # XXX: for more efficiency we would need to poke into the + # internals of CParser... the following registers the + # typedefs, because their presence or absence influences the + # parsing itself (but what they are typedef'ed to plays no role) + ctn = _common_type_names(csource) + typenames = [] + for name in sorted(self._declarations): + if name.startswith('typedef '): + name = name[8:] + typenames.append(name) + ctn.discard(name) + typenames += sorted(ctn) + # + csourcelines = [] + csourcelines.append('# 1 "<cdef automatic initialization code>"') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) + csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' + ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called <cdef source string> from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) + csourcelines.append(csource) + fullcsource = '\n'.join(csourcelines) + if lock is not None: + lock.acquire() # pycparser is not thread-safe... + try: + ast = _get_parser().parse(fullcsource) + except pycparser.c_parser.ParseError as e: + self.convert_pycparser_error(e, csource) + finally: + if lock is not None: + lock.release() + # csource will be used to find buggy source text + return ast, macros, csource + + def _convert_pycparser_error(self, e, csource): + # xxx look for "<cdef source string>:NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. + line = None + msg = str(e) + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + return line + + def convert_pycparser_error(self, e, csource): + line = self._convert_pycparser_error(e, csource) + + msg = str(e) + if line: + msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) + else: + msg = 'parse error\n%s' % (msg,) + raise CDefError(msg) + + def parse(self, csource, override=False, packed=False, pack=None, + dllexport=False): + if packed: + if packed != True: + raise ValueError("'packed' should be False or True; use " + "'pack' to give another value") + if pack: + raise ValueError("cannot give both 'pack' and 'packed'") + pack = 1 + elif pack: + if pack & (pack - 1): + raise ValueError("'pack' must be a power of two, not %r" % + (pack,)) + else: + pack = 0 + prev_options = self._options + try: + self._options = {'override': override, + 'packed': pack, + 'dllexport': dllexport} + self._internal_parse(csource) + finally: + self._options = prev_options + + def _internal_parse(self, csource): + ast, macros, csource = self._parse(csource) + # add the macros + self._process_macros(macros) + # find the first "__dotdotdot__" and use that as a separator + # between the repeated typedefs and the real csource + iterator = iter(ast.ext) + for decl in iterator: + if decl.name == '__dotdotdot__': + break + else: + assert 0 + current_decl = None + # + try: + self._inside_extern_python = '__cffi_extern_python_stop' + for decl in iterator: + current_decl = decl + if isinstance(decl, pycparser.c_ast.Decl): + self._parse_decl(decl) + elif isinstance(decl, pycparser.c_ast.Typedef): + if not decl.name: + raise CDefError("typedef does not declare any name", + decl) + quals = 0 + if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and + decl.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_type(decl) + elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and + isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and + isinstance(decl.type.type.type, + pycparser.c_ast.IdentifierType) and + decl.type.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_ptr_type(decl) + else: + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name, partial_length_ok=True, + typedef_example="*(%s *)0" % (decl.name,)) + self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 + else: + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise + except FFIError as e: + msg = self._convert_pycparser_error(e, csource) + if msg: + e.args = (e.args[0] + "\n *** Err: %s" % msg,) + raise + + def _add_constants(self, key, val): + if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations + raise FFIError( + "multiple declarations of constant: %s" % (key,)) + self._int_constants[key] = val + + def _add_integer_constant(self, name, int_str): + int_str = int_str.lower().rstrip("ul") + neg = int_str.startswith('-') + if neg: + int_str = int_str[1:] + # "010" is not valid oct in py3 + if (int_str.startswith("0") and int_str != '0' + and not int_str.startswith("0x")): + int_str = "0o" + int_str[1:] + pyvalue = int(int_str, 0) + if neg: + pyvalue = -pyvalue + self._add_constants(name, pyvalue) + self._declare('macro ' + name, pyvalue) + + def _process_macros(self, macros): + for key, value in macros.items(): + value = value.strip() + if _r_int_literal.match(value): + self._add_integer_constant(key, value) + elif value == '...': + self._declare('macro ' + key, value) + else: + raise CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) + + def _declare_function(self, tp, quals, decl): + tp = self._get_type_pointer(tp, quals) + if self._options.get('dllexport'): + tag = 'dllexport_python ' + elif self._inside_extern_python == '__cffi_extern_python_start': + tag = 'extern_python ' + elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': + tag = 'extern_python_plus_c ' + else: + tag = 'function ' + self._declare(tag + decl.name, tp) + + def _parse_decl(self, decl): + node = decl.type + if isinstance(node, pycparser.c_ast.FuncDecl): + tp, quals = self._get_type_and_quals(node, name=decl.name) + assert isinstance(tp, model.RawFunctionType) + self._declare_function(tp, quals, decl) + else: + if isinstance(node, pycparser.c_ast.Struct): + self._get_struct_union_enum_type('struct', node) + elif isinstance(node, pycparser.c_ast.Union): + self._get_struct_union_enum_type('union', node) + elif isinstance(node, pycparser.c_ast.Enum): + self._get_struct_union_enum_type('enum', node) + elif not decl.name: + raise CDefError("construct does not declare any variable", + decl) + # + if decl.name: + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) + if tp.is_raw_function: + self._declare_function(tp, quals, decl) + elif (tp.is_integer_type() and + hasattr(decl, 'init') and + hasattr(decl.init, 'value') and + _r_int_literal.match(decl.init.value)): + self._add_integer_constant(decl.name, decl.init.value) + elif (tp.is_integer_type() and + isinstance(decl.init, pycparser.c_ast.UnaryOp) and + decl.init.op == '-' and + hasattr(decl.init.expr, 'value') and + _r_int_literal.match(decl.init.expr.value)): + self._add_integer_constant(decl.name, + '-' + decl.init.expr.value) + elif (tp is model.void_type and + decl.name.startswith('__cffi_extern_python_')): + # hack: `extern "Python"` in the C source is replaced + # with "void __cffi_extern_python_start;" and + # "void __cffi_extern_python_stop;" + self._inside_extern_python = decl.name + else: + if self._inside_extern_python !='__cffi_extern_python_stop': + raise CDefError( + "cannot declare constants or " + "variables with 'extern \"Python\"'") + if (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) + else: + _warn_for_non_extern_non_static_global_variable(decl) + self._declare('variable ' + decl.name, tp, quals=quals) + + def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): + ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] + assert not macros + exprnode = ast.ext[-1].type.args.params[0] + if isinstance(exprnode, pycparser.c_ast.ID): + raise CDefError("unknown identifier '%s'" % (exprnode.name,)) + return self._get_type_and_quals(exprnode.type) + + def _declare(self, name, obj, included=False, quals=0): + if name in self._declarations: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: + return + if not self._options.get('override'): + raise FFIError( + "multiple declarations of %s (for interactive usage, " + "try cdef(xx, override=True))" % (name,)) + assert '__dotdotdot__' not in name.split() + self._declarations[name] = (obj, quals) + if included: + self._included_declarations.add(obj) + + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): + if isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + if (isinstance(type, model.StructOrUnionOrEnum) and + type.name.startswith('$') and type.name[1:].isdigit() and + type.forcename is None and declname is not None): + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) + + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, + typedef_example=None): + # first, dereference typedefs, if we have it already parsed, we're good + if (isinstance(typenode, pycparser.c_ast.TypeDecl) and + isinstance(typenode.type, pycparser.c_ast.IdentifierType) and + len(typenode.type.names) == 1 and + ('typedef ' + typenode.type.names[0]) in self._declarations): + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.ArrayDecl): + # array type + if typenode.dim is None: + length = None + else: + length = self._parse_constant( + typenode.dim, partial_length_ok=partial_length_ok) + # a hack: in 'typedef int foo_t[...][...];', don't use '...' as + # the length but use directly the C expression that would be + # generated by recompiler.py. This lets the typedef be used in + # many more places within recompiler.py + if typedef_example is not None: + if length == '...': + length = '_cffi_array_len(%s)' % (typedef_example,) + typedef_example = "*" + typedef_example + # + tp, quals = self._get_type_and_quals(typenode.type, + partial_length_ok=partial_length_ok, + typedef_example=typedef_example) + return model.ArrayType(tp, length), quals + # + if isinstance(typenode, pycparser.c_ast.PtrDecl): + # pointer type + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) + type = typenode.type + if isinstance(type, pycparser.c_ast.IdentifierType): + # assume a primitive type. get it from .names, but reduce + # synonyms to a single chosen combination + names = list(type.names) + if names != ['signed', 'char']: # keep this unmodified + prefixes = {} + while names: + name = names[0] + if name in ('short', 'long', 'signed', 'unsigned'): + prefixes[name] = prefixes.get(name, 0) + 1 + del names[0] + else: + break + # ignore the 'signed' prefix below, and reorder the others + newnames = [] + for prefix in ('unsigned', 'short', 'long'): + for i in range(prefixes.get(prefix, 0)): + newnames.append(prefix) + if not names: + names = ['int'] # implicitly + if names == ['int']: # but kill it if 'short' or 'long' + if 'short' in prefixes or 'long' in prefixes: + names = [] + names = newnames + names + ident = ' '.join(names) + if ident == 'void': + return model.void_type, quals + if ident == '__dotdotdot__': + raise FFIError(':%d: bad usage of "..."' % + typenode.coord.line) + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) + # + if isinstance(type, pycparser.c_ast.Struct): + # 'struct foobar' + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Union): + # 'union foobar' + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Enum): + # 'enum foobar' + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.FuncDecl): + # a function type + return self._parse_function_type(typenode, name), 0 + # + # nested anonymous structs or unions end up here + if isinstance(typenode, pycparser.c_ast.Struct): + return self._get_struct_union_enum_type('struct', typenode, name, + nested=True), 0 + if isinstance(typenode, pycparser.c_ast.Union): + return self._get_struct_union_enum_type('union', typenode, name, + nested=True), 0 + # + raise FFIError(":%d: bad or unsupported type declaration" % + typenode.coord.line) + + def _parse_function_type(self, typenode, funcname=None): + params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) + ellipsis = ( + len(params) > 0 and + isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and + isinstance(params[-1].type.type, + pycparser.c_ast.IdentifierType) and + params[-1].type.type.names == ['__dotdotdot__']) + if ellipsis: + params.pop() + if not params: + raise CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) + for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] + result, quals = self._get_type_and_quals(typenode.type) + # the 'quals' on the result type are ignored. HACK: we absure them + # to detect __stdcall functions: we textually replace "__stdcall" + # with "volatile volatile const" above. + abi = None + if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway + if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: + abi = '__stdcall' + return model.RawFunctionType(tuple(args), result, ellipsis, abi) + + def _as_func_arg(self, type, quals): + if isinstance(type, model.ArrayType): + return model.PointerType(type.item, quals) + elif isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + else: + return type + + def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): + # First, a level of caching on the exact 'type' node of the AST. + # This is obscure, but needed because pycparser "unrolls" declarations + # such as "typedef struct { } foo_t, *foo_p" and we end up with + # an AST that is not a tree, but a DAG, with the "type" node of the + # two branches foo_t and foo_p of the trees being the same node. + # It's a bit silly but detecting "DAG-ness" in the AST tree seems + # to be the only way to distinguish this case from two independent + # structs. See test_struct_with_two_usages. + try: + return self._structnode2type[type] + except KeyError: + pass + # + # Note that this must handle parsing "struct foo" any number of + # times and always return the same StructType object. Additionally, + # one of these times (not necessarily the first), the fields of + # the struct can be specified with "struct foo { ...fields... }". + # If no name is given, then we have to create a new anonymous struct + # with no caching; in this case, the fields are either specified + # right now or never. + # + force_name = name + name = type.name + # + # get the type or create it if needed + if name is None: + # 'force_name' is used to guess a more readable name for + # anonymous structs, for the common case "typedef struct { } foo". + if force_name is not None: + explicit_name = '$%s' % force_name + else: + self._anonymous_counter += 1 + explicit_name = '$%d' % self._anonymous_counter + tp = None + else: + explicit_name = name + key = '%s %s' % (kind, name) + tp, _ = self._declarations.get(key, (None, None)) + # + if tp is None: + if kind == 'struct': + tp = model.StructType(explicit_name, None, None, None) + elif kind == 'union': + tp = model.UnionType(explicit_name, None, None, None) + elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") + tp = self._build_enum_type(explicit_name, type.values) + else: + raise AssertionError("kind = %r" % (kind,)) + if name is not None: + self._declare(key, tp) + else: + if kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) + if not tp.forcename: + tp.force_the_name(force_name) + if tp.forcename and '$' in tp.name: + self._declare('anonymous %s' % tp.forcename, tp) + # + self._structnode2type[type] = tp + # + # enums: done here + if kind == 'enum': + return tp + # + # is there a 'type.decls'? If yes, then this is the place in the + # C sources that declare the fields. If no, then just return the + # existing type, possibly still incomplete. + if type.decls is None: + return tp + # + if tp.fldnames is not None: + raise CDefError("duplicate declaration of struct %s" % name) + fldnames = [] + fldtypes = [] + fldbitsize = [] + fldquals = [] + for decl in type.decls: + if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and + ''.join(decl.type.names) == '__dotdotdot__'): + # XXX pycparser is inconsistent: 'names' should be a list + # of strings, but is sometimes just one string. Use + # str.join() as a way to cope with both. + self._make_partial(tp, nested) + continue + if decl.bitsize is None: + bitsize = -1 + else: + bitsize = self._parse_constant(decl.bitsize) + self._partial_length = False + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) + if self._partial_length: + self._make_partial(tp, nested) + if isinstance(type, model.StructType) and type.partial: + self._make_partial(tp, nested) + fldnames.append(decl.name or '') + fldtypes.append(type) + fldbitsize.append(bitsize) + fldquals.append(fqual) + tp.fldnames = tuple(fldnames) + tp.fldtypes = tuple(fldtypes) + tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) + if fldbitsize != [-1] * len(fldbitsize): + if isinstance(tp, model.StructType) and tp.partial: + raise NotImplementedError("%s: using both bitfields and '...;'" + % (tp,)) + tp.packed = self._options.get('packed') + if tp.completed: # must be re-completed: it is not opaque any more + tp.completed = 0 + self._recomplete.append(tp) + return tp + + def _make_partial(self, tp, nested): + if not isinstance(tp, model.StructOrUnion): + raise CDefError("%s cannot be partial" % (tp,)) + if not tp.has_c_name() and not nested: + raise NotImplementedError("%s is partial but has no C name" %(tp,)) + tp.partial = True + + def _parse_constant(self, exprnode, partial_length_ok=False): + # for now, limited to expressions that are an immediate number + # or positive/negative number + if isinstance(exprnode, pycparser.c_ast.Constant): + s = exprnode.value + if '0' <= s[0] <= '9': + s = s.rstrip('uUlL') + try: + if s.startswith('0'): + return int(s, 8) + else: + return int(s, 10) + except ValueError: + if len(s) > 1: + if s.lower()[0:2] == '0x': + return int(s, 16) + elif s.lower()[0:2] == '0b': + return int(s, 2) + raise CDefError("invalid constant %r" % (s,)) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '-'): + return -self._parse_constant(exprnode.expr) + # load previously defined int constant + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name in self._int_constants): + return self._int_constants[exprnode.name] + # + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name == '__dotdotdotarray__'): + if partial_length_ok: + self._partial_length = True + return '...' + raise FFIError(":%d: unsupported '[...]' here, cannot derive " + "the actual array length in this context" + % exprnode.coord.line) + # + if isinstance(exprnode, pycparser.c_ast.BinaryOp): + left = self._parse_constant(exprnode.left) + right = self._parse_constant(exprnode.right) + if exprnode.op == '+': + return left + right + elif exprnode.op == '-': + return left - right + elif exprnode.op == '*': + return left * right + elif exprnode.op == '/': + return self._c_div(left, right) + elif exprnode.op == '%': + return left - self._c_div(left, right) * right + elif exprnode.op == '<<': + return left << right + elif exprnode.op == '>>': + return left >> right + elif exprnode.op == '&': + return left & right + elif exprnode.op == '|': + return left | right + elif exprnode.op == '^': + return left ^ right + # + raise FFIError(":%d: unsupported expression: expected a " + "simple numeric constant" % exprnode.coord.line) + + def _c_div(self, a, b): + result = a // b + if ((a < 0) ^ (b < 0)) and (a % b) != 0: + result += 1 + return result + + def _build_enum_type(self, explicit_name, decls): + if decls is not None: + partial = False + enumerators = [] + enumvalues = [] + nextenumvalue = 0 + for enum in decls.enumerators: + if _r_enum_dotdotdot.match(enum.name): + partial = True + continue + if enum.value is not None: + nextenumvalue = self._parse_constant(enum.value) + enumerators.append(enum.name) + enumvalues.append(nextenumvalue) + self._add_constants(enum.name, nextenumvalue) + nextenumvalue += 1 + enumerators = tuple(enumerators) + enumvalues = tuple(enumvalues) + tp = model.EnumType(explicit_name, enumerators, enumvalues) + tp.partial = partial + else: # opaque enum + tp = model.EnumType(explicit_name, (), ()) + return tp + + def include(self, other): + for name, (tp, quals) in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include + kind = name.split(' ', 1)[0] + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) + for k, v in other._int_constants.items(): + self._add_constants(k, v) + + def _get_unknown_type(self, decl): + typenames = decl.type.type.names + if typenames == ['__dotdotdot__']: + return model.unknown_type(decl.name) + + if typenames == ['__dotdotdotint__']: + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef int... %s'" % decl.name + return model.UnknownIntegerType(decl.name) + + if typenames == ['__dotdotdotfloat__']: + # note: not for 'long double' so far + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef float... %s'" % decl.name + return model.UnknownFloatType(decl.name) + + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) + + def _get_unknown_ptr_type(self, decl): + if decl.type.type.type.names == ['__dotdotdot__']: + return model.unknown_ptr_type(decl.name) + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/error.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/error.py new file mode 100644 index 0000000000000000000000000000000000000000..0a27247c32a381ab7cecedd0f985b781619c1ea5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/error.py @@ -0,0 +1,31 @@ + +class FFIError(Exception): + __module__ = 'cffi' + +class CDefError(Exception): + __module__ = 'cffi' + def __str__(self): + try: + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) + except (AttributeError, TypeError, IndexError): + prefix = '' + return '%s%s' % (prefix, self.args[0]) + +class VerificationError(Exception): + """ An error raised when verification fails + """ + __module__ = 'cffi' + +class VerificationMissing(Exception): + """ An error raised when incomplete structures are passed into + cdef, but no verification has been done + """ + __module__ = 'cffi' + +class PkgConfigError(Exception): + """ An error raised for missing modules in pkg-config + """ + __module__ = 'cffi' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/ffiplatform.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/ffiplatform.py new file mode 100644 index 0000000000000000000000000000000000000000..85313460a69477513c8e00f4df430925f2c4ecc9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/ffiplatform.py @@ -0,0 +1,127 @@ +import sys, os +from .error import VerificationError + + +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + +def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() + from distutils.core import Extension + allsources = [srcfilename] + for src in sources: + allsources.append(os.path.normpath(src)) + return Extension(name=modname, sources=allsources, **kwds) + +def compile(tmpdir, ext, compiler_verbose=0, debug=None): + """Compile a C extension module using distutils.""" + + _hack_at_distutils() + saved_environ = os.environ.copy() + try: + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) + outputfilename = os.path.abspath(outputfilename) + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + return outputfilename + +def _build(tmpdir, ext, compiler_verbose=0, debug=None): + # XXX compact but horrible :-( + from distutils.core import Distribution + import distutils.errors, distutils.log + # + dist = Distribution({'ext_modules': [ext]}) + dist.parse_config_files() + options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) + options['force'] = ('ffiplatform', True) + options['build_lib'] = ('ffiplatform', tmpdir) + options['build_temp'] = ('ffiplatform', tmpdir) + # + try: + old_level = distutils.log.set_threshold(0) or 0 + try: + distutils.log.set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + distutils.log.set_threshold(old_level) + except (distutils.errors.CompileError, + distutils.errors.LinkError) as e: + raise VerificationError('%s: %s' % (e.__class__.__name__, e)) + # + return soname + +try: + from os.path import samefile +except ImportError: + def samefile(f1, f2): + return os.path.abspath(f1) == os.path.abspath(f2) + +def maybe_relative_path(path): + if not os.path.isabs(path): + return path # already relative + dir = path + names = [] + while True: + prevdir = dir + dir, name = os.path.split(prevdir) + if dir == prevdir or not dir: + return path # failed to make it relative + names.append(name) + try: + if samefile(dir, os.curdir): + names.reverse() + return os.path.join(*names) + except OSError: + pass + +# ____________________________________________________________ + +try: + int_or_long = (int, long) + import cStringIO +except NameError: + int_or_long = int # Python 3 + import io as cStringIO + +def _flatten(x, f): + if isinstance(x, str): + f.write('%ds%s' % (len(x), x)) + elif isinstance(x, dict): + keys = sorted(x.keys()) + f.write('%dd' % len(keys)) + for key in keys: + _flatten(key, f) + _flatten(x[key], f) + elif isinstance(x, (list, tuple)): + f.write('%dl' % len(x)) + for value in x: + _flatten(value, f) + elif isinstance(x, int_or_long): + f.write('%di' % (x,)) + else: + raise TypeError( + "the keywords to verify() contains unsupported object %r" % (x,)) + +def flatten(x): + f = cStringIO.StringIO() + _flatten(x, f) + return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/lock.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/lock.py new file mode 100644 index 0000000000000000000000000000000000000000..db91b7158c4ee9aa653462fe38e79ed1b553db87 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/lock.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3,): + try: + from thread import allocate_lock + except ImportError: + from dummy_thread import allocate_lock +else: + try: + from _thread import allocate_lock + except ImportError: + from _dummy_thread import allocate_lock + + +##import sys +##l1 = allocate_lock + +##class allocate_lock(object): +## def __init__(self): +## self._real = l1() +## def __enter__(self): +## for i in range(4, 0, -1): +## print sys._getframe(i).f_code +## print +## return self._real.__enter__() +## def __exit__(self, *args): +## return self._real.__exit__(*args) +## def acquire(self, f): +## assert f is False +## return self._real.acquire(f) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/model.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/model.py new file mode 100644 index 0000000000000000000000000000000000000000..ad1c1764893d0257c0e75eeb61b0a359e89adf0f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/model.py @@ -0,0 +1,617 @@ +import types +import weakref + +from .lock import allocate_lock +from .error import CDefError, VerificationError, VerificationMissing + +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + +class BaseTypeByIdentity(object): + is_array_type = False + is_raw_function = False + + def get_c_name(self, replace_with='', context='a C file', quals=0): + result = self.c_name_with_marker + assert result.count('&') == 1 + # some logic duplication with ffi.getctype()... :-( + replace_with = replace_with.strip() + if replace_with: + if replace_with.startswith('*') and '&[' in result: + replace_with = '(%s)' % replace_with + elif not replace_with[0] in '[(': + replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) + result = result.replace('&', replace_with) + if '$' in result: + raise VerificationError( + "cannot generate '%s' in %s: unknown type name" + % (self._get_c_name(), context)) + return result + + def _get_c_name(self): + return self.c_name_with_marker.replace('&', '') + + def has_c_name(self): + return '$' not in self._get_c_name() + + def is_integer_type(self): + return False + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + try: + BType = ffi._cached_btypes[self] + except KeyError: + BType = self.build_backend_type(ffi, finishlist) + BType2 = ffi._cached_btypes.setdefault(self, BType) + assert BType2 is BType + return BType + + def __repr__(self): + return '<%s>' % (self._get_c_name(),) + + def _get_items(self): + return [(name, getattr(self, name)) for name in self._attrs_] + + +class BaseType(BaseTypeByIdentity): + + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self._get_items() == other._get_items()) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.__class__, tuple(self._get_items()))) + + +class VoidType(BaseType): + _attrs_ = () + + def __init__(self): + self.c_name_with_marker = 'void&' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_void_type') + +void_type = VoidType() + + +class BasePrimitiveType(BaseType): + def is_complex_type(self): + return False + + +class PrimitiveType(BasePrimitiveType): + _attrs_ = ('name',) + + ALL_PRIMITIVE_TYPES = { + 'char': 'c', + 'short': 'i', + 'int': 'i', + 'long': 'i', + 'long long': 'i', + 'signed char': 'i', + 'unsigned char': 'i', + 'unsigned short': 'i', + 'unsigned int': 'i', + 'unsigned long': 'i', + 'unsigned long long': 'i', + 'float': 'f', + 'double': 'f', + 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', + '_Bool': 'i', + # the following types are not primitive in the C sense + 'wchar_t': 'c', + 'char16_t': 'c', + 'char32_t': 'c', + 'int8_t': 'i', + 'uint8_t': 'i', + 'int16_t': 'i', + 'uint16_t': 'i', + 'int32_t': 'i', + 'uint32_t': 'i', + 'int64_t': 'i', + 'uint64_t': 'i', + 'int_least8_t': 'i', + 'uint_least8_t': 'i', + 'int_least16_t': 'i', + 'uint_least16_t': 'i', + 'int_least32_t': 'i', + 'uint_least32_t': 'i', + 'int_least64_t': 'i', + 'uint_least64_t': 'i', + 'int_fast8_t': 'i', + 'uint_fast8_t': 'i', + 'int_fast16_t': 'i', + 'uint_fast16_t': 'i', + 'int_fast32_t': 'i', + 'uint_fast32_t': 'i', + 'int_fast64_t': 'i', + 'uint_fast64_t': 'i', + 'intptr_t': 'i', + 'uintptr_t': 'i', + 'intmax_t': 'i', + 'uintmax_t': 'i', + 'ptrdiff_t': 'i', + 'size_t': 'i', + 'ssize_t': 'i', + } + + def __init__(self, name): + assert name in self.ALL_PRIMITIVE_TYPES + self.name = name + self.c_name_with_marker = name + '&' + + def is_char_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' + def is_integer_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' + def is_float_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_primitive_type', self.name) + + +class UnknownIntegerType(BasePrimitiveType): + _attrs_ = ('name',) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def is_integer_type(self): + return True + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("integer type '%s' can only be used after " + "compilation" % self.name) + +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + + +class BaseFunctionType(BaseType): + _attrs_ = ('args', 'result', 'ellipsis', 'abi') + + def __init__(self, args, result, ellipsis, abi=None): + self.args = args + self.result = result + self.ellipsis = ellipsis + self.abi = abi + # + reprargs = [arg._get_c_name() for arg in self.args] + if self.ellipsis: + reprargs.append('...') + reprargs = reprargs or ['void'] + replace_with = self._base_pattern % (', '.join(reprargs),) + if abi is not None: + replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] + self.c_name_with_marker = ( + self.result.c_name_with_marker.replace('&', replace_with)) + + +class RawFunctionType(BaseFunctionType): + # Corresponds to a C type like 'int(int)', which is the C type of + # a function, but not a pointer-to-function. The backend has no + # notion of such a type; it's used temporarily by parsing. + _base_pattern = '(&)(%s)' + is_raw_function = True + + def build_backend_type(self, ffi, finishlist): + raise CDefError("cannot render the type %r: it is a function " + "type, not a pointer-to-function type" % (self,)) + + def as_function_pointer(self): + return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) + + +class FunctionPtrType(BaseFunctionType): + _base_pattern = '(*&)(%s)' + + def build_backend_type(self, ffi, finishlist): + result = self.result.get_cached_btype(ffi, finishlist) + args = [] + for tp in self.args: + args.append(tp.get_cached_btype(ffi, finishlist)) + abi_args = () + if self.abi == "__stdcall": + if not self.ellipsis: # __stdcall ignored for variadic funcs + try: + abi_args = (ffi._backend.FFI_STDCALL,) + except AttributeError: + pass + return global_cache(self, ffi, 'new_function_type', + tuple(args), result, self.ellipsis, *abi_args) + + def as_raw_function(self): + return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) + + +class PointerType(BaseType): + _attrs_ = ('totype', 'quals') + + def __init__(self, totype, quals=0): + self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + + def build_backend_type(self, ffi, finishlist): + BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) + return global_cache(self, ffi, 'new_pointer_type', BItem) + +voidp_type = PointerType(void_type) + +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) + +const_voidp_type = ConstPointerType(void_type) + + +class NamedPointerType(PointerType): + _attrs_ = ('totype', 'name') + + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) + self.name = name + self.c_name_with_marker = name + '&' + + +class ArrayType(BaseType): + _attrs_ = ('item', 'length') + is_array_type = True + + def __init__(self, item, length): + self.item = item + self.length = length + # + if length is None: + brackets = '&[]' + elif length == '...': + brackets = '&[/*...*/]' + else: + brackets = '&[%s]' % length + self.c_name_with_marker = ( + self.item.c_name_with_marker.replace('&', brackets)) + + def length_is_unknown(self): + return isinstance(self.length, str) + + def resolve_length(self, newlength): + return ArrayType(self.item, newlength) + + def build_backend_type(self, ffi, finishlist): + if self.length_is_unknown(): + raise CDefError("cannot render the type %r: unknown length" % + (self,)) + self.item.get_cached_btype(ffi, finishlist) # force the item BType + BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) + return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) + +char_array_type = ArrayType(PrimitiveType('char'), None) + + +class StructOrUnionOrEnum(BaseTypeByIdentity): + _attrs_ = ('name',) + forcename = None + + def build_c_name_with_marker(self): + name = self.forcename or '%s %s' % (self.kind, self.name) + self.c_name_with_marker = name + '&' + + def force_the_name(self, forcename): + self.forcename = forcename + self.build_c_name_with_marker() + + def get_official_name(self): + assert self.c_name_with_marker.endswith('&') + return self.c_name_with_marker[:-1] + + +class StructOrUnion(StructOrUnionOrEnum): + fixedlayout = None + completed = 0 + partial = False + packed = 0 + + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): + self.name = name + self.fldnames = fldnames + self.fldtypes = fldtypes + self.fldbitsize = fldbitsize + self.fldquals = fldquals + self.build_c_name_with_marker() + + def anonymous_struct_fields(self): + if self.fldtypes is not None: + for name, type in zip(self.fldnames, self.fldtypes): + if name == '' and isinstance(type, StructOrUnion): + yield type + + def enumfields(self, expand_anonymous_struct_union=True): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): + if (name == '' and isinstance(type, StructOrUnion) + and expand_anonymous_struct_union): + # nested anonymous struct/union + for result in type.enumfields(): + yield result + else: + yield (name, type, bitsize, quals) + + def force_flatten(self): + # force the struct or union to have a declaration that lists + # directly all fields returned by enumfields(), flattening + # nested anonymous structs/unions. + names = [] + types = [] + bitsizes = [] + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): + names.append(name) + types.append(type) + bitsizes.append(bitsize) + fldquals.append(quals) + self.fldnames = tuple(names) + self.fldtypes = tuple(types) + self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, + can_delay) + if not can_delay: + self.finish_backend_type(ffi, finishlist) + return BType + + def finish_backend_type(self, ffi, finishlist): + if self.completed: + if self.completed != 2: + raise NotImplementedError("recursive structure declaration " + "for '%s'" % (self.name,)) + return + BType = ffi._cached_btypes[self] + # + self.completed = 1 + # + if self.fldtypes is None: + pass # not completing it: it's an opaque struct + # + elif self.fixedlayout is None: + fldtypes = [tp.get_cached_btype(ffi, finishlist) + for tp in self.fldtypes] + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) + extra_flags = () + if self.packed: + if self.packed == 1: + extra_flags = (8,) # SF_PACKED + else: + extra_flags = (0, self.packed) + ffi._backend.complete_struct_or_union(BType, lst, self, + -1, -1, *extra_flags) + # + else: + fldtypes = [] + fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout + for i in range(len(self.fldnames)): + fsize = fieldsize[i] + ftype = self.fldtypes[i] + # + if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): + # fix the length to match the total size + BItemType = ftype.item.get_cached_btype(ffi, finishlist) + nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) + if nrest != 0: + self._verification_error( + "field '%s.%s' has a bogus size?" % ( + self.name, self.fldnames[i] or '{}')) + ftype = ftype.resolve_length(nlen) + self.fldtypes = (self.fldtypes[:i] + (ftype,) + + self.fldtypes[i+1:]) + # + BFieldType = ftype.get_cached_btype(ffi, finishlist) + if isinstance(ftype, ArrayType) and ftype.length is None: + assert fsize == 0 + else: + bitemsize = ffi.sizeof(BFieldType) + if bitemsize != fsize: + self._verification_error( + "field '%s.%s' is declared as %d bytes, but is " + "really %d bytes" % (self.name, + self.fldnames[i] or '{}', + bitemsize, fsize)) + fldtypes.append(BFieldType) + # + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) + ffi._backend.complete_struct_or_union(BType, lst, self, + totalsize, totalalignment) + self.completed = 2 + + def _verification_error(self, msg): + raise VerificationError(msg) + + def check_not_partial(self): + if self.partial and self.fixedlayout is None: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + finishlist.append(self) + # + return global_cache(self, ffi, 'new_%s_type' % self.kind, + self.get_official_name(), key=self) + + +class StructType(StructOrUnion): + kind = 'struct' + + +class UnionType(StructOrUnion): + kind = 'union' + + +class EnumType(StructOrUnionOrEnum): + kind = 'enum' + partial = False + partial_resolved = False + + def __init__(self, name, enumerators, enumvalues, baseinttype=None): + self.name = name + self.enumerators = enumerators + self.enumvalues = enumvalues + self.baseinttype = baseinttype + self.build_c_name_with_marker() + + def force_the_name(self, forcename): + StructOrUnionOrEnum.force_the_name(self, forcename) + if self.forcename is None: + name = self.get_official_name() + self.forcename = '$' + name.replace(' ', '_') + + def check_not_partial(self): + if self.partial and not self.partial_resolved: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + base_btype = self.build_baseinttype(ffi, finishlist) + return global_cache(self, ffi, 'new_enum_type', + self.get_official_name(), + self.enumerators, self.enumvalues, + base_btype, key=self) + + def build_baseinttype(self, ffi, finishlist): + if self.baseinttype is not None: + return self.baseinttype.get_cached_btype(ffi, finishlist) + # + if self.enumvalues: + smallest_value = min(self.enumvalues) + largest_value = max(self.enumvalues) + else: + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 + if smallest_value < 0: # needs a signed type + sign = 1 + candidate1 = PrimitiveType("int") + candidate2 = PrimitiveType("long") + else: + sign = 0 + candidate1 = PrimitiveType("unsigned int") + candidate2 = PrimitiveType("unsigned long") + btype1 = candidate1.get_cached_btype(ffi, finishlist) + btype2 = candidate2.get_cached_btype(ffi, finishlist) + size1 = ffi.sizeof(btype1) + size2 = ffi.sizeof(btype2) + if (smallest_value >= ((-1) << (8*size1-1)) and + largest_value < (1 << (8*size1-sign))): + return btype1 + if (smallest_value >= ((-1) << (8*size2-1)) and + largest_value < (1 << (8*size2-sign))): + return btype2 + raise CDefError("%s values don't all fit into either 'long' " + "or 'unsigned long'" % self._get_c_name()) + +def unknown_type(name, structname=None): + if structname is None: + structname = '$%s' % name + tp = StructType(structname, None, None, None) + tp.force_the_name(name) + tp.origin = "unknown_type" + return tp + +def unknown_ptr_type(name, structname=None): + if structname is None: + structname = '$$%s' % name + tp = StructType(structname, None, None, None) + return NamedPointerType(tp, name) + + +global_lock = allocate_lock() +_typecache_cffi_backend = weakref.WeakValueDictionary() + +def get_typecache(backend): + # returns _typecache_cffi_backend if backend is the _cffi_backend + # module, or type(backend).__typecache if backend is an instance of + # CTypesBackend (or some FakeBackend class during tests) + if isinstance(backend, types.ModuleType): + return _typecache_cffi_backend + with global_lock: + if not hasattr(type(backend), '__typecache'): + type(backend).__typecache = weakref.WeakValueDictionary() + return type(backend).__typecache + +def global_cache(srctype, ffi, funcname, *args, **kwds): + key = kwds.pop('key', (funcname, args)) + assert not kwds + try: + return ffi._typecache[key] + except KeyError: + pass + try: + res = getattr(ffi._backend, funcname)(*args) + except NotImplementedError as e: + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) + # note that setdefault() on WeakValueDictionary is not atomic + # and contains a rare bug (http://bugs.python.org/issue19542); + # we have to use a lock and do it ourselves + cache = ffi._typecache + with global_lock: + res1 = cache.get(key) + if res1 is None: + cache[key] = res + return res + else: + return res1 + +def pointer_cache(ffi, BType): + return global_cache('?', ffi, 'new_pointer_type', BType) + +def attach_exception_info(e, name): + if e.args and type(e.args[0]) is str: + e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/parse_c_type.h b/Latest_Group_Project/.venv/Lib/site-packages/cffi/parse_c_type.h new file mode 100644 index 0000000000000000000000000000000000000000..84e4ef85659eb63e6453d8af9f024f1866182342 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/parse_c_type.h @@ -0,0 +1,181 @@ + +/* This part is from file 'cffi/parse_c_type.h'. It is copied at the + beginning of C sources generated by CFFI's ffi.set_source(). */ + +typedef void *_cffi_opcode_t; + +#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) +#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) +#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) + +#define _CFFI_OP_PRIMITIVE 1 +#define _CFFI_OP_POINTER 3 +#define _CFFI_OP_ARRAY 5 +#define _CFFI_OP_OPEN_ARRAY 7 +#define _CFFI_OP_STRUCT_UNION 9 +#define _CFFI_OP_ENUM 11 +#define _CFFI_OP_FUNCTION 13 +#define _CFFI_OP_FUNCTION_END 15 +#define _CFFI_OP_NOOP 17 +#define _CFFI_OP_BITFIELD 19 +#define _CFFI_OP_TYPENAME 21 +#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs +#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs +#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN_FUNC 35 +#define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 +#define _CFFI_OP_EXTERN_PYTHON 41 + +#define _CFFI_PRIM_VOID 0 +#define _CFFI_PRIM_BOOL 1 +#define _CFFI_PRIM_CHAR 2 +#define _CFFI_PRIM_SCHAR 3 +#define _CFFI_PRIM_UCHAR 4 +#define _CFFI_PRIM_SHORT 5 +#define _CFFI_PRIM_USHORT 6 +#define _CFFI_PRIM_INT 7 +#define _CFFI_PRIM_UINT 8 +#define _CFFI_PRIM_LONG 9 +#define _CFFI_PRIM_ULONG 10 +#define _CFFI_PRIM_LONGLONG 11 +#define _CFFI_PRIM_ULONGLONG 12 +#define _CFFI_PRIM_FLOAT 13 +#define _CFFI_PRIM_DOUBLE 14 +#define _CFFI_PRIM_LONGDOUBLE 15 + +#define _CFFI_PRIM_WCHAR 16 +#define _CFFI_PRIM_INT8 17 +#define _CFFI_PRIM_UINT8 18 +#define _CFFI_PRIM_INT16 19 +#define _CFFI_PRIM_UINT16 20 +#define _CFFI_PRIM_INT32 21 +#define _CFFI_PRIM_UINT32 22 +#define _CFFI_PRIM_INT64 23 +#define _CFFI_PRIM_UINT64 24 +#define _CFFI_PRIM_INTPTR 25 +#define _CFFI_PRIM_UINTPTR 26 +#define _CFFI_PRIM_PTRDIFF 27 +#define _CFFI_PRIM_SIZE 28 +#define _CFFI_PRIM_SSIZE 29 +#define _CFFI_PRIM_INT_LEAST8 30 +#define _CFFI_PRIM_UINT_LEAST8 31 +#define _CFFI_PRIM_INT_LEAST16 32 +#define _CFFI_PRIM_UINT_LEAST16 33 +#define _CFFI_PRIM_INT_LEAST32 34 +#define _CFFI_PRIM_UINT_LEAST32 35 +#define _CFFI_PRIM_INT_LEAST64 36 +#define _CFFI_PRIM_UINT_LEAST64 37 +#define _CFFI_PRIM_INT_FAST8 38 +#define _CFFI_PRIM_UINT_FAST8 39 +#define _CFFI_PRIM_INT_FAST16 40 +#define _CFFI_PRIM_UINT_FAST16 41 +#define _CFFI_PRIM_INT_FAST32 42 +#define _CFFI_PRIM_UINT_FAST32 43 +#define _CFFI_PRIM_INT_FAST64 44 +#define _CFFI_PRIM_UINT_FAST64 45 +#define _CFFI_PRIM_INTMAX 46 +#define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 +#define _CFFI_PRIM_CHAR16 50 +#define _CFFI_PRIM_CHAR32 51 + +#define _CFFI__NUM_PRIM 52 +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) + +#define _CFFI__IO_FILE_STRUCT (-1) + + +struct _cffi_global_s { + const char *name; + void *address; + _cffi_opcode_t type_op; + void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown + // OP_CPYTHON_BLTN_*: addr of direct function +}; + +struct _cffi_getconst_s { + unsigned long long value; + const struct _cffi_type_context_s *ctx; + int gindex; +}; + +struct _cffi_struct_union_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // _CFFI_F_* flags below + size_t size; + int alignment; + int first_field_index; // -> _cffi_fields array + int num_fields; +}; +#define _CFFI_F_UNION 0x01 // is a union, not a struct +#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the + // "standard layout" or if some are missing +#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct +#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() +#define _CFFI_F_OPAQUE 0x10 // opaque + +struct _cffi_field_s { + const char *name; + size_t field_offset; + size_t field_size; + _cffi_opcode_t field_type_op; +}; + +struct _cffi_enum_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_ENUM + int type_prim; // _CFFI_PRIM_xxx + const char *enumerators; // comma-delimited string +}; + +struct _cffi_typename_s { + const char *name; + int type_index; /* if opaque, points to a possibly artificial + OP_STRUCT which is itself opaque */ +}; + +struct _cffi_type_context_s { + _cffi_opcode_t *types; + const struct _cffi_global_s *globals; + const struct _cffi_field_s *fields; + const struct _cffi_struct_union_s *struct_unions; + const struct _cffi_enum_s *enums; + const struct _cffi_typename_s *typenames; + int num_globals; + int num_struct_unions; + int num_enums; + int num_typenames; + const char *const *includes; + int num_types; + int flags; /* future extension */ +}; + +struct _cffi_parse_info_s { + const struct _cffi_type_context_s *ctx; + _cffi_opcode_t *output; + unsigned int output_size; + size_t error_location; + const char *error_message; +}; + +struct _cffi_externpy_s { + const char *name; + size_t size_of_result; + void *reserved1, *reserved2; +}; + +#ifdef _CFFI_INTERNAL +static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); +static int search_in_globals(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +#endif diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/pkgconfig.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/pkgconfig.py new file mode 100644 index 0000000000000000000000000000000000000000..5c93f15a60e6f904b2dd108d6e22044a5890bcb4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/pkgconfig.py @@ -0,0 +1,121 @@ +# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi +import sys, os, subprocess + +from .error import PkgConfigError + + +def merge_flags(cfg1, cfg2): + """Merge values from cffi config flags cfg2 to cf1 + + Example: + merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) + {"libraries": ["one", "two"]} + """ + for key, value in cfg2.items(): + if key not in cfg1: + cfg1[key] = value + else: + if not isinstance(cfg1[key], list): + raise TypeError("cfg1[%r] should be a list of strings" % (key,)) + if not isinstance(value, list): + raise TypeError("cfg2[%r] should be a list of strings" % (key,)) + cfg1[key].extend(value) + return cfg1 + + +def call(libname, flag, encoding=sys.getfilesystemencoding()): + """Calls pkg-config and returns the output if found + """ + a = ["pkg-config", "--print-errors"] + a.append(flag) + a.append(libname) + try: + pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError as e: + raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) + + bout, berr = pc.communicate() + if pc.returncode != 0: + try: + berr = berr.decode(encoding) + except Exception: + pass + raise PkgConfigError(berr.strip()) + + if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x + try: + bout = bout.decode(encoding) + except UnicodeDecodeError: + raise PkgConfigError("pkg-config %s %s returned bytes that cannot " + "be decoded with encoding %r:\n%r" % + (flag, libname, encoding, bout)) + + if os.altsep != '\\' and '\\' in bout: + raise PkgConfigError("pkg-config %s %s returned an unsupported " + "backslash-escaped output:\n%r" % + (flag, libname, bout)) + return bout + + +def flags_from_pkgconfig(libs): + r"""Return compiler line flags for FFI.set_source based on pkg-config output + + Usage + ... + ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) + + If pkg-config is installed on build machine, then arguments include_dirs, + library_dirs, libraries, define_macros, extra_compile_args and + extra_link_args are extended with an output of pkg-config for libfoo and + libbar. + + Raises PkgConfigError in case the pkg-config call fails. + """ + + def get_include_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-I")] + + def get_library_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-L")] + + def get_libraries(string): + return [x[2:] for x in string.split() if x.startswith("-l")] + + # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils + def get_macros(string): + def _macro(x): + x = x[2:] # drop "-D" + if '=' in x: + return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") + else: + return (x, None) # "-Dfoo" => ("foo", None) + return [_macro(x) for x in string.split() if x.startswith("-D")] + + def get_other_cflags(string): + return [x for x in string.split() if not x.startswith("-I") and + not x.startswith("-D")] + + def get_other_libs(string): + return [x for x in string.split() if not x.startswith("-L") and + not x.startswith("-l")] + + # return kwargs for given libname + def kwargs(libname): + fse = sys.getfilesystemencoding() + all_cflags = call(libname, "--cflags") + all_libs = call(libname, "--libs") + return { + "include_dirs": get_include_dirs(all_cflags), + "library_dirs": get_library_dirs(all_libs), + "libraries": get_libraries(all_libs), + "define_macros": get_macros(all_cflags), + "extra_compile_args": get_other_cflags(all_cflags), + "extra_link_args": get_other_libs(all_libs), + } + + # merge all arguments together + ret = {} + for libname in libs: + lib_flags = kwargs(libname) + merge_flags(ret, lib_flags) + return ret diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/recompiler.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/recompiler.py new file mode 100644 index 0000000000000000000000000000000000000000..5d9d32d7132027562c5a29405d625899611bc977 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/recompiler.py @@ -0,0 +1,1581 @@ +import os, sys, io +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) + + +class GlobalExpr: + def __init__(self, name, address, type_op, size=0, check_value=0): + self.name = name + self.address = address + self.type_op = type_op + self.size = size + self.check_value = check_value + + def as_c_expr(self): + return ' { "%s", (void *)%s, %s, (void *)%s },' % ( + self.name, self.address, self.type_op.as_c_expr(), self.size) + + def as_python_expr(self): + return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, + self.check_value) + +class FieldExpr: + def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): + self.name = name + self.field_offset = field_offset + self.field_size = field_size + self.fbitsize = fbitsize + self.field_type_op = field_type_op + + def as_c_expr(self): + spaces = " " * len(self.name) + return (' { "%s", %s,\n' % (self.name, self.field_offset) + + ' %s %s,\n' % (spaces, self.field_size) + + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) + + def as_python_expr(self): + raise NotImplementedError + + def as_field_python_expr(self): + if self.field_type_op.op == OP_NOOP: + size_expr = '' + elif self.field_type_op.op == OP_BITFIELD: + size_expr = format_four_bytes(self.fbitsize) + else: + raise NotImplementedError + return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), + size_expr, + self.name) + +class StructUnionExpr: + def __init__(self, name, type_index, flags, size, alignment, comment, + first_field_index, c_fields): + self.name = name + self.type_index = type_index + self.flags = flags + self.size = size + self.alignment = alignment + self.comment = comment + self.first_field_index = first_field_index + self.c_fields = c_fields + + def as_c_expr(self): + return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + + '\n %s, %s, ' % (self.size, self.alignment) + + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + + ('/* %s */ ' % self.comment if self.comment else '') + + '},') + + def as_python_expr(self): + flags = eval(self.flags, G_FLAGS) + fields_expr = [c_field.as_field_python_expr() + for c_field in self.c_fields] + return "(b'%s%s%s',%s)" % ( + format_four_bytes(self.type_index), + format_four_bytes(flags), + self.name, + ','.join(fields_expr)) + +class EnumExpr: + def __init__(self, name, type_index, size, signed, allenums): + self.name = name + self.type_index = type_index + self.size = size + self.signed = signed + self.allenums = allenums + + def as_c_expr(self): + return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' + ' "%s" },' % (self.name, self.type_index, + self.size, self.signed, self.allenums)) + + def as_python_expr(self): + prim_index = { + (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, + (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, + (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, + (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, + }[self.size, self.signed] + return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), + format_four_bytes(prim_index), + self.name, self.allenums) + +class TypenameExpr: + def __init__(self, name, type_index): + self.name = name + self.type_index = type_index + + def as_c_expr(self): + return ' { "%s", %d },' % (self.name, self.type_index) + + def as_python_expr(self): + return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) + + +# ____________________________________________________________ + + +class Recompiler: + _num_externpy = 0 + + def __init__(self, ffi, module_name, target_is_python=False): + self.ffi = ffi + self.module_name = module_name + self.target_is_python = target_is_python + self._version = VERSION_BASE + + def needs_version(self, ver): + self._version = max(self._version, ver) + + def collect_type_table(self): + self._typesdict = {} + self._generate("collecttype") + # + all_decls = sorted(self._typesdict, key=str) + # + # prepare all FUNCTION bytecode sequences first + self.cffi_types = [] + for tp in all_decls: + if tp.is_raw_function: + assert self._typesdict[tp] is None + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + for tp1 in tp.args: + assert isinstance(tp1, (model.VoidType, + model.BasePrimitiveType, + model.PointerType, + model.StructOrUnionOrEnum, + model.FunctionPtrType)) + if self._typesdict[tp1] is None: + self._typesdict[tp1] = len(self.cffi_types) + self.cffi_types.append(tp1) # placeholder + self.cffi_types.append('END') # placeholder + # + # prepare all OTHER bytecode sequences + for tp in all_decls: + if not tp.is_raw_function and self._typesdict[tp] is None: + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + if tp.is_array_type and tp.length is not None: + self.cffi_types.append('LEN') # placeholder + assert None not in self._typesdict.values() + # + # collect all structs and unions and enums + self._struct_unions = {} + self._enums = {} + for tp in all_decls: + if isinstance(tp, model.StructOrUnion): + self._struct_unions[tp] = None + elif isinstance(tp, model.EnumType): + self._enums[tp] = None + for i, tp in enumerate(sorted(self._struct_unions, + key=lambda tp: tp.name)): + self._struct_unions[tp] = i + for i, tp in enumerate(sorted(self._enums, + key=lambda tp: tp.name)): + self._enums[tp] = i + # + # emit all bytecode sequences now + for tp in all_decls: + method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) + method(tp, self._typesdict[tp]) + # + # consistency check + for op in self.cffi_types: + assert isinstance(op, CffiOp) + self.cffi_types = tuple(self.cffi_types) # don't change any more + + def _enum_fields(self, tp): + # When producing C, expand all anonymous struct/union fields. + # That's necessary to have C code checking the offsets of the + # individual fields contained in them. When producing Python, + # don't do it and instead write it like it is, with the + # corresponding fields having an empty name. Empty names are + # recognized at runtime when we import the generated Python + # file. + expand_anonymous_struct_union = not self.target_is_python + return tp.enumfields(expand_anonymous_struct_union) + + def _do_collect_type(self, tp): + if not isinstance(tp, model.BaseTypeByIdentity): + if isinstance(tp, tuple): + for x in tp: + self._do_collect_type(x) + return + if tp not in self._typesdict: + self._typesdict[tp] = None + if isinstance(tp, model.FunctionPtrType): + self._do_collect_type(tp.as_raw_function()) + elif isinstance(tp, model.StructOrUnion): + if tp.fldtypes is not None and ( + tp not in self.ffi._parser._included_declarations): + for name1, tp1, _, _ in self._enum_fields(tp): + self._do_collect_type(self._field_type(tp, name1, tp1)) + else: + for _, x in tp._get_items(): + self._do_collect_type(x) + + def _generate(self, step_name): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in recompile(): %r" % name) + try: + self._current_quals = quals + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + # ---------- + + ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] + + def collect_step_tables(self): + # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. + self._lsts = {} + for step_name in self.ALL_STEPS: + self._lsts[step_name] = [] + self._seen_struct_unions = set() + self._generate("ctx") + self._add_missing_struct_unions() + # + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if step_name != "field": + lst.sort(key=lambda entry: entry.name) + self._lsts[step_name] = tuple(lst) # don't change any more + # + # check for a possible internal inconsistency: _cffi_struct_unions + # should have been generated with exactly self._struct_unions + lst = self._lsts["struct_union"] + for tp, i in self._struct_unions.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._struct_unions) + # same with enums + lst = self._lsts["enum"] + for tp, i in self._enums.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._enums) + + # ---------- + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self, f, preamble): + if self.target_is_python: + assert preamble is None + self.write_py_source_to_f(f) + else: + assert preamble is not None + self.write_c_source_to_f(f, preamble) + + def _rel_readlines(self, filename): + g = open(os.path.join(os.path.dirname(__file__), filename), 'r') + lines = g.readlines() + g.close() + return lines + + def write_c_source_to_f(self, f, preamble): + self._f = f + prnt = self._prnt + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') + if not USE_LIMITED_API: + prnt('#define _CFFI_NO_LIMITED_API') + # + # first the '#include' (actually done by inlining the file's content) + lines = self._rel_readlines('_cffi_include.h') + i = lines.index('#include "parse_c_type.h"\n') + lines[i:i+1] = self._rel_readlines('parse_c_type.h') + prnt(''.join(lines)) + # + # if we have ffi._embedding != None, we give it here as a macro + # and include an extra file + base_module_name = self.module_name.split('.')[-1] + if self.ffi._embedding is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) + prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') + self._print_string_literal_in_array(self.ffi._embedding) + prnt('0 };') + prnt('#ifdef PYPY_VERSION') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( + base_module_name,)) + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( + base_module_name,)) + prnt('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( + base_module_name,)) + prnt('#endif') + lines = self._rel_readlines('_embedding.h') + i = lines.index('#include "_cffi_errors.h"\n') + lines[i:i+1] = self._rel_readlines('_cffi_errors.h') + prnt(''.join(lines)) + self.needs_version(VERSION_EMBEDDED) + # + # then paste the C source given by the user, verbatim. + prnt('/************************************************************/') + prnt() + prnt(preamble) + prnt() + prnt('/************************************************************/') + prnt() + # + # the declaration of '_cffi_types' + prnt('static void *_cffi_types[] = {') + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + for i, op in enumerate(self.cffi_types): + comment = '' + if i in typeindex2type: + comment = ' // ' + typeindex2type[i]._get_c_name() + prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) + if not self.cffi_types: + prnt(' 0') + prnt('};') + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._seen_constants = set() + self._generate("decl") + # + # the declaration of '_cffi_globals' and '_cffi_typenames' + nums = {} + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + nums[step_name] = len(lst) + if nums[step_name] > 0: + prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( + step_name, step_name)) + for entry in lst: + prnt(entry.as_c_expr()) + prnt('};') + prnt() + # + # the declaration of '_cffi_includes' + if self.ffi._included_ffis: + prnt('static const char * const _cffi_includes[] = {') + for ffi_to_include in self.ffi._included_ffis: + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is None: + raise VerificationError( + "not implemented yet: ffi.include() of a Python-based " + "ffi inside a C-based ffi") + prnt(' "%s",' % (included_module_name,)) + prnt(' NULL') + prnt('};') + prnt() + # + # the declaration of '_cffi_type_context' + prnt('static const struct _cffi_type_context_s _cffi_type_context = {') + prnt(' _cffi_types,') + for step_name in self.ALL_STEPS: + if nums[step_name] > 0: + prnt(' _cffi_%ss,' % step_name) + else: + prnt(' NULL, /* no %ss */' % step_name) + for step_name in self.ALL_STEPS: + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if self.ffi._included_ffis: + prnt(' _cffi_includes,') + else: + prnt(' NULL, /* no includes */') + prnt(' %d, /* num_types */' % (len(self.cffi_types),)) + flags = 0 + if self._num_externpy > 0 or self.ffi._embedding is not None: + flags |= 1 # set to mean that we use extern "Python" + prnt(' %d, /* flags */' % flags) + prnt('};') + prnt() + # + # the init function + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') + prnt('#endif') + prnt() + prnt('#ifdef PYPY_VERSION') + prnt('PyMODINIT_FUNC') + prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) + prnt('{') + if flags & 1: + prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') + prnt(' _cffi_call_python_org = ' + '(void(*)(struct _cffi_externpy_s *, char *))p[1];') + prnt(' }') + prnt(' p[0] = (const void *)0x%x;' % self._version) + prnt(' p[1] = &_cffi_type_context;') + prnt('#if PY_MAJOR_VERSION >= 3') + prnt(' return NULL;') + prnt('#endif') + prnt('}') + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + prnt('# ifdef _MSC_VER') + prnt(' PyMODINIT_FUNC') + prnt('# if PY_MAJOR_VERSION >= 3') + prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# else') + prnt(' init%s(void) { }' % (base_module_name,)) + prnt('# endif') + prnt('# endif') + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % (base_module_name,)) + prnt('{') + prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#else') + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % (base_module_name,)) + prnt('{') + prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#endif') + prnt() + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility pop') + prnt('#endif') + self._version = None + + def _to_py(self, x): + if isinstance(x, str): + return "b'%s'" % (x,) + if isinstance(x, (list, tuple)): + rep = [self._to_py(item) for item in x] + if len(rep) == 1: + rep.append('') + return "(%s)" % (','.join(rep),) + return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. + + def write_py_source_to_f(self, f): + self._f = f + prnt = self._prnt + # + # header + prnt("# auto-generated file") + prnt("import _cffi_backend") + # + # the 'import' of the included ffis + num_includes = len(self.ffi._included_ffis or ()) + for i in range(num_includes): + ffi_to_include = self.ffi._included_ffis[i] + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is not None: + raise VerificationError( + "not implemented yet: ffi.include() of a C-based " + "ffi inside a Python-based ffi") + prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) + prnt() + prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) + prnt(" _version = 0x%x," % (self._version,)) + self._version = None + # + # the '_types' keyword argument + self.cffi_types = tuple(self.cffi_types) # don't change any more + types_lst = [op.as_python_bytes() for op in self.cffi_types] + prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + # + # the keyword arguments from ALL_STEPS + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if len(lst) > 0 and step_name != "field": + prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) + # + # the '_includes' keyword argument + if num_includes > 0: + prnt(' _includes = (%s,),' % ( + ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) + # + # the footer + prnt(')') + + # ---------- + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) + else: + cname = tp.get_c_name('') + converter = '(%s)_cffi_to_c_%s' % (cname, + tp.name.replace(' ', '_')) + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + '(%s)alloca((size_t)datasize) : NULL;' % ( + tovar, tp.get_c_name(''))) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.BasePrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) + elif tp.name != 'long double' and not tp.is_complex_type(): + cname = tp.name.replace(' ', '_') + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + return '_cffi_from_c_%s(%s)' % (cname, var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs + + def _typedef_type(self, tp, name): + return self._global_type(tp, "(*(%s *)0)" % (name,)) + + def _generate_cpy_typedef_collecttype(self, tp, name): + self._do_collect_type(self._typedef_type(tp, name)) + + def _generate_cpy_typedef_decl(self, tp, name): + pass + + def _typedef_ctx(self, tp, name): + type_index = self._typesdict[tp] + self._lsts["typename"].append(TypenameExpr(name, type_index)) + + def _generate_cpy_typedef_ctx(self, tp, name): + tp = self._typedef_type(tp, name) + self._typedef_ctx(tp, name) + if getattr(tp, "origin", None) == "unknown_type": + self._struct_ctx(tp, tp.name, approxname=None) + elif isinstance(tp, model.NamedPointerType): + self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, + named_ptr=tp) + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + self._do_collect_type(tp.as_raw_function()) + if tp.ellipsis and not self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_function_decl(self, tp, name): + assert not self.target_is_python + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_constant_decl(tp, name) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + # + # ------------------------------ + # the 'd' version of the function, only for addressof(lib, 'func') + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arguments.append(type.get_c_name(' x%d' % i, context)) + call_arguments.append('x%d' % i) + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) + prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) + prnt('{') + call_arguments = ', '.join(call_arguments) + result_code = 'return ' + if isinstance(tp.result, model.VoidType): + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, call_arguments)) + prnt('}') + # + prnt('#ifndef PYPY_VERSION') # ------------------------------ + # + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' x%d' % i, context) + prnt(' %s;' % arg) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + result_decl = ' %s;' % tp.result.get_c_name(' result', context) + prnt(result_decl) + prnt(' PyObject *pyresult;') + else: + result_decl = None + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( + name, len(rng), len(rng), + ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + call_arguments = ['x%d' % i for i in range(len(tp.args))] + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + # + prnt('#else') # ------------------------------ + # + # the PyPy version: need to replace struct/union arguments with + # pointers, and if the result is a struct/union, insert a first + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) + difference = False + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + indirection = '' + if need_indirection(type): + indirection = '*' + difference = True + arg = type.get_c_name(' %sx%d' % (indirection, i), context) + arguments.append(arg) + call_arguments.append('%sx%d' % (indirection, i)) + tp_result = tp.result + if need_indirection(tp_result): + context = 'result of %s' % name + arg = tp_result.get_c_name(' *result', context) + arguments.insert(0, arg) + tp_result = model.void_type + result_decl = None + result_code = '*result = ' + difference = True + if difference: + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, + repr_arguments) + prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) + prnt('{') + if result_decl: + prnt(result_decl) + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + if result_decl: + prnt(' return result;') + prnt('}') + else: + prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) + # + prnt('#endif') # ------------------------------ + prnt() + + def _generate_cpy_function_ctx(self, tp, name): + if tp.ellipsis and not self.target_is_python: + self._generate_cpy_constant_ctx(tp, name) + return + type_index = self._typesdict[tp.as_raw_function()] + numargs = len(tp.args) + if self.target_is_python: + meth_kind = OP_DLOPEN_FUNC + elif numargs == 0: + meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' + elif numargs == 1: + meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' + else: + meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' + self._lsts["global"].append( + GlobalExpr(name, '_cffi_f_%s' % name, + CffiOp(meth_kind, type_index), + size='_cffi_d_%s' % name)) + + # ---------- + # named structs or unions + + def _field_type(self, tp_struct, field_name, tp_field): + if isinstance(tp_field, model.ArrayType): + actual_length = tp_field.length + if actual_length == '...': + ptr_struct_name = tp_struct.get_c_name('*') + actual_length = '_cffi_array_len(((%s)0)->%s)' % ( + ptr_struct_name, field_name) + tp_item = self._field_type(tp_struct, '%s[0]' % field_name, + tp_field.item) + tp_field = model.ArrayType(tp_item, actual_length) + return tp_field + + def _struct_collecttype(self, tp): + self._do_collect_type(tp) + if self.target_is_python: + # also requires nested anon struct/unions in ABI mode, recursively + for fldtype in tp.anonymous_struct_fields(): + self._struct_collecttype(fldtype) + + def _struct_decl(self, tp, cname, approxname): + if tp.fldtypes is None: + return + prnt = self._prnt + checkfuncname = '_cffi_checkfld_%s' % (approxname,) + prnt('_CFFI_UNUSED_FN') + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in self._enum_fields(tp): + try: + if ftype.is_integer_type() or fbitsize >= 0: + # accept all integers, but complain on float or double + if fname != '': + prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) + continue + # only accept exactly the type declared, except that '[]' + # is interpreted as a '*' and so will match any array length. + # (It would also match '*', but that's harder to detect...) + while (isinstance(ftype, model.ArrayType) + and (ftype.length is None or ftype.length == '...')): + ftype = ftype.item + fname = fname + '[0]' + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) + prnt() + + def _struct_ctx(self, tp, cname, approxname, named_ptr=None): + type_index = self._typesdict[tp] + reason_for_not_expanding = None + flags = [] + if isinstance(tp, model.UnionType): + flags.append("_CFFI_F_UNION") + if tp.fldtypes is None: + flags.append("_CFFI_F_OPAQUE") + reason_for_not_expanding = "opaque" + if (tp not in self.ffi._parser._included_declarations and + (named_ptr is None or + named_ptr not in self.ffi._parser._included_declarations)): + if tp.fldtypes is None: + pass # opaque + elif tp.partial or any(tp.anonymous_struct_fields()): + pass # field layout obtained silently from the C compiler + else: + flags.append("_CFFI_F_CHECK_FIELDS") + if tp.packed: + if tp.packed > 1: + raise NotImplementedError( + "%r is declared with 'pack=%r'; only 0 or 1 are " + "supported in API mode (try to use \"...;\", which " + "does not require a 'pack' declaration)" % + (tp, tp.packed)) + flags.append("_CFFI_F_PACKED") + else: + flags.append("_CFFI_F_EXTERNAL") + reason_for_not_expanding = "external" + flags = '|'.join(flags) or '0' + c_fields = [] + if reason_for_not_expanding is None: + enumfields = list(self._enum_fields(tp)) + for fldname, fldtype, fbitsize, fqual in enumfields: + fldtype = self._field_type(tp, fldname, fldtype) + self._check_not_opaque(fldtype, + "field '%s.%s'" % (tp.name, fldname)) + # cname is None for _add_missing_struct_unions() only + op = OP_NOOP + if fbitsize >= 0: + op = OP_BITFIELD + size = '%d /* bits */' % fbitsize + elif cname is None or ( + isinstance(fldtype, model.ArrayType) and + fldtype.length is None): + size = '(size_t)-1' + else: + size = 'sizeof(((%s)0)->%s)' % ( + tp.get_c_name('*') if named_ptr is None + else named_ptr.name, + fldname) + if cname is None or fbitsize >= 0: + offset = '(size_t)-1' + elif named_ptr is not None: + offset = '((char *)&((%s)0)->%s) - (char *)0' % ( + named_ptr.name, fldname) + else: + offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) + c_fields.append( + FieldExpr(fldname, offset, size, fbitsize, + CffiOp(op, self._typesdict[fldtype]))) + first_field_index = len(self._lsts["field"]) + self._lsts["field"].extend(c_fields) + # + if cname is None: # unknown name, for _add_missing_struct_unions + size = '(size_t)-2' + align = -2 + comment = "unnamed" + else: + if named_ptr is not None: + size = 'sizeof(*(%s)0)' % (named_ptr.name,) + align = '-1 /* unknown alignment */' + else: + size = 'sizeof(%s)' % (cname,) + align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) + comment = None + else: + size = '(size_t)-1' + align = -1 + first_field_index = -1 + comment = reason_for_not_expanding + self._lsts["struct_union"].append( + StructUnionExpr(tp.name, type_index, flags, size, align, comment, + first_field_index, c_fields)) + self._seen_struct_unions.add(tp) + + def _check_not_opaque(self, tp, location): + while isinstance(tp, model.ArrayType): + tp = tp.item + if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: + raise TypeError( + "%s is of an opaque type (not declared in cdef())" % location) + + def _add_missing_struct_unions(self): + # not very nice, but some struct declarations might be missing + # because they don't have any known C name. Check that they are + # not partial (we can't complete or verify them!) and emit them + # anonymously. + lst = list(self._struct_unions.items()) + lst.sort(key=lambda tp_order: tp_order[1]) + for tp, order in lst: + if tp not in self._seen_struct_unions: + if tp.partial: + raise NotImplementedError("internal inconsistency: %r is " + "partial but was not seen at " + "this point" % (tp,)) + if tp.name.startswith('$') and tp.name[1:].isdigit(): + approxname = tp.name[1:] + elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': + approxname = 'FILE' + self._typedef_ctx(tp, 'FILE') + else: + raise NotImplementedError("internal inconsistency: %r" % + (tp,)) + self._struct_ctx(tp, None, approxname) + + def _generate_cpy_struct_collecttype(self, tp, name): + self._struct_collecttype(tp) + _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype + + def _struct_names(self, tp): + cname = tp.get_c_name('') + if ' ' in cname: + return cname, cname.replace(' ', '_') + else: + return cname, '_' + cname + + def _generate_cpy_struct_decl(self, tp, name): + self._struct_decl(tp, *self._struct_names(tp)) + _generate_cpy_union_decl = _generate_cpy_struct_decl + + def _generate_cpy_struct_ctx(self, tp, name): + self._struct_ctx(tp, *self._struct_names(tp)) + _generate_cpy_union_ctx = _generate_cpy_struct_ctx + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_cpy_anonymous_collecttype(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_collecttype(tp, name) + else: + self._struct_collecttype(tp) + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp) + else: + self._struct_decl(tp, name, 'typedef_' + name) + + def _generate_cpy_anonymous_ctx(self, tp, name): + if isinstance(tp, model.EnumType): + self._enum_ctx(tp, name) + else: + self._struct_ctx(tp, name, 'typedef_' + name) + + # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + if (category, name) in self._seen_constants: + raise VerificationError( + "duplicate declaration of %s '%s'" % (category, name)) + self._seen_constants.add((category, name)) + # + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' int n = (%s) <= 0;' % (name,)) + prnt(' *o = (unsigned long long)((%s) | 0);' + ' /* check that %s is an integer */' % (name, name)) + if check_value is not None: + if check_value > 0: + check_value = '%dU' % (check_value,) + prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) + prnt(' n |= 2;') + prnt(' return n;') + prnt('}') + else: + assert check_value is None + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = tp.is_integer_type() + if not is_int or self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + if not self.target_is_python and tp.is_integer_type(): + type_op = CffiOp(OP_CONSTANT_INT, -1) + else: + if self.target_is_python: + const_kind = OP_DLOPEN_CONST + else: + const_kind = OP_CONSTANT + type_index = self._typesdict[tp] + type_op = CffiOp(const_kind, type_index) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op)) + + # ---------- + # enums + + def _generate_cpy_enum_collecttype(self, tp, name): + self._do_collect_type(tp) + + def _generate_cpy_enum_decl(self, tp, name=None): + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator) + + def _enum_ctx(self, tp, cname): + type_index = self._typesdict[tp] + type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._lsts["global"].append( + GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, + check_value=enumvalue)) + # + if cname is not None and '$' not in cname and not self.target_is_python: + size = "sizeof(%s)" % cname + signed = "((%s)-1) <= 0" % cname + else: + basetp = tp.build_baseinttype(self.ffi, []) + size = self.ffi.sizeof(basetp) + signed = int(int(self.ffi.cast(basetp, -1)) < 0) + allenums = ",".join(tp.enumerators) + self._lsts["enum"].append( + EnumExpr(tp.name, type_index, size, signed, allenums)) + + def _generate_cpy_enum_ctx(self, tp, name): + self._enum_ctx(tp, tp._get_c_name()) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + if tp == '...': + if self.target_is_python: + raise VerificationError( + "cannot use the syntax '...' in '#define %s ...' when " + "using the ABI mode" % (name,)) + check_value = None + else: + check_value = tp # an integer + type_op = CffiOp(OP_CONSTANT_INT, -1) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op, + check_value=check_value)) + + # ---------- + # global variables + + def _global_type(self, tp, global_name): + if isinstance(tp, model.ArrayType): + actual_length = tp.length + if actual_length == '...': + actual_length = '_cffi_array_len(%s)' % (global_name,) + tp_item = self._global_type(tp.item, '%s[0]' % global_name) + tp = model.ArrayType(tp_item, actual_length) + return tp + + def _generate_cpy_variable_collecttype(self, tp, name): + self._do_collect_type(self._global_type(tp, name)) + + def _generate_cpy_variable_decl(self, tp, name): + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_cpy_variable_ctx(self, tp, name): + tp = self._global_type(tp, name) + type_index = self._typesdict[tp] + if self.target_is_python: + op = OP_GLOBAL_VAR + else: + op = OP_GLOBAL_VAR_F + self._lsts["global"].append( + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) + + # ---------- + # extern "Python" + + def _generate_cpy_extern_python_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + self._do_collect_type(tp) + _generate_cpy_dllexport_python_collecttype = \ + _generate_cpy_extern_python_plus_c_collecttype = \ + _generate_cpy_extern_python_collecttype + + def _extern_python_decl(self, tp, name, tag_and_space): + prnt = self._prnt + if isinstance(tp.result, model.VoidType): + size_of_result = '0' + else: + context = 'result of %s' % name + size_of_result = '(int)sizeof(%s)' % ( + tp.result.get_c_name('', context),) + prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) + prnt(' { "%s.%s", %s, 0, 0 };' % ( + self.module_name, name, size_of_result)) + prnt() + # + arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' a%d' % i, context) + arguments.append(arg) + # + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s(%s)' % (name, repr_arguments) + if tp.abi == "__stdcall": + name_and_arguments = '_cffi_stdcall ' + name_and_arguments + # + def may_need_128_bits(tp): + return (isinstance(tp, model.PrimitiveType) and + tp.name == 'long double') + # + size_of_a = max(len(tp.args)*8, 8) + if may_need_128_bits(tp.result): + size_of_a = max(size_of_a, 16) + if isinstance(tp.result, model.StructOrUnion): + size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( + tp.result.get_c_name(''), size_of_a, + tp.result.get_c_name(''), size_of_a) + prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) + prnt('{') + prnt(' char a[%s];' % size_of_a) + prnt(' char *p = a;') + for i, type in enumerate(tp.args): + arg = 'a%d' % i + if (isinstance(type, model.StructOrUnion) or + may_need_128_bits(type)): + arg = '&' + arg + type = model.PointerType(type) + prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) + prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) + if not isinstance(tp.result, model.VoidType): + prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) + prnt('}') + prnt() + self._num_externpy += 1 + + def _generate_cpy_extern_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'static ') + + def _generate_cpy_dllexport_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') + + def _generate_cpy_extern_python_plus_c_decl(self, tp, name): + self._extern_python_decl(tp, name, '') + + def _generate_cpy_extern_python_ctx(self, tp, name): + if self.target_is_python: + raise VerificationError( + "cannot use 'extern \"Python\"' in the ABI mode") + if tp.ellipsis: + raise NotImplementedError("a vararg function is extern \"Python\"") + type_index = self._typesdict[tp] + type_op = CffiOp(OP_EXTERN_PYTHON, type_index) + self._lsts["global"].append( + GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) + + _generate_cpy_dllexport_python_ctx = \ + _generate_cpy_extern_python_plus_c_ctx = \ + _generate_cpy_extern_python_ctx + + def _print_string_literal_in_array(self, s): + prnt = self._prnt + prnt('// # NB. this is not a string because of a size limit in MSVC') + if not isinstance(s, bytes): # unicode + s = s.encode('utf-8') # -> bytes + else: + s.decode('utf-8') # got bytes, check for valid utf-8 + try: + s.decode('ascii') + except UnicodeDecodeError: + s = b'# -*- encoding: utf8 -*-\n' + s + for line in s.splitlines(True): + comment = line + if type('//') is bytes: # python2 + line = map(ord, line) # make a list of integers + else: # python3 + # type(line) is bytes, which enumerates like a list of integers + comment = ascii(comment)[1:-1] + prnt(('// ' + comment).rstrip()) + printed_line = '' + for c in line: + if len(printed_line) >= 76: + prnt(printed_line) + printed_line = '' + printed_line += '%d,' % (c,) + prnt(printed_line) + + # ---------- + # emitting the opcodes for individual types + + def _emit_bytecode_VoidType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) + + def _emit_bytecode_PrimitiveType(self, tp, index): + prim_index = PRIMITIVE_TO_INDEX[tp.name] + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) + + def _emit_bytecode_UnknownIntegerType(self, tp, index): + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) | 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_RawFunctionType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) + index += 1 + for tp1 in tp.args: + realindex = self._typesdict[tp1] + if index != realindex: + if isinstance(tp1, model.PrimitiveType): + self._emit_bytecode_PrimitiveType(tp1, index) + else: + self.cffi_types[index] = CffiOp(OP_NOOP, realindex) + index += 1 + flags = int(tp.ellipsis) + if tp.abi is not None: + if tp.abi == '__stdcall': + flags |= 2 + else: + raise NotImplementedError("abi=%r" % (tp.abi,)) + self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) + + def _emit_bytecode_PointerType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType + + def _emit_bytecode_FunctionPtrType(self, tp, index): + raw = tp.as_raw_function() + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) + + def _emit_bytecode_ArrayType(self, tp, index): + item_index = self._typesdict[tp.item] + if tp.length is None: + self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) + elif tp.length == '...': + raise VerificationError( + "type %s badly placed: the '...' array length can only be " + "used on global arrays or on fields of structures" % ( + str(tp).replace('/*...*/', '...'),)) + else: + assert self.cffi_types[index + 1] == 'LEN' + self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) + self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) + + def _emit_bytecode_StructType(self, tp, index): + struct_index = self._struct_unions[tp] + self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + + def _emit_bytecode_EnumType(self, tp, index): + enum_index = self._enums[tp] + self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) + recompiler = Recompiler(ffi, module_name, + target_is_python=(preamble is None)) + recompiler.collect_type_table() + recompiler.collect_step_tables() + f = NativeIO() + recompiler.write_source_to_f(f, preamble) + output = f.getvalue() + try: + with open(target_file, 'r') as f1: + if f1.read(len(output) + 1) != output: + raise IOError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except IOError: + tmp_file = '%s.~%d' % (target_file, os.getpid()) + with open(tmp_file, 'w') as f1: + f1.write(output) + try: + os.rename(tmp_file, target_file) + except OSError: + os.unlink(target_file) + os.rename(tmp_file, target_file) + return True + +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): + assert preamble is not None + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) + +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) + +def _modname_to_file(outputdir, modname, extension): + parts = modname.split('.') + try: + os.makedirs(os.path.join(outputdir, *parts[:-1])) + except OSError: + pass + parts[-1] += extension + return os.path.join(outputdir, *parts), parts + + +# Aaargh. Distutils is not tested at all for the purpose of compiling +# DLLs that are not extension modules. Here are some hacks to work +# around that, in the _patch_for_*() functions... + +def _patch_meth(patchlist, cls, name, new_meth): + old = getattr(cls, name) + patchlist.append((cls, name, old)) + setattr(cls, name, new_meth) + return old + +def _unpatch_meths(patchlist): + for cls, name, old_meth in reversed(patchlist): + setattr(cls, name, old_meth) + +def _patch_for_embedding(patchlist): + if sys.platform == 'win32': + # we must not remove the manifest when building for embedding! + from distutils.msvc9compiler import MSVCCompiler + _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', + lambda self, manifest_file: manifest_file) + + if sys.platform == 'darwin': + # we must not make a '-bundle', but a '-dynamiclib' instead + from distutils.ccompiler import CCompiler + def my_link_shared_object(self, *args, **kwds): + if '-bundle' in self.linker_so: + self.linker_so = list(self.linker_so) + i = self.linker_so.index('-bundle') + self.linker_so[i] = '-dynamiclib' + return old_link_shared_object(self, *args, **kwds) + old_link_shared_object = _patch_meth(patchlist, CCompiler, + 'link_shared_object', + my_link_shared_object) + +def _patch_for_target(patchlist, target): + from distutils.command.build_ext import build_ext + # if 'target' is different from '*', we need to patch some internal + # method to just return this 'target' value, instead of having it + # built from module_name + if target.endswith('.*'): + target = target[:-2] + if sys.platform == 'win32': + target += '.dll' + elif sys.platform == 'darwin': + target += '.dylib' + else: + target += '.so' + _patch_meth(patchlist, build_ext, 'get_ext_filename', + lambda self, ext_name: target) + + +def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, + c_file=None, source_extension='.c', extradir=None, + compiler_verbose=1, target=None, debug=None, **kwds): + if not isinstance(module_name, str): + module_name = module_name.encode('ascii') + if ffi._windows_unicode: + ffi._apply_windows_unicode(kwds) + if preamble is not None: + embedding = (ffi._embedding is not None) + if embedding: + ffi._apply_embedding_fix(kwds) + if c_file is None: + c_file, parts = _modname_to_file(tmpdir, module_name, + source_extension) + if extradir: + parts = [extradir] + parts + ext_c_file = os.path.join(*parts) + else: + ext_c_file = c_file + # + if target is None: + if embedding: + target = '%s.*' % module_name + else: + target = '*' + # + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) + if call_c_compiler: + patchlist = [] + cwd = os.getcwd() + try: + if embedding: + _patch_for_embedding(patchlist) + if target != '*': + _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) + os.chdir(tmpdir) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) + finally: + os.chdir(cwd) + _unpatch_meths(patchlist) + return outputfilename + else: + return ext, updated + else: + if c_file is None: + c_file, _ = _modname_to_file(tmpdir, module_name, '.py') + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) + if call_c_compiler: + return c_file + else: + return None, updated + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/setuptools_ext.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/setuptools_ext.py new file mode 100644 index 0000000000000000000000000000000000000000..8fe361487e469b3a87b80ddec1c5585b3801c587 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/setuptools_ext.py @@ -0,0 +1,219 @@ +import os +import sys + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from distutils.errors import DistutilsSetupError + raise DistutilsSetupError(msg) + + +def execfile(filename, glob): + # We use execfile() (here rewritten for Python 3) instead of + # __import__() to load the build script. The problem with + # a normal import is that in some packages, the intermediate + # __init__.py files may already try to import the file that + # we are generating. + with open(filename) as f: + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') + exec(code, glob, glob) + + +def add_cffi_module(dist, mod_spec): + from cffi.api import FFI + + if not isinstance(mod_spec, basestring): + error("argument to 'cffi_modules=...' must be a str or a list of str," + " not %r" % (type(mod_spec).__name__,)) + mod_spec = str(mod_spec) + try: + build_file_name, ffi_var_name = mod_spec.split(':') + except ValueError: + error("%r must be of the form 'path/build.py:ffi_variable'" % + (mod_spec,)) + if not os.path.exists(build_file_name): + ext = '' + rewritten = build_file_name.replace('.', '/') + '.py' + if os.path.exists(rewritten): + ext = ' (rewrite cffi_modules to [%r])' % ( + rewritten + ':' + ffi_var_name,) + error("%r does not name an existing file%s" % (build_file_name, ext)) + + mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} + execfile(build_file_name, mod_vars) + + try: + ffi = mod_vars[ffi_var_name] + except KeyError: + error("%r: object %r not found in module" % (mod_spec, + ffi_var_name)) + if not isinstance(ffi, FFI): + ffi = ffi() # maybe it's a function instead of directly an ffi + if not isinstance(ffi, FFI): + error("%r is not an FFI instance (got %r)" % (mod_spec, + type(ffi).__name__)) + if not hasattr(ffi, '_assigned_source'): + error("%r: the set_source() method was not called" % (mod_spec,)) + module_name, source, source_extension, kwds = ffi._assigned_source + if ffi._windows_unicode: + kwds = kwds.copy() + ffi._apply_windows_unicode(kwds) + + if source is None: + _add_py_module(dist, ffi, module_name) + else: + _add_c_module(dist, ffi, module_name, source, source_extension, kwds) + +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent + of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) + + On Windows, with CPython <= 3.4, it's better not to use py_limited_api + because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. + Recently (2020) we started shipping only >= 3.5 wheels, though. So + we'll give it another try and set py_limited_api on Windows >= 3.5. + """ + from cffi import recompiler + + if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') + and recompiler.USE_LIMITED_API): + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + from distutils.core import Extension + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from distutils.dir_util import mkpath + from distutils import log + from cffi import recompiler + + allsources = ['$PLACEHOLDER'] + allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) + ext = Extension(name=module_name, sources=allsources, **kwds) + + def make_mod(tmpdir, pre_run=None): + c_file = os.path.join(tmpdir, module_name + source_extension) + log.info("generating cffi module %r" % c_file) + mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) + updated = recompiler.make_c_source(ffi, module_name, source, c_file) + if not updated: + log.info("already up-to-date") + return c_file + + if dist.ext_modules is None: + dist.ext_modules = [] + dist.ext_modules.append(ext) + + base_class = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class): + def run(self): + if ext.sources[0] == '$PLACEHOLDER': + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) + base_class.run(self) + dist.cmdclass['build_ext'] = build_ext_make_mod + # NB. multiple runs here will create multiple 'build_ext_make_mod' + # classes. Even in this case the 'build_ext' command should be + # run once; but just in case, the logic above does nothing if + # called again. + + +def _add_py_module(dist, ffi, module_name): + from distutils.dir_util import mkpath + from setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from distutils import log + from cffi import recompiler + + def generate_mod(py_file): + log.info("generating cffi module %r" % py_file) + mkpath(os.path.dirname(py_file)) + updated = recompiler.make_py_source(ffi, module_name, py_file) + if not updated: + log.info("already up-to-date") + + base_class = dist.cmdclass.get('build_py', build_py) + class build_py_make_mod(base_class): + def run(self): + base_class.run(self) + module_path = module_name.split('.') + module_path[-1] += '.py' + generate_mod(os.path.join(self.build_lib, *module_path)) + def get_source_files(self): + # This is called from 'setup.py sdist' only. Exclude + # the generate .py module in this case. + saved_py_modules = self.py_modules + try: + if saved_py_modules: + self.py_modules = [m for m in saved_py_modules + if m != module_name] + return base_class.get_source_files(self) + finally: + self.py_modules = saved_py_modules + dist.cmdclass['build_py'] = build_py_make_mod + + # distutils and setuptools have no notion I could find of a + # generated python module. If we don't add module_name to + # dist.py_modules, then things mostly work but there are some + # combination of options (--root and --record) that will miss + # the module. So we add it here, which gives a few apparently + # harmless warnings about not finding the file outside the + # build directory. + # Then we need to hack more in get_source_files(); see above. + if dist.py_modules is None: + dist.py_modules = [] + dist.py_modules.append(module_name) + + # the following is only for "build_ext -i" + base_class_2 = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class_2): + def run(self): + base_class_2.run(self) + if self.inplace: + # from get_ext_fullpath() in distutils/command/build_ext.py + module_path = module_name.split('.') + package = '.'.join(module_path[:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + file_name = module_path[-1] + '.py' + generate_mod(os.path.join(package_dir, file_name)) + dist.cmdclass['build_ext'] = build_ext_make_mod + +def cffi_modules(dist, attr, value): + assert attr == 'cffi_modules' + if isinstance(value, basestring): + value = [value] + + for cffi_module in value: + add_cffi_module(dist, cffi_module) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_cpy.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_cpy.py new file mode 100644 index 0000000000000000000000000000000000000000..6de0df0ea4e1a98e65964ab61588df9abf536bac --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_cpy.py @@ -0,0 +1,1076 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, imp +from . import model +from .error import VerificationError + + +class VCPythonEngine(object): + _class_key = 'x' + _gen_python_module = True + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self._struct_pending_verification = {} + self._types_of_builtin_functions = {} + + def patch_extension_kwds(self, kwds): + pass + + def find_module(self, module_name, path, so_suffixes): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] not in so_suffixes: + return None + return filename + + def collect_types(self): + self._typesdict = {} + self._generate("collecttype") + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _do_collect_type(self, tp): + if ((not isinstance(tp, model.PrimitiveType) + or tp.name == 'long double') + and tp not in self._typesdict): + num = len(self._typesdict) + self._typesdict[tp] = num + + def write_source_to_f(self): + self.collect_types() + # + # The new module will have a _cffi_setup() function that receives + # objects from the ffi world, and that calls some setup code in + # the module. This setup code is split in several independent + # functions, e.g. one per constant. The functions are "chained" + # by ending in a tail call to each other. + # + # This is further split in two chained lists, depending on if we + # can do it at import-time or if we must wait for _cffi_setup() to + # provide us with the <ctype> objects. This is needed because we + # need the values of the enum constants in order to build the + # <ctype 'enum'> that we may have to pass to _cffi_setup(). + # + # The following two 'chained_list_constants' items contains + # the head of these two chained lists, as a string that gives the + # call to do, if any. + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] + # + prnt = self._prnt + # first paste some standard set of lines that are mostly '#define' + prnt(cffimod_header) + prnt() + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate("decl") + # + # implement the function _cffi_setup_custom() as calling the + # head of the chained list. + self._generate_setup_custom() + prnt() + # + # produce the method table, including the entries for the + # generated Python->C function wrappers, which are done + # by generate_cpy_function_method(). + prnt('static PyMethodDef _cffi_methods[] = {') + self._generate("method") + prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') + prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') + prnt('};') + prnt() + # + # standard init. + modname = self.verifier.get_module_name() + constants = self._chained_list_constants[False] + prnt('#if PY_MAJOR_VERSION >= 3') + prnt() + prnt('static struct PyModuleDef _cffi_module_def = {') + prnt(' PyModuleDef_HEAD_INIT,') + prnt(' "%s",' % modname) + prnt(' NULL,') + prnt(' -1,') + prnt(' _cffi_methods,') + prnt(' NULL, NULL, NULL, NULL') + prnt('};') + prnt() + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = PyModule_Create(&_cffi_module_def);') + prnt(' if (lib == NULL)') + prnt(' return NULL;') + prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) + prnt(' Py_DECREF(lib);') + prnt(' return NULL;') + prnt(' }') + prnt(' return lib;') + prnt('}') + prnt() + prnt('#else') + prnt() + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) + prnt(' if (lib == NULL)') + prnt(' return;') + prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) + prnt(' return;') + prnt(' return;') + prnt('}') + prnt() + prnt('#endif') + + def load_library(self, flags=None): + # XXX review all usages of 'self' here! + # import it as a new extension module + imp.acquire_lock() + try: + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() + try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) + module = imp.load_dynamic(self.verifier.get_module_name(), + self.verifier.modulefilename) + except ImportError as e: + error = "importing %r: %s" % (self.verifier.modulefilename, e) + raise VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) + finally: + imp.release_lock() + # + # call loading_cpy_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + # + # the C code will need the <ctype> objects. Collect them in + # order in a list. + revmapping = dict([(value, key) + for (key, value) in self._typesdict.items()]) + lst = [revmapping[i] for i in range(len(revmapping))] + lst = list(map(self.ffi._get_cached_btype, lst)) + # + # build the FFILibrary class and instance and call _cffi_setup(). + # this will set up some fields like '_cffi_types', and only then + # it will invoke the chained list of functions that will really + # build (notably) the constant objects, as <cdata> if they are + # pointers, and store them as attributes on the 'library' object. + class FFILibrary(object): + _cffi_python_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) + library = FFILibrary() + if module._cffi_setup(lst, VerificationError, library): + import warnings + warnings.warn("reimporting %r might overwrite older definitions" + % (self.verifier.get_module_name())) + # + # finally, call the loaded_cpy_xxx() functions. This will perform + # the final adjustments, like copying the Python->C wrapper + # functions from the module to the 'library' object, and setting + # up the FFILibrary class with properties for the global C variables. + self._load(module, 'loaded', library=library) + module._cffi_original_ffi = self.ffi + module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + else: + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif isinstance(tp, (model.StructOrUnion, model.EnumType)): + # a struct (not a struct pointer) as a function argument + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + 'alloca((size_t)datasize) : NULL;' % (tovar,)) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif tp.name != 'long double': + return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs: generates no code so far + + _generate_cpy_typedef_collecttype = _generate_nothing + _generate_cpy_typedef_decl = _generate_nothing + _generate_cpy_typedef_method = _generate_nothing + _loading_cpy_typedef = _loaded_noop + _loaded_cpy_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + self._do_collect_type(tp) + else: + # don't call _do_collect_type(tp) in this common case, + # otherwise test_autofilled_struct_as_argument fails + for type in tp.args: + self._do_collect_type(type) + self._do_collect_type(tp.result) + + def _generate_cpy_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + prnt(' %s;' % type.get_c_name(' x%d' % i, context)) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + prnt(' %s;' % tp.result.get_c_name(' result', context)) + prnt(' PyObject *pyresult;') + else: + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( + 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + prnt(' { %s%s(%s); }' % ( + result_code, name, + ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + prnt() + + def _generate_cpy_function_method(self, tp, name): + if tp.ellipsis: + return + numargs = len(tp.args) + if numargs == 0: + meth = 'METH_NOARGS' + elif numargs == 1: + meth = 'METH_O' + else: + meth = 'METH_VARARGS' + self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) + + _loading_cpy_function = _loaded_noop + + def _loaded_cpy_function(self, tp, name, module, library): + if tp.ellipsis: + return + func = getattr(module, name) + setattr(library, name, func) + self._types_of_builtin_functions[func] = tp + + # ---------- + # named structs + + _generate_cpy_struct_collecttype = _generate_nothing + def _generate_cpy_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + def _generate_cpy_struct_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'struct', name) + def _loading_cpy_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + def _loaded_cpy_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + _generate_cpy_union_collecttype = _generate_nothing + def _generate_cpy_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + def _generate_cpy_union_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'union', name) + def _loading_cpy_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + def _loaded_cpy_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('static PyObject *') + prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static Py_ssize_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') + prnt(' return _cffi_get_struct_layout(nums);') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _generate_struct_or_union_method(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, + layoutfuncname)) + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + function = getattr(module, layoutfuncname) + layout = function() + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + _generate_cpy_anonymous_collecttype = _generate_nothing + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _generate_cpy_anonymous_method(self, tp, name): + if not isinstance(tp, model.EnumType): + self._generate_struct_or_union_method(tp, '', name) + + def _loading_cpy_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_cpy_enum(tp, name, module) + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_cpy_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_cpy_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + vartp=None, delayed=True, size_too=False, + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + prnt(' PyObject *o;') + prnt(' int res;') + if not is_int: + prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) + else: + assert category == 'const' + # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # + if not is_int: + if category == 'var': + realexpr = '&' + name + else: + realexpr = name + prnt(' i = (%s);' % (realexpr,)) + prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', + 'variable type'),)) + assert delayed + else: + prnt(' o = _cffi_from_c_int_const(%s);' % name) + prnt(' if (o == NULL)') + prnt(' return -1;') + if size_too: + prnt(' {') + prnt(' PyObject *o1 = o;') + prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' + % (name,)) + prnt(' Py_DECREF(o1);') + prnt(' if (o == NULL)') + prnt(' return -1;') + prnt(' }') + prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) + prnt(' Py_DECREF(o);') + prnt(' if (res < 0)') + prnt(' return -1;') + prnt(' return %s;' % self._chained_list_constants[delayed]) + self._chained_list_constants[delayed] = funcname + '(lib)' + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + _generate_cpy_constant_method = _generate_nothing + _loading_cpy_constant = _loaded_noop + _loaded_cpy_constant = _loaded_noop + + # ---------- + # enums + + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator, delayed=False) + return + # + funcname = self._enum_funcname(prefix, name) + prnt = self._prnt + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) + prnt(' return %s;' % self._chained_list_constants[True]) + self._chained_list_constants[True] = funcname + '(lib)' + prnt('}') + prnt() + + _generate_cpy_enum_collecttype = _generate_nothing + _generate_cpy_enum_method = _generate_nothing + + def _loading_cpy_enum(self, tp, name, module): + if tp.partial: + enumvalues = [getattr(module, enumerator) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + + def _loaded_cpy_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + _generate_cpy_macro_collecttype = _generate_nothing + _generate_cpy_macro_method = _generate_nothing + _loading_cpy_macro = _loaded_noop + _loaded_cpy_macro = _loaded_noop + + # ---------- + # global variables + + def _generate_cpy_variable_collecttype(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + else: + tp_ptr = model.PointerType(tp) + self._do_collect_type(tp_ptr) + + def _generate_cpy_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + self._generate_cpy_const(False, name, tp, vartp=tp_ptr, + size_too = tp.length_is_unknown()) + else: + tp_ptr = model.PointerType(tp) + self._generate_cpy_const(False, name, tp_ptr, category='var') + + _generate_cpy_variable_method = _generate_nothing + _loading_cpy_variable = _loaded_noop + + def _loaded_cpy_variable(self, tp, name, module, library): + value = getattr(library, name) + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + assert isinstance(value, tuple) + (value, size) = value + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + # 'value' is a <cdata 'type *'> which we have to replace with + # a <cdata 'type[N]'> if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + return + # remove ptr=<cdata 'int *'> from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + ptr = value + delattr(library, name) + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + + # ---------- + + def _generate_setup_custom(self): + prnt = self._prnt + prnt('static int _cffi_setup_custom(PyObject *lib)') + prnt('{') + prnt(' return %s;' % self._chained_list_constants[True]) + prnt('}') + +cffimod_header = r''' +#include <Python.h> +#include <stddef.h> + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include <malloc.h> /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include <stdint.h> +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include <stdint.h> +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include <alloca.h> +# endif +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_CheckExact +# undef PyCapsule_GetPointer +# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int_const(x) \ + (((x) > 0) ? \ + ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) +#define _CFFI_NUM_EXPORTS 25 + +typedef struct _ctypedescr CTypeDescrObject; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; +static PyObject *_cffi_types, *_cffi_VerificationError; + +static int _cffi_setup_custom(PyObject *lib); /* forward */ + +static PyObject *_cffi_setup(PyObject *self, PyObject *args) +{ + PyObject *library; + int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ + if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, + &library)) + return NULL; + Py_INCREF(_cffi_types); + Py_INCREF(_cffi_VerificationError); + if (_cffi_setup_custom(library) < 0) + return NULL; + return PyBool_FromLong(was_alive); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +static int _cffi_init(void) +{ + PyObject *module, *c_api_object = NULL; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) + goto failure; + if (!PyCapsule_CheckExact(c_api_object)) { + PyErr_SetNone(PyExc_ImportError); + goto failure; + } + memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), + _CFFI_NUM_EXPORTS * sizeof(void *)); + + Py_DECREF(module); + Py_DECREF(c_api_object); + return 0; + + failure: + Py_XDECREF(module); + Py_XDECREF(c_api_object); + return -1; +} + +#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) + +/**********/ +''' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_gen.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_gen.py new file mode 100644 index 0000000000000000000000000000000000000000..26421526f62a07e04419cd57f1f19a64ecd36452 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/vengine_gen.py @@ -0,0 +1,675 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine(object): + _class_key = 'g' + _gen_python_module = False + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self.export_symbols = [] + self._struct_pending_verification = {} + + def patch_extension_kwds(self, kwds): + # add 'export_symbols' to the dictionary. Note that we add the + # list before filling it. When we fill it, it will thus also show + # up in kwds['export_symbols']. + kwds.setdefault('export_symbols', self.export_symbols) + + def find_module(self, module_name, path, so_suffixes): + for so_suffix in so_suffixes: + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + + def collect_types(self): + pass # not needed in the generic engine + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self): + prnt = self._prnt + # first paste some standard set of lines that are mostly '#include' + prnt(cffimod_header) + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + # + # call generate_gen_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate('decl') + # + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + if sys.platform == 'win32': + if sys.version_info >= (3,): + prefix = 'PyInit_' + else: + prefix = 'init' + modname = self.verifier.get_module_name() + prnt("void %s%s(void) { }\n" % (prefix, modname)) + + def load_library(self, flags=0): + # import it with the CFFI backend + backend = self.ffi._backend + # needs to make a path that contains '/', on Posix + filename = os.path.join(os.curdir, self.verifier.modulefilename) + module = backend.load_library(filename, flags) + # + # call loading_gen_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + + # build the FFILibrary class and instance, this is a module subclass + # because modules are expected to have usually-constant-attributes and + # in PyPy this means the JIT is able to treat attributes as constant, + # which we want. + class FFILibrary(types.ModuleType): + _cffi_generic_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + library = FFILibrary("") + # + # finally, call the loaded_gen_xxx() functions. This will set + # up the 'library' object. + self._load(module, 'loaded', library=library) + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_gen_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_gen_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + # typedefs: generates no code so far + + _generate_gen_typedef_decl = _generate_nothing + _loading_gen_typedef = _loaded_noop + _loaded_gen_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_gen_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no _cffi_f_%s wrapper) + self._generate_gen_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + context = 'argument of %s' % name + arglist = [type.get_c_name(' %s' % arg, context) + for type, arg in zip(tp.args, argnames)] + tpresult = tp.result + if isinstance(tpresult, model.StructOrUnion): + arglist.insert(0, tpresult.get_c_name(' *r', context)) + tpresult = model.void_type + arglist = ', '.join(arglist) or 'void' + wrappername = '_cffi_f_%s' % name + self.export_symbols.append(wrappername) + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) + context = 'result of %s' % name + prnt(tpresult.get_c_name(funcdecl, context)) + prnt('{') + # + if isinstance(tp.result, model.StructOrUnion): + result_code = '*r = ' + elif not isinstance(tp.result, model.VoidType): + result_code = 'return ' + else: + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) + prnt('}') + prnt() + + _loading_gen_function = _loaded_noop + + def _loaded_gen_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + newfunction = self._load_constant(False, tp, name, module) + else: + indirections = [] + base_tp = tp + if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) + or isinstance(tp.result, model.StructOrUnion)): + indirect_args = [] + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) + indirect_result = tp.result + if isinstance(indirect_result, model.StructOrUnion): + if indirect_result.fldtypes is None: + raise TypeError("'%s' is used as result type, " + "but is opaque" % ( + indirect_result._get_c_name(),)) + indirect_result = model.PointerType(indirect_result) + indirect_args.insert(0, indirect_result) + indirections.insert(0, ("result", indirect_result)) + indirect_result = model.void_type + tp = model.FunctionPtrType(tuple(indirect_args), + indirect_result, tp.ellipsis) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ, + base_tp) + setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) + + def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + if i == "result": + ffi = self.ffi + def newfunc(*args): + res = ffi.new(BType) + oldfunc(res, *args) + return res[0] + else: + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + newfunc._cffi_base_type = base_tp + return newfunc + + # ---------- + # named structs + + def _generate_gen_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + + def _loading_gen_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + + def _loaded_gen_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_gen_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + + def _loading_gen_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + + def _loaded_gen_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + self.export_symbols.append(layoutfuncname) + prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static intptr_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' return nums[i];') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] + function = module.load_function(BFunc, layoutfuncname) + layout = [] + num = 0 + while True: + x = function(num) + if x < 0: break + layout.append(x) + num += 1 + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_gen_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_gen_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _loading_gen_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_gen_enum(tp, name, module, '') + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_gen_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_gen_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + self.export_symbols.append(funcname) + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: + assert category == 'const' + prnt('int %s(long long *out_value)' % funcname) + prnt('{') + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + assert tp is not None + assert check_value is None + if category == 'var': + ampersand = '&' + else: + ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') + prnt(' return (%s%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_gen_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_gen_const(is_int, name, tp) + + _loading_gen_constant = _loaded_noop + + def _load_constant(self, is_int, tp, name, module, check_value=None): + funcname = '_cffi_const_%s' % name + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: + BType = self.ffi._typeof_locked("long long*")[0] + BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType) + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + BLongLong = self.ffi._typeof_locked("long long")[0] + value += (1 << (8*self.ffi.sizeof(BLongLong))) + else: + assert check_value is None + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] + function = module.load_function(BFunc, funcname) + value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] + return value + + def _loaded_gen_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # enums + + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise VerificationError(error) + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_gen_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_gen_const(True, enumerator) + return + # + funcname = self._enum_funcname(prefix, name) + self.export_symbols.append(funcname) + prnt = self._prnt + prnt('int %s(char *out_error)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue) + prnt(' return 0;') + prnt('}') + prnt() + + def _loading_gen_enum(self, tp, name, module, prefix='enum'): + if tp.partial: + enumvalues = [self._load_constant(True, tp, enumerator, module) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + else: + funcname = self._enum_funcname(prefix, name) + self._load_known_int_constant(module, funcname) + + def _loaded_gen_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) + + # ---------- + # macros: for now only for integers + + def _generate_gen_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) + + _loading_gen_macro = _loaded_noop + + def _loaded_gen_macro(self, tp, name, module, library): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # global variables + + def _generate_gen_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + if tp.length_is_unknown(): + prnt = self._prnt + funcname = '_cffi_sizeof_%s' % (name,) + self.export_symbols.append(funcname) + prnt("size_t %s(void)" % funcname) + prnt("{") + prnt(" return sizeof(%s);" % (name,)) + prnt("}") + tp_ptr = model.PointerType(tp.item) + self._generate_gen_const(False, name, tp_ptr) + else: + tp_ptr = model.PointerType(tp) + self._generate_gen_const(False, name, tp_ptr, category='var') + + _loading_gen_variable = _loaded_noop + + def _loaded_gen_variable(self, tp, name, module, library): + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + funcname = '_cffi_sizeof_%s' % (name,) + BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] + function = module.load_function(BFunc, funcname) + size = function() + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + # 'value' is a <cdata 'type *'> which we have to replace with + # a <cdata 'type[N]'> if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + return + # remove ptr=<cdata 'int *'> from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + funcname = '_cffi_var_%s' % name + BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] + function = module.load_function(BFunc, funcname) + ptr = function() + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + +cffimod_header = r''' +#include <stdio.h> +#include <stddef.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/types.h> /* XXX for ssize_t on some platforms */ + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include <malloc.h> /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include <stdint.h> +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include <stdint.h> +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include <alloca.h> +# endif +#endif +''' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cffi/verifier.py b/Latest_Group_Project/.venv/Lib/site-packages/cffi/verifier.py new file mode 100644 index 0000000000000000000000000000000000000000..a500c7814adf8ce52e911e0679d0b98335ae6597 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cffi/verifier.py @@ -0,0 +1,307 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os, binascii, shutil, io +from . import __version_verifier_modules__ +from . import ffiplatform +from .error import VerificationError + +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + + +class Verifier(object): + + def __init__(self, ffi, preamble, tmpdir=None, modulename=None, + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): + if ffi._parser._uses_new_feature: + raise VerificationError( + "feature not supported with ffi.verify(), but only " + "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) + self.ffi = ffi + self.preamble = preamble + if not modulename: + flattened_kwds = ffiplatform.flatten(kwds) + vengine_class = _locate_engine_class(ffi, force_generic_engine) + self._vengine = vengine_class(self) + self._vengine.patch_extension_kwds(kwds) + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) + # + if modulename: + if tag: + raise TypeError("can't specify both 'modulename' and 'tag'") + else: + key = '\x00'.join(['%d.%d' % sys.version_info[:2], + __version_verifier_modules__, + preamble, flattened_kwds] + + ffi._cdefsources) + if sys.version_info >= (3,): + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, + k1, k2) + suffix = _get_so_suffixes()[0] + self.tmpdir = tmpdir or _caller_dir_pycache() + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) + self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) + self.ext_package = ext_package + self._has_source = False + self._has_module = False + + def write_source(self, file=None): + """Write the C source code. It is produced in 'self.sourcefilename', + which can be tweaked beforehand.""" + with self.ffi._lock: + if self._has_source and file is None: + raise VerificationError( + "source code already written") + self._write_source(file) + + def compile_module(self): + """Write the C source code (if not done already) and compile it. + This produces a dynamic link library in 'self.modulefilename'.""" + with self.ffi._lock: + if self._has_module: + raise VerificationError("module already compiled") + if not self._has_source: + self._write_source() + self._compile_module() + + def load_library(self): + """Get a C module from this Verifier instance. + Returns an instance of a FFILibrary class that behaves like the + objects returned by ffi.dlopen(), but that delegates all + operations to the C module. If necessary, the C code is written + and compiled first. + """ + with self.ffi._lock: + if not self._has_module: + self._locate_module() + if not self._has_module: + if not self._has_source: + self._write_source() + self._compile_module() + return self._load_library() + + def get_module_name(self): + basename = os.path.basename(self.modulefilename) + # kill both the .so extension and the other .'s, as introduced + # by Python 3: 'basename.cpython-33m.so' + basename = basename.split('.', 1)[0] + # and the _d added in Python 2 debug builds --- but try to be + # conservative and not kill a legitimate _d + if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + basename = basename[:-2] + return basename + + def get_extension(self): + ffiplatform._hack_at_distutils() # backward compatibility hack + if not self._has_source: + with self.ffi._lock: + if not self._has_source: + self._write_source() + sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) + modname = self.get_module_name() + return ffiplatform.get_extension(sourcename, modname, **self.kwds) + + def generates_python_module(self): + return self._vengine._gen_python_module + + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + + # ---------- + + def _locate_module(self): + if not os.path.isfile(self.modulefilename): + if self.ext_package: + try: + pkg = __import__(self.ext_package, None, None, ['__doc__']) + except ImportError: + return # cannot import the package itself, give up + # (e.g. it might be called differently before installation) + path = pkg.__path__ + else: + path = None + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffixes()) + if filename is None: + return + self.modulefilename = filename + self._vengine.collect_types() + self._has_module = True + + def _write_source_to(self, file): + self._vengine._f = file + try: + self._vengine.write_source_to_f() + finally: + del self._vengine._f + + def _write_source(self, file=None): + if file is not None: + self._write_source_to(file) + else: + # Write our source file to an in memory file. + f = NativeIO() + self._write_source_to(f) + source_data = f.getvalue() + + # Determine if this matches the current file + if os.path.exists(self.sourcefilename): + with open(self.sourcefilename, "r") as fp: + needs_written = not (fp.read() == source_data) + else: + needs_written = True + + # Actually write the file out if it doesn't match + if needs_written: + _ensure_dir(self.sourcefilename) + with open(self.sourcefilename, "w") as fp: + fp.write(source_data) + + # Set this flag + self._has_source = True + + def _compile_module(self): + # compile this C source + tmpdir = os.path.dirname(self.sourcefilename) + outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) + try: + same = ffiplatform.samefile(outputfilename, self.modulefilename) + except OSError: + same = False + if not same: + _ensure_dir(self.modulefilename) + shutil.move(outputfilename, self.modulefilename) + self._has_module = True + + def _load_library(self): + assert self._has_module + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() + +# ____________________________________________________________ + +_FORCE_GENERIC_ENGINE = False # for tests + +def _locate_engine_class(ffi, force_generic_engine): + if _FORCE_GENERIC_ENGINE: + force_generic_engine = True + if not force_generic_engine: + if '__pypy__' in sys.builtin_module_names: + force_generic_engine = True + else: + try: + import _cffi_backend + except ImportError: + _cffi_backend = '?' + if ffi._backend is not _cffi_backend: + force_generic_engine = True + if force_generic_engine: + from . import vengine_gen + return vengine_gen.VGenericEngine + else: + from . import vengine_cpy + return vengine_cpy.VCPythonEngine + +# ____________________________________________________________ + +_TMPDIR = None + +def _caller_dir_pycache(): + if _TMPDIR: + return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result + filename = sys._getframe(2).f_code.co_filename + return os.path.abspath(os.path.join(os.path.dirname(filename), + '__pycache__')) + +def set_tmpdir(dirname): + """Set the temporary directory to use instead of __pycache__.""" + global _TMPDIR + _TMPDIR = dirname + +def cleanup_tmpdir(tmpdir=None, keep_so=False): + """Clean up the temporary directory by removing all files in it + called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" + tmpdir = tmpdir or _caller_dir_pycache() + try: + filelist = os.listdir(tmpdir) + except OSError: + return + if keep_so: + suffix = '.c' # only remove .c files + else: + suffix = _get_so_suffixes()[0].lower() + for fn in filelist: + if fn.lower().startswith('_cffi_') and ( + fn.lower().endswith(suffix) or fn.lower().endswith('.c')): + try: + os.unlink(os.path.join(tmpdir, fn)) + except OSError: + pass + clean_dir = [os.path.join(tmpdir, 'build')] + for dir in clean_dir: + try: + for fn in os.listdir(dir): + fn = os.path.join(dir, fn) + if os.path.isdir(fn): + clean_dir.append(fn) + else: + os.unlink(fn) + except OSError: + pass + +def _get_so_suffixes(): + suffixes = _extension_suffixes() + if not suffixes: + # bah, no C_EXTENSION available. Occurs on pypy without cpyext + if sys.platform == 'win32': + suffixes = [".pyd"] + else: + suffixes = [".so"] + + return suffixes + +def _ensure_dir(filename): + dirname = os.path.dirname(filename) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/DESCRIPTION.rst b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000000000000000000000000000000000000..e1187231a3553e6c1bec45c6b5a4e4e62b8ef70d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/DESCRIPTION.rst @@ -0,0 +1,3 @@ +UNKNOWN + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..3f94e7724e6efaae6b55325119a4f16820743f53 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/METADATA @@ -0,0 +1,31 @@ +Metadata-Version: 2.0 +Name: coreapi +Version: 2.3.3 +Summary: Python client library for Core API. +Home-page: https://github.com/core-api/python-client +Author: Tom Christie +Author-email: tom@tomchristie.com +License: BSD +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD 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.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Dist: coreschema +Requires-Dist: requests +Requires-Dist: itypes +Requires-Dist: uritemplate + +UNKNOWN + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..afc703ad7a8349e03ae9e53dcbd07cf27cbc385c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/RECORD @@ -0,0 +1,44 @@ +coreapi-2.3.3.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 +coreapi-2.3.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +coreapi-2.3.3.dist-info/METADATA,sha256=rnTekraFZkIHIF0BWe2PcSrZDBy537vH5pgRLzDDlUQ,1005 +coreapi-2.3.3.dist-info/RECORD,, +coreapi-2.3.3.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113 +coreapi-2.3.3.dist-info/entry_points.txt,sha256=Mb3FDcoqJ6cqPUKcCzqiwPvKXa-Wf3ZHtQxS_m-pXI4,224 +coreapi-2.3.3.dist-info/metadata.json,sha256=iWFzlCJHgq-mGUND10wri4b2dku0BpOeuSYL7kRRqko,1343 +coreapi-2.3.3.dist-info/top_level.txt,sha256=MJFenaIXVjtwaMfQPAehWlQlDbfzogpxABkcZ8M511g,42 +coreapi/__init__.py,sha256=QwRAmejBP4magBOzXnLo5x8nlugBYtgoOuRi0y4gjbQ,359 +coreapi/__pycache__/__init__.cpython-310.pyc,, +coreapi/__pycache__/auth.cpython-310.pyc,, +coreapi/__pycache__/client.cpython-310.pyc,, +coreapi/__pycache__/compat.cpython-310.pyc,, +coreapi/__pycache__/document.cpython-310.pyc,, +coreapi/__pycache__/exceptions.cpython-310.pyc,, +coreapi/__pycache__/utils.cpython-310.pyc,, +coreapi/auth.py,sha256=iSVI56TJf0Pc-PWSTdlrFaBJpJvauWpQrJgRbxpkLeg,2280 +coreapi/client.py,sha256=cOSlnvTcMQUVR_JEH7vhgO0FsWBF_1BS9uIEcifbqhQ,6572 +coreapi/codecs/__init__.py,sha256=hh9H7FHOxtRO_N3wjRiAvZdTbx2UKHuPadpo47uW93I,467 +coreapi/codecs/__pycache__/__init__.cpython-310.pyc,, +coreapi/codecs/__pycache__/base.cpython-310.pyc,, +coreapi/codecs/__pycache__/corejson.cpython-310.pyc,, +coreapi/codecs/__pycache__/display.cpython-310.pyc,, +coreapi/codecs/__pycache__/download.cpython-310.pyc,, +coreapi/codecs/__pycache__/jsondata.cpython-310.pyc,, +coreapi/codecs/__pycache__/python.cpython-310.pyc,, +coreapi/codecs/__pycache__/text.cpython-310.pyc,, +coreapi/codecs/base.py,sha256=OoH98Hk9KJ7Sx0SN6C-NIEFqe1abUoFeanee_OB6-pE,1278 +coreapi/codecs/corejson.py,sha256=cKLxulArpXicXWUo3NGAFO4t3MVWv42W07YWvZR8gn0,10198 +coreapi/codecs/display.py,sha256=UVTY739flQL_rVe_bviHHiODKG0A6gcZ3snUd7_tq64,4385 +coreapi/codecs/download.py,sha256=Pr8x3LUq1phxwxRjJbHevT0hst2iXecA7Q68L8rsW-Y,4596 +coreapi/codecs/jsondata.py,sha256=RzqWgoT_XEJ2fdZr4zGFqVDIoDySZAjOP2V2Q6sctiM,568 +coreapi/codecs/python.py,sha256=cH-4k_OHezzGghAfNTsgsEPROODSFrBvNb4ECE4QsNg,2769 +coreapi/codecs/text.py,sha256=GY5foOXXX1nTLKa2_txul9pyNhpBdGg-e7zD7XUaBlw,222 +coreapi/compat.py,sha256=3brcKEtkulFmQwN5eL9jp1J2t2lil40ko84n-3RJURc,1417 +coreapi/document.py,sha256=pll105Xv5wN-DQ4YD2yN41XDpFgVhOLpeg1Yyqny-9k,9768 +coreapi/exceptions.py,sha256=gWSHBpKkewb3-yHxKeX_y18gCsgcMY1NiIotVvyS7ec,1320 +coreapi/transports/__init__.py,sha256=9qo1d4arbmHKvh1kkFB_1dEqLU69_WnSrQ4CFiVKs7Y,169 +coreapi/transports/__pycache__/__init__.cpython-310.pyc,, +coreapi/transports/__pycache__/base.cpython-310.pyc,, +coreapi/transports/__pycache__/http.cpython-310.pyc,, +coreapi/transports/base.py,sha256=6-J0OgYVZ7LIKCYp4LPoQigIUykzU1HIwgOjhLelXxg,238 +coreapi/transports/http.py,sha256=jbdmDnOQjg91n93-pWLtqAFKPtZc6PhlsKSx_tyJ8sw,12578 +coreapi/utils.py,sha256=SXpRgSCg_zRid0yBoJi1jIaJukXC7T_Qi50Wpr8Aq6Q,11094 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..7bf9daa1ada4a6a6a9bfbf07f3b1a9f84a71bb32 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0.a0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/entry_points.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/entry_points.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6f86002a9646e3cd29e6a54606cf685ebe14ea0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/entry_points.txt @@ -0,0 +1,9 @@ +[coreapi.codecs] +corejson = coreapi.codecs:CoreJSONCodec +download = coreapi.codecs:DownloadCodec +json = coreapi.codecs:JSONCodec +text = coreapi.codecs:TextCodec + +[coreapi.transports] +http = coreapi.transports:HTTPTransport + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/metadata.json b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..c8e94d88eccf33a1e1c7b52c82a1c3aa4dab0474 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP"], "extensions": {"python.details": {"contacts": [{"email": "tom@tomchristie.com", "name": "Tom Christie", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/core-api/python-client"}}, "python.exports": {"coreapi.codecs": {"corejson": "coreapi.codecs:CoreJSONCodec", "download": "coreapi.codecs:DownloadCodec", "json": "coreapi.codecs:JSONCodec", "text": "coreapi.codecs:TextCodec"}, "coreapi.transports": {"http": "coreapi.transports:HTTPTransport"}}}, "extras": [], "generator": "bdist_wheel (0.30.0.a0)", "license": "BSD", "metadata_version": "2.0", "name": "coreapi", "run_requires": [{"requires": ["coreschema", "itypes", "requests", "uritemplate"]}], "summary": "Python client library for Core API.", "version": "2.3.3"} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ae44babdcd2afe7cf3fa7b4a9617278354bb74f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi-2.3.3.dist-info/top_level.txt @@ -0,0 +1,3 @@ +coreapi +coreapi/codecs +coreapi/transports diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..92ac89059e328b3b39af3143a4c447c6142747cf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__init__.py @@ -0,0 +1,12 @@ +# coding: utf-8 +from coreapi import auth, codecs, exceptions, transports, utils +from coreapi.client import Client +from coreapi.document import Array, Document, Link, Object, Error, Field + + +__version__ = '2.3.3' +__all__ = [ + 'Array', 'Document', 'Link', 'Object', 'Error', 'Field', + 'Client', + 'auth', 'codecs', 'exceptions', 'transports', 'utils', +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24a5a595fbaa6ac016229637dbf3f5cc64195c35 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/auth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2944eb8161718c7f2dcc38888a394c94e1236b0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/auth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/client.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/client.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6b8e9a699b1f0da6955aa5ea6216b0c0da3686a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/client.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f12e2678e6383ff0b337af0b393ba0670b51e84 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/document.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/document.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f30ea7ea187e3b499f9e05b73543ef9f998bdc2e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/document.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ff7be6191574f1e25d702dbe925b0a78cac1ade Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fcaced261f84a9ab545e7fd1ee566591920d5be2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/auth.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/auth.py new file mode 100644 index 0000000000000000000000000000000000000000..e110547c4b5940d001f2fd1c5aa21d9878d86061 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/auth.py @@ -0,0 +1,69 @@ +from coreapi.utils import domain_matches +from requests.auth import AuthBase, HTTPBasicAuth + + +class BasicAuthentication(HTTPBasicAuth): + allow_cookies = False + + def __init__(self, username, password, domain=None): + self.domain = domain + super(BasicAuthentication, self).__init__(username, password) + + def __call__(self, request): + if not domain_matches(request, self.domain): + return request + + return super(BasicAuthentication, self).__call__(request) + + +class TokenAuthentication(AuthBase): + allow_cookies = False + scheme = 'Bearer' + + def __init__(self, token, scheme=None, domain=None): + """ + * Use an unauthenticated client, and make a request to obtain a token. + * Create an authenticated client using eg. `TokenAuthentication(token="<token>")` + """ + self.token = token + self.domain = domain + if scheme is not None: + self.scheme = scheme + + def __call__(self, request): + if not domain_matches(request, self.domain): + return request + + request.headers['Authorization'] = '%s %s' % (self.scheme, self.token) + return request + + +class SessionAuthentication(AuthBase): + """ + Enables session based login. + + * Make an initial request to obtain a CSRF token. + * Make a login request. + """ + allow_cookies = True + safe_methods = ('GET', 'HEAD', 'OPTIONS', 'TRACE') + + def __init__(self, csrf_cookie_name=None, csrf_header_name=None, domain=None): + self.csrf_cookie_name = csrf_cookie_name + self.csrf_header_name = csrf_header_name + self.csrf_token = None + self.domain = domain + + def store_csrf_token(self, response, **kwargs): + if self.csrf_cookie_name in response.cookies: + self.csrf_token = response.cookies[self.csrf_cookie_name] + + def __call__(self, request): + if not domain_matches(request, self.domain): + return request + + if self.csrf_token and self.csrf_header_name is not None and (request.method not in self.safe_methods): + request.headers[self.csrf_header_name] = self.csrf_token + if self.csrf_cookie_name is not None: + request.register_hook('response', self.store_csrf_token) + return request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/client.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/client.py new file mode 100644 index 0000000000000000000000000000000000000000..d02a59ce822f1810d23777469b34dcf995bfc180 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/client.py @@ -0,0 +1,178 @@ +from coreapi import codecs, exceptions, transports +from coreapi.compat import string_types +from coreapi.document import Document, Link +from coreapi.utils import determine_transport, get_installed_codecs +import collections +import itypes + + +LinkAncestor = collections.namedtuple('LinkAncestor', ['document', 'keys']) + + +def _lookup_link(document, keys): + """ + Validates that keys looking up a link are correct. + + Returns a two-tuple of (link, link_ancestors). + """ + if not isinstance(keys, (list, tuple)): + msg = "'keys' must be a list of strings or ints." + raise TypeError(msg) + if any([ + not isinstance(key, string_types) and not isinstance(key, int) + for key in keys + ]): + raise TypeError("'keys' must be a list of strings or ints.") + + # Determine the link node being acted on, and its parent document. + # 'node' is the link we're calling the action for. + # 'document_keys' is the list of keys to the link's parent document. + node = document + link_ancestors = [LinkAncestor(document=document, keys=[])] + for idx, key in enumerate(keys): + try: + node = node[key] + except (KeyError, IndexError, TypeError): + index_string = ''.join('[%s]' % repr(key).strip('u') for key in keys) + msg = 'Index %s did not reference a link. Key %s was not found.' + raise exceptions.LinkLookupError(msg % (index_string, repr(key).strip('u'))) + if isinstance(node, Document): + ancestor = LinkAncestor(document=node, keys=keys[:idx + 1]) + link_ancestors.append(ancestor) + + # Ensure that we've correctly indexed into a link. + if not isinstance(node, Link): + index_string = ''.join('[%s]' % repr(key).strip('u') for key in keys) + msg = "Can only call 'action' on a Link. Index %s returned type '%s'." + raise exceptions.LinkLookupError( + msg % (index_string, type(node).__name__) + ) + + return (node, link_ancestors) + + +def _validate_parameters(link, parameters): + """ + Ensure that parameters passed to the link are correct. + Raises a `ParameterError` if any parameters do not validate. + """ + provided = set(parameters.keys()) + required = set([ + field.name for field in link.fields if field.required + ]) + optional = set([ + field.name for field in link.fields if not field.required + ]) + + errors = {} + + # Determine if any required field names not supplied. + missing = required - provided + for item in missing: + errors[item] = 'This parameter is required.' + + # Determine any parameter names supplied that are not valid. + unexpected = provided - (optional | required) + for item in unexpected: + errors[item] = 'Unknown parameter.' + + if errors: + raise exceptions.ParameterError(errors) + + +def get_default_decoders(): + return [ + codecs.CoreJSONCodec(), + codecs.JSONCodec(), + codecs.TextCodec(), + codecs.DownloadCodec() + ] + + +def get_default_transports(auth=None, session=None): + return [ + transports.HTTPTransport(auth=auth, session=session) + ] + + +class Client(itypes.Object): + def __init__(self, decoders=None, transports=None, auth=None, session=None): + assert transports is None or auth is None, ( + "Cannot specify both 'auth' and 'transports'. " + "When specifying transport instances explicitly you should set " + "the authentication directly on the transport." + ) + if decoders is None: + decoders = get_default_decoders() + if transports is None: + transports = get_default_transports(auth=auth) + self._decoders = itypes.List(decoders) + self._transports = itypes.List(transports) + + @property + def decoders(self): + return self._decoders + + @property + def transports(self): + return self._transports + + def get(self, url, format=None, force_codec=False): + link = Link(url, action='get') + + decoders = self.decoders + if format: + force_codec = True + decoders = [decoder for decoder in self.decoders if decoder.format == format] + if not decoders: + installed_codecs = get_installed_codecs() + if format in installed_codecs: + decoders = [installed_codecs[format]] + else: + raise ValueError("No decoder available with format='%s'" % format) + + # Perform the action, and return a new document. + transport = determine_transport(self.transports, link.url) + return transport.transition(link, decoders, force_codec=force_codec) + + def reload(self, document, format=None, force_codec=False): + # Fallback for v1.x. To be removed in favour of explict `get` style. + return self.get(document.url, format=format, force_codec=force_codec) + + def action(self, document, keys, params=None, validate=True, overrides=None, + action=None, encoding=None, transform=None): + if (action is not None) or (encoding is not None) or (transform is not None): + # Fallback for v1.x overrides. + # Will be removed at some point, most likely in a 2.1 release. + if overrides is None: + overrides = {} + if action is not None: + overrides['action'] = action + if encoding is not None: + overrides['encoding'] = encoding + if transform is not None: + overrides['transform'] = transform + + if isinstance(keys, string_types): + keys = [keys] + + if params is None: + params = {} + + # Validate the keys and link parameters. + link, link_ancestors = _lookup_link(document, keys) + if validate: + _validate_parameters(link, params) + + if overrides: + # Handle any explicit overrides. + url = overrides.get('url', link.url) + action = overrides.get('action', link.action) + encoding = overrides.get('encoding', link.encoding) + transform = overrides.get('transform', link.transform) + fields = overrides.get('fields', link.fields) + link = Link(url, action=action, encoding=encoding, transform=transform, fields=fields) + + # Perform the action, and return a new document. + transport = determine_transport(self.transports, link.url) + return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4fa6a1aa81ac1e67f931dabef7e9dec483a956e6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__init__.py @@ -0,0 +1,14 @@ +# coding: utf-8 +from coreapi.codecs.base import BaseCodec +from coreapi.codecs.corejson import CoreJSONCodec +from coreapi.codecs.display import DisplayCodec +from coreapi.codecs.download import DownloadCodec +from coreapi.codecs.jsondata import JSONCodec +from coreapi.codecs.python import PythonCodec +from coreapi.codecs.text import TextCodec + + +__all__ = [ + 'BaseCodec', 'CoreJSONCodec', 'DisplayCodec', + 'JSONCodec', 'PythonCodec', 'TextCodec', 'DownloadCodec' +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54e7a2e62a29cc6876bf90dfdbe5a59447383b65 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..427e234736de047db9dcbed46a481178df0e2fd0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/corejson.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/corejson.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86ddd8caac920e4e3e1f1e3909a269ba2f593a31 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/corejson.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/display.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/display.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8059e5fa52c8ac4a9beb3153d97995ded74fe0d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/display.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/download.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/download.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07aa6299b5e50eb88f27921676c8f19de10042f8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/download.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/jsondata.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/jsondata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5dee736423252e84f1c86e7020ae79464c7d38d7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/jsondata.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/python.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/python.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f62f479f1cf47ce8195a8210315adcb44b366d6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/python.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/text.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/text.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..044d41fbf839538e5895e9d03452021d2439c82b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/__pycache__/text.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/base.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/base.py new file mode 100644 index 0000000000000000000000000000000000000000..6f20044e436e273f65326997c31ea5d3c9729edc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/base.py @@ -0,0 +1,44 @@ +import itypes + + +class BaseCodec(itypes.Object): + media_type = None + + # We don't implement stubs, to ensure that we can check which of these + # two operations a codec supports. For example: + # `if hasattr(codec, 'decode'): ...` + + # def decode(self, bytestring, **options): + # pass + + # def encode(self, document, **options): + # pass + + # The following will be removed at some point, most likely in a 2.1 release: + def dump(self, *args, **kwargs): + # Fallback for v1.x interface + return self.encode(*args, **kwargs) + + def load(self, *args, **kwargs): + # Fallback for v1.x interface + return self.decode(*args, **kwargs) + + @property + def supports(self): + # Fallback for v1.x interface. + if '+' not in self.media_type: + return ['data'] + + ret = [] + if hasattr(self, 'encode'): + ret.append('encoding') + if hasattr(self, 'decode'): + ret.append('decoding') + return ret + + def get_media_types(self): + # Fallback, while transitioning from `application/vnd.coreapi+json` + # to simply `application/coreapi+json`. + if hasattr(self, 'media_types'): + return list(self.media_types) + return [self.media_type] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/corejson.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/corejson.py new file mode 100644 index 0000000000000000000000000000000000000000..f025533ee59e2d56b2c763cac3900db91c114c02 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/corejson.py @@ -0,0 +1,346 @@ +from __future__ import unicode_literals +from collections import OrderedDict +from coreapi.codecs.base import BaseCodec +from coreapi.compat import force_bytes, string_types, urlparse +from coreapi.compat import COMPACT_SEPARATORS, VERBOSE_SEPARATORS +from coreapi.document import Document, Link, Array, Object, Error, Field +from coreapi.exceptions import ParseError +import coreschema +import json + + +# Schema encoding and decoding. +# Just a naive first-pass at this point. + +SCHEMA_CLASS_TO_TYPE_ID = { + coreschema.Object: 'object', + coreschema.Array: 'array', + coreschema.Number: 'number', + coreschema.Integer: 'integer', + coreschema.String: 'string', + coreschema.Boolean: 'boolean', + coreschema.Null: 'null', + coreschema.Enum: 'enum', + coreschema.Anything: 'anything' +} + +TYPE_ID_TO_SCHEMA_CLASS = { + value: key + for key, value + in SCHEMA_CLASS_TO_TYPE_ID.items() +} + + +def encode_schema_to_corejson(schema): + if hasattr(schema, 'typename'): + type_id = schema.typename + else: + type_id = SCHEMA_CLASS_TO_TYPE_ID.get(schema.__class__, 'anything') + retval = { + '_type': type_id, + 'title': schema.title, + 'description': schema.description + } + if hasattr(schema, 'enum'): + retval['enum'] = schema.enum + return retval + + +def decode_schema_from_corejson(data): + type_id = _get_string(data, '_type') + title = _get_string(data, 'title') + description = _get_string(data, 'description') + + kwargs = {} + if type_id == 'enum': + kwargs['enum'] = _get_list(data, 'enum') + + schema_cls = TYPE_ID_TO_SCHEMA_CLASS.get(type_id, coreschema.Anything) + return schema_cls(title=title, description=description, **kwargs) + + +# Robust dictionary lookups, that always return an item of the correct +# type, using an empty default if an incorrect type exists. +# Useful for liberal parsing of inputs. + +def _get_schema(item, key): + schema_data = _get_dict(item, key) + if schema_data: + return decode_schema_from_corejson(schema_data) + return None + + +def _get_string(item, key): + value = item.get(key) + if isinstance(value, string_types): + return value + return '' + + +def _get_dict(item, key): + value = item.get(key) + if isinstance(value, dict): + return value + return {} + + +def _get_list(item, key): + value = item.get(key) + if isinstance(value, list): + return value + return [] + + +def _get_bool(item, key): + value = item.get(key) + if isinstance(value, bool): + return value + return False + + +def _graceful_relative_url(base_url, url): + """ + Return a graceful link for a URL relative to a base URL. + + * If they are the same, return an empty string. + * If the have the same scheme and hostname, return the path & query params. + * Otherwise return the full URL. + """ + if url == base_url: + return '' + base_prefix = '%s://%s' % urlparse.urlparse(base_url or '')[0:2] + url_prefix = '%s://%s' % urlparse.urlparse(url or '')[0:2] + if base_prefix == url_prefix and url_prefix != '://': + return url[len(url_prefix):] + return url + + +def _escape_key(string): + """ + The '_type' and '_meta' keys are reserved. + Prefix with an additional '_' if they occur. + """ + if string.startswith('_') and string.lstrip('_') in ('type', 'meta'): + return '_' + string + return string + + +def _unescape_key(string): + """ + Unescape '__type' and '__meta' keys if they occur. + """ + if string.startswith('__') and string.lstrip('_') in ('type', 'meta'): + return string[1:] + return string + + +def _get_content(item, base_url=None): + """ + Return a dictionary of content, for documents, objects and errors. + """ + return { + _unescape_key(key): _primitive_to_document(value, base_url) + for key, value in item.items() + if key not in ('_type', '_meta') + } + + +def _document_to_primitive(node, base_url=None): + """ + Take a Core API document and return Python primitives + ready to be rendered into the JSON style encoding. + """ + if isinstance(node, Document): + ret = OrderedDict() + ret['_type'] = 'document' + + meta = OrderedDict() + url = _graceful_relative_url(base_url, node.url) + if url: + meta['url'] = url + if node.title: + meta['title'] = node.title + if node.description: + meta['description'] = node.description + if meta: + ret['_meta'] = meta + + # Fill in key-value content. + ret.update([ + (_escape_key(key), _document_to_primitive(value, base_url=url)) + for key, value in node.items() + ]) + return ret + + elif isinstance(node, Error): + ret = OrderedDict() + ret['_type'] = 'error' + + if node.title: + ret['_meta'] = {'title': node.title} + + # Fill in key-value content. + ret.update([ + (_escape_key(key), _document_to_primitive(value, base_url=base_url)) + for key, value in node.items() + ]) + return ret + + elif isinstance(node, Link): + ret = OrderedDict() + ret['_type'] = 'link' + url = _graceful_relative_url(base_url, node.url) + if url: + ret['url'] = url + if node.action: + ret['action'] = node.action + if node.encoding: + ret['encoding'] = node.encoding + if node.transform: + ret['transform'] = node.transform + if node.title: + ret['title'] = node.title + if node.description: + ret['description'] = node.description + if node.fields: + ret['fields'] = [ + _document_to_primitive(field) for field in node.fields + ] + return ret + + elif isinstance(node, Field): + ret = OrderedDict({'name': node.name}) + if node.required: + ret['required'] = node.required + if node.location: + ret['location'] = node.location + if node.schema: + ret['schema'] = encode_schema_to_corejson(node.schema) + return ret + + elif isinstance(node, Object): + return OrderedDict([ + (_escape_key(key), _document_to_primitive(value, base_url=base_url)) + for key, value in node.items() + ]) + + elif isinstance(node, Array): + return [_document_to_primitive(value) for value in node] + + return node + + +def _primitive_to_document(data, base_url=None): + """ + Take Python primitives as returned from parsing JSON content, + and return a Core API document. + """ + if isinstance(data, dict) and data.get('_type') == 'document': + # Document + meta = _get_dict(data, '_meta') + url = _get_string(meta, 'url') + url = urlparse.urljoin(base_url, url) + title = _get_string(meta, 'title') + description = _get_string(meta, 'description') + content = _get_content(data, base_url=url) + return Document( + url=url, + title=title, + description=description, + media_type='application/coreapi+json', + content=content + ) + + if isinstance(data, dict) and data.get('_type') == 'error': + # Error + meta = _get_dict(data, '_meta') + title = _get_string(meta, 'title') + content = _get_content(data, base_url=base_url) + return Error(title=title, content=content) + + elif isinstance(data, dict) and data.get('_type') == 'link': + # Link + url = _get_string(data, 'url') + url = urlparse.urljoin(base_url, url) + action = _get_string(data, 'action') + encoding = _get_string(data, 'encoding') + transform = _get_string(data, 'transform') + title = _get_string(data, 'title') + description = _get_string(data, 'description') + fields = _get_list(data, 'fields') + fields = [ + Field( + name=_get_string(item, 'name'), + required=_get_bool(item, 'required'), + location=_get_string(item, 'location'), + schema=_get_schema(item, 'schema') + ) + for item in fields if isinstance(item, dict) + ] + return Link( + url=url, action=action, encoding=encoding, transform=transform, + title=title, description=description, fields=fields + ) + + elif isinstance(data, dict): + # Map + content = _get_content(data, base_url=base_url) + return Object(content) + + elif isinstance(data, list): + # Array + content = [_primitive_to_document(item, base_url) for item in data] + return Array(content) + + # String, Integer, Number, Boolean, null. + return data + + +class CoreJSONCodec(BaseCodec): + media_type = 'application/coreapi+json' + format = 'corejson' + + # The following is due to be deprecated... + media_types = ['application/coreapi+json', 'application/vnd.coreapi+json'] + + def decode(self, bytestring, **options): + """ + Takes a bytestring and returns a document. + """ + base_url = options.get('base_url') + + try: + data = json.loads(bytestring.decode('utf-8')) + except ValueError as exc: + raise ParseError('Malformed JSON. %s' % exc) + + doc = _primitive_to_document(data, base_url) + + if isinstance(doc, Object): + doc = Document(content=dict(doc)) + elif not (isinstance(doc, Document) or isinstance(doc, Error)): + raise ParseError('Top level node should be a document or error.') + + return doc + + def encode(self, document, **options): + """ + Takes a document and returns a bytestring. + """ + indent = options.get('indent') + + if indent: + kwargs = { + 'ensure_ascii': False, + 'indent': 4, + 'separators': VERBOSE_SEPARATORS + } + else: + kwargs = { + 'ensure_ascii': False, + 'indent': None, + 'separators': COMPACT_SEPARATORS + } + + data = _document_to_primitive(document) + return force_bytes(json.dumps(data, **kwargs)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/display.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/display.py new file mode 100644 index 0000000000000000000000000000000000000000..250e0ccfa41e1992883c3ae170ea2c78d3dfa618 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/display.py @@ -0,0 +1,124 @@ +# Note that `DisplayCodec` is deliberately omitted from the documentation, +# as it is considered an implementation detail. +# It may move into a utility function in the future. +from __future__ import unicode_literals +from coreapi.codecs.base import BaseCodec +from coreapi.compat import console_style, string_types +from coreapi.document import Document, Link, Array, Object, Error +import json + + +def _colorize_document(text): + return console_style(text, fg='green') # pragma: nocover + + +def _colorize_error(text): + return console_style(text, fg='red') # pragma: nocover + + +def _colorize_keys(text): + return console_style(text, fg='cyan') # pragma: nocover + + +def _to_plaintext(node, indent=0, base_url=None, colorize=False, extra_offset=None): + colorize_document = _colorize_document if colorize else lambda x: x + colorize_error = _colorize_error if colorize else lambda x: x + colorize_keys = _colorize_keys if colorize else lambda x: x + + if isinstance(node, Document): + head_indent = ' ' * indent + body_indent = ' ' * (indent + 1) + + body = '\n'.join([ + body_indent + colorize_keys(str(key) + ': ') + + _to_plaintext(value, indent + 1, base_url=base_url, colorize=colorize, extra_offset=len(str(key))) + for key, value in node.data.items() + ] + [ + body_indent + colorize_keys(str(key) + '(') + + _fields_to_plaintext(value, colorize=colorize) + colorize_keys(')') + for key, value in node.links.items() + ]) + + head = colorize_document('<%s %s>' % ( + node.title.strip() or 'Document', + json.dumps(node.url) + )) + + return head if (not body) else head + '\n' + body + + elif isinstance(node, Object): + head_indent = ' ' * indent + body_indent = ' ' * (indent + 1) + + body = '\n'.join([ + body_indent + colorize_keys(str(key)) + ': ' + + _to_plaintext(value, indent + 1, base_url=base_url, colorize=colorize, extra_offset=len(str(key))) + for key, value in node.data.items() + ] + [ + body_indent + colorize_keys(str(key) + '(') + + _fields_to_plaintext(value, colorize=colorize) + colorize_keys(')') + for key, value in node.links.items() + ]) + + return '{}' if (not body) else '{\n' + body + '\n' + head_indent + '}' + + if isinstance(node, Error): + head_indent = ' ' * indent + body_indent = ' ' * (indent + 1) + + body = '\n'.join([ + body_indent + colorize_keys(str(key) + ': ') + + _to_plaintext(value, indent + 1, base_url=base_url, colorize=colorize, extra_offset=len(str(key))) + for key, value in node.items() + ]) + + head = colorize_error('<Error: %s>' % node.title.strip() if node.title else '<Error>') + + return head if (not body) else head + '\n' + body + + elif isinstance(node, Array): + head_indent = ' ' * indent + body_indent = ' ' * (indent + 1) + + body = ',\n'.join([ + body_indent + _to_plaintext(value, indent + 1, base_url=base_url, colorize=colorize) + for value in node + ]) + + return '[]' if (not body) else '[\n' + body + '\n' + head_indent + ']' + + elif isinstance(node, Link): + return ( + colorize_keys('link(') + + _fields_to_plaintext(node, colorize=colorize) + + colorize_keys(')') + ) + + if isinstance(node, string_types) and (extra_offset is not None) and ('\n' in node): + # Display newlines in strings gracefully. + text = json.dumps(node) + spacing = (' ' * indent) + (' ' * extra_offset) + ' ' + return text.replace('\\n', '\n' + spacing) + + return json.dumps(node) + + +def _fields_to_plaintext(link, colorize=False): + colorize_keys = _colorize_keys if colorize else lambda x: x + + return colorize_keys(', ').join([ + field.name for field in link.fields if field.required + ] + [ + '[%s]' % field.name for field in link.fields if not field.required + ]) + + +class DisplayCodec(BaseCodec): + """ + A plaintext representation of a Document, intended for readability. + """ + media_type = 'text/plain' + + def encode(self, document, **options): + colorize = options.get('colorize', False) + return _to_plaintext(document, colorize=colorize) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/download.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/download.py new file mode 100644 index 0000000000000000000000000000000000000000..09956908cbf8cea6f935473562763c56ab1a13f1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/download.py @@ -0,0 +1,149 @@ +# coding: utf-8 +from coreapi.codecs.base import BaseCodec +from coreapi.compat import urlparse +from coreapi.utils import DownloadedFile, guess_extension +import cgi +import os +import posixpath +import tempfile + + +def _unique_output_path(path): + """ + Given a path like '/a/b/c.txt' + + Return the first available filename that doesn't already exist, + using an incrementing suffix if needed. + + For example: '/a/b/c.txt' or '/a/b/c (1).txt' or '/a/b/c (2).txt'... + """ + basename, ext = os.path.splitext(path) + idx = 0 + while os.path.exists(path): + idx += 1 + path = "%s (%d)%s" % (basename, idx, ext) + return path + + +def _safe_filename(filename): + """ + Sanitize output filenames, to remove any potentially unsafe characters. + """ + filename = os.path.basename(filename) + + keepcharacters = (' ', '.', '_', '-') + filename = ''.join( + char for char in filename + if char.isalnum() or char in keepcharacters + ).strip().strip('.') + + return filename + + +def _get_filename_from_content_disposition(content_disposition): + """ + Determine an output filename based on the `Content-Disposition` header. + """ + params = value, params = cgi.parse_header(content_disposition) + + if 'filename*' in params: + try: + charset, lang, filename = params['filename*'].split('\'', 2) + filename = urlparse.unquote(filename) + filename = filename.encode('iso-8859-1').decode(charset) + return _safe_filename(filename) + except (ValueError, LookupError): + pass + + if 'filename' in params: + filename = params['filename'] + return _safe_filename(filename) + + return None + + +def _get_filename_from_url(url, content_type=None): + """ + Determine an output filename based on the download URL. + """ + parsed = urlparse.urlparse(url) + final_path_component = posixpath.basename(parsed.path.rstrip('/')) + filename = _safe_filename(final_path_component) + suffix = guess_extension(content_type or '') + + if filename: + if '.' not in filename: + return filename + suffix + return filename + elif suffix: + return 'download' + suffix + + return None + + +def _get_filename(base_url=None, content_type=None, content_disposition=None): + """ + Determine an output filename to use for the download. + """ + filename = None + if content_disposition: + filename = _get_filename_from_content_disposition(content_disposition) + if base_url and not filename: + filename = _get_filename_from_url(base_url, content_type) + if not filename: + return None # Ensure empty filenames return as `None` for consistency. + return filename + + +class DownloadCodec(BaseCodec): + """ + A codec to handle raw file downloads, such as images and other media. + """ + media_type = '*/*' + format = 'download' + + def __init__(self, download_dir=None): + """ + `download_dir` - The path to use for file downloads. + """ + self._delete_on_close = download_dir is None + self._download_dir = download_dir + + @property + def download_dir(self): + return self._download_dir + + def decode(self, bytestring, **options): + base_url = options.get('base_url') + content_type = options.get('content_type') + content_disposition = options.get('content_disposition') + + # Write the download to a temporary .download file. + fd, temp_path = tempfile.mkstemp(suffix='.download') + file_handle = os.fdopen(fd, 'wb') + file_handle.write(bytestring) + file_handle.close() + + # Determine the output filename. + output_filename = _get_filename(base_url, content_type, content_disposition) + if output_filename is None: + output_filename = os.path.basename(temp_path) + + # Determine the output directory. + output_dir = self._download_dir + if output_dir is None: + output_dir = os.path.dirname(temp_path) + + # Determine the full output path. + output_path = os.path.join(output_dir, output_filename) + + # Move the temporary download file to the final location. + if output_path != temp_path: + output_path = _unique_output_path(output_path) + os.rename(temp_path, output_path) + + # Open the file and return the file object. + output_file = open(output_path, 'rb') + downloaded = DownloadedFile(output_file, output_path, delete=self._delete_on_close) + downloaded.basename = output_filename + return downloaded diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/jsondata.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/jsondata.py new file mode 100644 index 0000000000000000000000000000000000000000..9fa1732f9da20fde0b15061bf6f79247b2218795 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/jsondata.py @@ -0,0 +1,22 @@ +# coding: utf-8 +from coreapi.codecs.base import BaseCodec +from coreapi.exceptions import ParseError +import collections +import json + + +class JSONCodec(BaseCodec): + media_type = 'application/json' + format = 'json' + + def decode(self, bytestring, **options): + """ + Return raw JSON data. + """ + try: + return json.loads( + bytestring.decode('utf-8'), + object_pairs_hook=collections.OrderedDict + ) + except ValueError as exc: + raise ParseError('Malformed JSON. %s' % exc) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/python.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/python.py new file mode 100644 index 0000000000000000000000000000000000000000..6265a280de83265d22360a533b4c3c4d08e92799 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/python.py @@ -0,0 +1,82 @@ +# Note that `DisplayCodec` is deliberately omitted from the documentation, +# as it is considered an implementation detail. +# It may move into a utility function in the future. +from __future__ import unicode_literals +from coreapi.codecs.base import BaseCodec +from coreapi.document import Document, Link, Array, Object, Error, Field + + +def _to_repr(node): + if isinstance(node, Document): + content = ', '.join([ + '%s: %s' % (repr(key), _to_repr(value)) + for key, value in node.items() + ]) + return 'Document(url=%s, title=%s, content={%s})' % ( + repr(node.url), repr(node.title), content + ) + + elif isinstance(node, Error): + content = ', '.join([ + '%s: %s' % (repr(key), _to_repr(value)) + for key, value in node.items() + ]) + return 'Error(title=%s, content={%s})' % ( + repr(node.title), content + ) + + elif isinstance(node, Object): + return '{%s}' % ', '.join([ + '%s: %s' % (repr(key), _to_repr(value)) + for key, value in node.items() + ]) + + elif isinstance(node, Array): + return '[%s]' % ', '.join([ + _to_repr(value) for value in node + ]) + + elif isinstance(node, Link): + args = "url=%s" % repr(node.url) + if node.action: + args += ", action=%s" % repr(node.action) + if node.encoding: + args += ", encoding=%s" % repr(node.encoding) + if node.transform: + args += ", transform=%s" % repr(node.transform) + if node.description: + args += ", description=%s" % repr(node.description) + if node.fields: + fields_repr = ', '.join(_to_repr(item) for item in node.fields) + args += ", fields=[%s]" % fields_repr + return "Link(%s)" % args + + elif isinstance(node, Field): + args = repr(node.name) + if not node.required and not node.location: + return args + if node.required: + args += ', required=True' + if node.location: + args += ', location=%s' % repr(node.location) + if node.schema: + args += ', schema=%s' % repr(node.schema) + return 'Field(%s)' % args + + return repr(node) + + +class PythonCodec(BaseCodec): + """ + A Python representation of a Document, for use with '__repr__'. + """ + media_type = 'text/python' + + def encode(self, document, **options): + # Object and Array only have the class name wrapper if they + # are the outermost element. + if isinstance(document, Object): + return 'Object(%s)' % _to_repr(document) + elif isinstance(document, Array): + return 'Array(%s)' % _to_repr(document) + return _to_repr(document) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/text.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/text.py new file mode 100644 index 0000000000000000000000000000000000000000..77604986a65ecbf016731a5292474b4242a1cd96 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/codecs/text.py @@ -0,0 +1,10 @@ +# coding: utf-8 +from coreapi.codecs.base import BaseCodec + + +class TextCodec(BaseCodec): + media_type = 'text/*' + format = 'text' + + def decode(self, bytestring, **options): + return bytestring.decode('utf-8') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..9890ec171217e640dd37af14e10f68fb1945b453 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/compat.py @@ -0,0 +1,65 @@ +# coding: utf-8 + +import base64 + + +__all__ = [ + 'urlparse', 'string_types', + 'COMPACT_SEPARATORS', 'VERBOSE_SEPARATORS' +] + + +try: + # Python 2 + import urlparse + import cookielib as cookiejar + + string_types = (basestring,) + text_type = unicode + COMPACT_SEPARATORS = (b',', b':') + VERBOSE_SEPARATORS = (b',', b': ') + + def b64encode(input_string): + # Provide a consistently-as-unicode interface across 2.x and 3.x + return base64.b64encode(input_string) + +except ImportError: + # Python 3 + import urllib.parse as urlparse + from io import IOBase + from http import cookiejar + + string_types = (str,) + text_type = str + COMPACT_SEPARATORS = (',', ':') + VERBOSE_SEPARATORS = (',', ': ') + + def b64encode(input_string): + # Provide a consistently-as-unicode interface across 2.x and 3.x + return base64.b64encode(input_string.encode('ascii')).decode('ascii') + + +def force_bytes(string): + if isinstance(string, string_types): + return string.encode('utf-8') + return string + + +def force_text(string): + if not isinstance(string, string_types): + return string.decode('utf-8') + return string + + +try: + import click + console_style = click.style +except ImportError: + def console_style(text, **kwargs): + return text + + +try: + from tempfile import _TemporaryFileWrapper +except ImportError: + _TemporaryFileWrapper = None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/document.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/document.py new file mode 100644 index 0000000000000000000000000000000000000000..c6c9ceb55abd400376ea3ddd2eb0f34406e27836 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/document.py @@ -0,0 +1,310 @@ +# coding: utf-8 +from __future__ import unicode_literals +from collections import OrderedDict, namedtuple +from coreapi.compat import string_types +import itypes + + +def _to_immutable(value): + if isinstance(value, dict): + return Object(value) + elif isinstance(value, list): + return Array(value) + return value + + +def _repr(node): + from coreapi.codecs.python import PythonCodec + return PythonCodec().encode(node) + + +def _str(node): + from coreapi.codecs.display import DisplayCodec + return DisplayCodec().encode(node) + + +def _key_sorting(item): + """ + Document and Object sorting. + Regular attributes sorted alphabetically. + Links are sorted based on their URL and action. + """ + key, value = item + if isinstance(value, Link): + action_priority = { + 'get': 0, + 'post': 1, + 'put': 2, + 'patch': 3, + 'delete': 4 + }.get(value.action, 5) + return (1, (value.url, action_priority)) + return (0, key) + + +# The field class, as used by Link objects: + +# NOTE: 'type', 'description' and 'example' are now deprecated, +# in favor of 'schema'. +Field = namedtuple('Field', ['name', 'required', 'location', 'schema', 'description', 'type', 'example']) +Field.__new__.__defaults__ = (False, '', None, None, None, None) + + +# The Core API primitives: + +class Document(itypes.Dict): + """ + The Core API document type. + + Expresses the data that the client may access, + and the actions that the client may perform. + """ + def __init__(self, url=None, title=None, description=None, media_type=None, content=None): + content = {} if (content is None) else content + + if url is not None and not isinstance(url, string_types): + raise TypeError("'url' must be a string.") + if title is not None and not isinstance(title, string_types): + raise TypeError("'title' must be a string.") + if description is not None and not isinstance(description, string_types): + raise TypeError("'description' must be a string.") + if media_type is not None and not isinstance(media_type, string_types): + raise TypeError("'media_type' must be a string.") + if not isinstance(content, dict): + raise TypeError("'content' must be a dict.") + if any([not isinstance(key, string_types) for key in content.keys()]): + raise TypeError('content keys must be strings.') + + self._url = '' if (url is None) else url + self._title = '' if (title is None) else title + self._description = '' if (description is None) else description + self._media_type = '' if (media_type is None) else media_type + self._data = {key: _to_immutable(value) for key, value in content.items()} + + def clone(self, data): + return self.__class__(self.url, self.title, self.description, self.media_type, data) + + def __iter__(self): + items = sorted(self._data.items(), key=_key_sorting) + return iter([key for key, value in items]) + + def __repr__(self): + return _repr(self) + + def __str__(self): + return _str(self) + + def __eq__(self, other): + if self.__class__ == other.__class__: + return ( + self.url == other.url and + self.title == other.title and + self._data == other._data + ) + return super(Document, self).__eq__(other) + + @property + def url(self): + return self._url + + @property + def title(self): + return self._title + + @property + def description(self): + return self._description + + @property + def media_type(self): + return self._media_type + + @property + def data(self): + return OrderedDict([ + (key, value) for key, value in self.items() + if not isinstance(value, Link) + ]) + + @property + def links(self): + return OrderedDict([ + (key, value) for key, value in self.items() + if isinstance(value, Link) + ]) + + +class Object(itypes.Dict): + """ + An immutable mapping of strings to values. + """ + def __init__(self, *args, **kwargs): + data = dict(*args, **kwargs) + if any([not isinstance(key, string_types) for key in data.keys()]): + raise TypeError('Object keys must be strings.') + self._data = {key: _to_immutable(value) for key, value in data.items()} + + def __iter__(self): + items = sorted(self._data.items(), key=_key_sorting) + return iter([key for key, value in items]) + + def __repr__(self): + return _repr(self) + + def __str__(self): + return _str(self) + + @property + def data(self): + return OrderedDict([ + (key, value) for key, value in self.items() + if not isinstance(value, Link) + ]) + + @property + def links(self): + return OrderedDict([ + (key, value) for key, value in self.items() + if isinstance(value, Link) + ]) + + +class Array(itypes.List): + """ + An immutable list type container. + """ + def __init__(self, *args): + self._data = [_to_immutable(value) for value in list(*args)] + + def __repr__(self): + return _repr(self) + + def __str__(self): + return _str(self) + + +class Link(itypes.Object): + """ + Links represent the actions that a client may perform. + """ + def __init__(self, url=None, action=None, encoding=None, transform=None, title=None, description=None, fields=None): + if (url is not None) and (not isinstance(url, string_types)): + raise TypeError("Argument 'url' must be a string.") + if (action is not None) and (not isinstance(action, string_types)): + raise TypeError("Argument 'action' must be a string.") + if (encoding is not None) and (not isinstance(encoding, string_types)): + raise TypeError("Argument 'encoding' must be a string.") + if (transform is not None) and (not isinstance(transform, string_types)): + raise TypeError("Argument 'transform' must be a string.") + if (title is not None) and (not isinstance(title, string_types)): + raise TypeError("Argument 'title' must be a string.") + if (description is not None) and (not isinstance(description, string_types)): + raise TypeError("Argument 'description' must be a string.") + if (fields is not None) and (not isinstance(fields, (list, tuple))): + raise TypeError("Argument 'fields' must be a list.") + if (fields is not None) and any([ + not (isinstance(item, string_types) or isinstance(item, Field)) + for item in fields + ]): + raise TypeError("Argument 'fields' must be a list of strings or fields.") + + self._url = '' if (url is None) else url + self._action = '' if (action is None) else action + self._encoding = '' if (encoding is None) else encoding + self._transform = '' if (transform is None) else transform + self._title = '' if (title is None) else title + self._description = '' if (description is None) else description + self._fields = () if (fields is None) else tuple([ + item if isinstance(item, Field) else Field(item, required=False, location='') + for item in fields + ]) + + @property + def url(self): + return self._url + + @property + def action(self): + return self._action + + @property + def encoding(self): + return self._encoding + + @property + def transform(self): + return self._transform + + @property + def title(self): + return self._title + + @property + def description(self): + return self._description + + @property + def fields(self): + return self._fields + + def __eq__(self, other): + return ( + isinstance(other, Link) and + self.url == other.url and + self.action == other.action and + self.encoding == other.encoding and + self.transform == other.transform and + self.description == other.description and + sorted(self.fields, key=lambda f: f.name) == sorted(other.fields, key=lambda f: f.name) + ) + + def __repr__(self): + return _repr(self) + + def __str__(self): + return _str(self) + + +class Error(itypes.Dict): + def __init__(self, title=None, content=None): + data = {} if (content is None) else content + + if title is not None and not isinstance(title, string_types): + raise TypeError("'title' must be a string.") + if content is not None and not isinstance(content, dict): + raise TypeError("'content' must be a dict.") + if any([not isinstance(key, string_types) for key in data.keys()]): + raise TypeError('content keys must be strings.') + + self._title = '' if (title is None) else title + self._data = {key: _to_immutable(value) for key, value in data.items()} + + def __iter__(self): + items = sorted(self._data.items(), key=_key_sorting) + return iter([key for key, value in items]) + + def __repr__(self): + return _repr(self) + + def __str__(self): + return _str(self) + + def __eq__(self, other): + return ( + isinstance(other, Error) and + self.title == other.title and + self._data == other._data + ) + + @property + def title(self): + return self._title + + def get_messages(self): + messages = [] + for value in self.values(): + if isinstance(value, Array): + messages += [ + item for item in value if isinstance(item, string_types) + ] + return messages diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..fee52f08e2ccace7f4dc1c01db8fe164c809c8e5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/exceptions.py @@ -0,0 +1,62 @@ +# coding: utf-8 +from __future__ import unicode_literals + + +class CoreAPIException(Exception): + """ + A base class for all `coreapi` exceptions. + """ + pass + + +class ParseError(CoreAPIException): + """ + Raised when an invalid Core API encoding is encountered. + """ + pass + + +class NoCodecAvailable(CoreAPIException): + """ + Raised when there is no available codec that can handle the given media. + """ + pass + + +class NetworkError(CoreAPIException): + """ + Raised when the transport layer fails to make a request or get a response. + """ + pass + + +class LinkLookupError(CoreAPIException): + """ + Raised when `.action` fails to index a link in the document. + """ + pass + + +class ParameterError(CoreAPIException): + """ + Raised when the parameters passed do not match the link fields. + + * A required field was not included. + * An unknown field was included. + * A field was passed an invalid type for the link location/encoding. + """ + pass + + +class ErrorMessage(CoreAPIException): + """ + Raised when the transition returns an error message. + """ + def __init__(self, error): + self.error = error + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, repr(self.error)) + + def __str__(self): + return str(self.error) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a6e22d87c3d40cb9b888a5db0f5e18883f4074a6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__init__.py @@ -0,0 +1,8 @@ +# coding: utf-8 +from coreapi.transports.base import BaseTransport +from coreapi.transports.http import HTTPTransport + + +__all__ = [ + 'BaseTransport', 'HTTPTransport' +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4eac274e0fd7b1bde4978b5b77a1819a10892be0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ab110e756b8b73900d35b5170570edcf40ef629 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/http.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/http.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fe88271f1726ac2a8980b46c1957887c914c8d3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/__pycache__/http.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/base.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/base.py new file mode 100644 index 0000000000000000000000000000000000000000..b19f0ccc64b9c2dbce082db8d07b9160ffe4ec08 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/base.py @@ -0,0 +1,9 @@ +# coding: utf-8 +import itypes + + +class BaseTransport(itypes.Object): + schemes = None + + def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False): + raise NotImplementedError() # pragma: nocover diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/http.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/http.py new file mode 100644 index 0000000000000000000000000000000000000000..a54802432e221386df3f74445f24ae5fa67fff74 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/transports/http.py @@ -0,0 +1,388 @@ +# coding: utf-8 +from __future__ import unicode_literals +from collections import OrderedDict +from coreapi import exceptions, utils +from coreapi.compat import cookiejar, urlparse +from coreapi.document import Document, Object, Link, Array, Error +from coreapi.transports.base import BaseTransport +from coreapi.utils import guess_filename, is_file, File +import collections +import requests +import itypes +import mimetypes +import uritemplate +import warnings + + +Params = collections.namedtuple('Params', ['path', 'query', 'data', 'files']) +empty_params = Params({}, {}, {}, {}) + + +class ForceMultiPartDict(dict): + """ + A dictionary that always evaluates as True. + Allows us to force requests to use multipart encoding, even when no + file parameters are passed. + """ + def __bool__(self): + return True + + def __nonzero__(self): + return True + + +class BlockAll(cookiejar.CookiePolicy): + """ + A cookie policy that rejects all cookies. + Used to override the default `requests` behavior. + """ + return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False + netscape = True + rfc2965 = hide_cookie2 = False + + +class DomainCredentials(requests.auth.AuthBase): + """ + Custom auth class to support deprecated 'credentials' argument. + """ + allow_cookies = False + credentials = None + + def __init__(self, credentials=None): + self.credentials = credentials + + def __call__(self, request): + if not self.credentials: + return request + + # Include any authorization credentials relevant to this domain. + url_components = urlparse.urlparse(request.url) + host = url_components.hostname + if host in self.credentials: + request.headers['Authorization'] = self.credentials[host] + return request + + +class CallbackAdapter(requests.adapters.HTTPAdapter): + """ + Custom requests HTTP adapter, to support deprecated callback arguments. + """ + def __init__(self, request_callback=None, response_callback=None): + self.request_callback = request_callback + self.response_callback = response_callback + + def send(self, request, **kwargs): + if self.request_callback is not None: + self.request_callback(request) + response = super(CallbackAdapter, self).send(request, **kwargs) + if self.response_callback is not None: + self.response_callback(response) + return response + + +def _get_method(action): + if not action: + return 'GET' + return action.upper() + + +def _get_encoding(encoding): + if not encoding: + return 'application/json' + return encoding + + +def _get_params(method, encoding, fields, params=None): + """ + Separate the params into the various types. + """ + if params is None: + return empty_params + + field_map = {field.name: field for field in fields} + + path = {} + query = {} + data = {} + files = {} + + errors = {} + + # Ensure graceful behavior in edge-case where both location='body' and + # location='form' fields are present. + seen_body = False + + for key, value in params.items(): + if key not in field_map or not field_map[key].location: + # Default is 'query' for 'GET' and 'DELETE', and 'form' for others. + location = 'query' if method in ('GET', 'DELETE') else 'form' + else: + location = field_map[key].location + + if location == 'form' and encoding == 'application/octet-stream': + # Raw uploads should always use 'body', not 'form'. + location = 'body' + + try: + if location == 'path': + path[key] = utils.validate_path_param(value) + elif location == 'query': + query[key] = utils.validate_query_param(value) + elif location == 'body': + data = utils.validate_body_param(value, encoding=encoding) + seen_body = True + elif location == 'form': + if not seen_body: + data[key] = utils.validate_form_param(value, encoding=encoding) + except exceptions.ParameterError as exc: + errors[key] = "%s" % exc + + if errors: + raise exceptions.ParameterError(errors) + + # Move any files from 'data' into 'files'. + if isinstance(data, dict): + for key, value in list(data.items()): + if is_file(data[key]): + files[key] = data.pop(key) + + return Params(path, query, data, files) + + +def _get_url(url, path_params): + """ + Given a templated URL and some parameters that have been provided, + expand the URL. + """ + if path_params: + return uritemplate.expand(url, path_params) + return url + + +def _get_headers(url, decoders): + """ + Return a dictionary of HTTP headers to use in the outgoing request. + """ + accept_media_types = decoders[0].get_media_types() + if '*/*' not in accept_media_types: + accept_media_types.append('*/*') + + headers = { + 'accept': ', '.join(accept_media_types), + 'user-agent': 'coreapi' + } + + return headers + + +def _get_upload_headers(file_obj): + """ + When a raw file upload is made, determine the Content-Type and + Content-Disposition headers to use with the request. + """ + name = guess_filename(file_obj) + content_type = None + content_disposition = None + + # Determine the content type of the upload. + if getattr(file_obj, 'content_type', None): + content_type = file_obj.content_type + elif name: + content_type, encoding = mimetypes.guess_type(name) + + # Determine the content disposition of the upload. + if name: + content_disposition = 'attachment; filename="%s"' % name + + return { + 'Content-Type': content_type or 'application/octet-stream', + 'Content-Disposition': content_disposition or 'attachment' + } + + +def _build_http_request(session, url, method, headers=None, encoding=None, params=empty_params): + """ + Make an HTTP request and return an HTTP response. + """ + opts = { + "headers": headers or {} + } + + if params.query: + opts['params'] = params.query + + if params.data or params.files: + if encoding == 'application/json': + opts['json'] = params.data + elif encoding == 'multipart/form-data': + opts['data'] = params.data + opts['files'] = ForceMultiPartDict(params.files) + elif encoding == 'application/x-www-form-urlencoded': + opts['data'] = params.data + elif encoding == 'application/octet-stream': + if isinstance(params.data, File): + opts['data'] = params.data.content + else: + opts['data'] = params.data + upload_headers = _get_upload_headers(params.data) + opts['headers'].update(upload_headers) + + request = requests.Request(method, url, **opts) + return session.prepare_request(request) + + +def _coerce_to_error_content(node): + """ + Errors should not contain nested documents or links. + If we get a 4xx or 5xx response with a Document, then coerce + the document content into plain data. + """ + if isinstance(node, (Document, Object)): + # Strip Links from Documents, treat Documents as plain dicts. + return OrderedDict([ + (key, _coerce_to_error_content(value)) + for key, value in node.data.items() + ]) + elif isinstance(node, Array): + # Strip Links from Arrays. + return [ + _coerce_to_error_content(item) + for item in node + if not isinstance(item, Link) + ] + return node + + +def _coerce_to_error(obj, default_title): + """ + Given an arbitrary return result, coerce it into an Error instance. + """ + if isinstance(obj, Document): + return Error( + title=obj.title or default_title, + content=_coerce_to_error_content(obj) + ) + elif isinstance(obj, dict): + return Error(title=default_title, content=obj) + elif isinstance(obj, list): + return Error(title=default_title, content={'messages': obj}) + elif obj is None: + return Error(title=default_title) + return Error(title=default_title, content={'message': obj}) + + +def _decode_result(response, decoders, force_codec=False): + """ + Given an HTTP response, return the decoded Core API document. + """ + if response.content: + # Content returned in response. We should decode it. + if force_codec: + codec = decoders[0] + else: + content_type = response.headers.get('content-type') + codec = utils.negotiate_decoder(decoders, content_type) + + options = { + 'base_url': response.url + } + if 'content-type' in response.headers: + options['content_type'] = response.headers['content-type'] + if 'content-disposition' in response.headers: + options['content_disposition'] = response.headers['content-disposition'] + + result = codec.load(response.content, **options) + else: + # No content returned in response. + result = None + + # Coerce 4xx and 5xx codes into errors. + is_error = response.status_code >= 400 and response.status_code <= 599 + if is_error and not isinstance(result, Error): + default_title = '%d %s' % (response.status_code, response.reason) + result = _coerce_to_error(result, default_title=default_title) + + return result + + +def _handle_inplace_replacements(document, link, link_ancestors): + """ + Given a new document, and the link/ancestors it was created, + determine if we should: + + * Make an inline replacement and then return the modified document tree. + * Return the new document as-is. + """ + if not link.transform: + if link.action.lower() in ('put', 'patch', 'delete'): + transform = 'inplace' + else: + transform = 'new' + else: + transform = link.transform + + if transform == 'inplace': + root = link_ancestors[0].document + keys_to_link_parent = link_ancestors[-1].keys + if document is None: + return root.delete_in(keys_to_link_parent) + return root.set_in(keys_to_link_parent, document) + + return document + + +class HTTPTransport(BaseTransport): + schemes = ['http', 'https'] + + def __init__(self, credentials=None, headers=None, auth=None, session=None, request_callback=None, response_callback=None): + if headers: + headers = {key.lower(): value for key, value in headers.items()} + if session is None: + session = requests.Session() + if auth is not None: + session.auth = auth + if not getattr(session.auth, 'allow_cookies', False): + session.cookies.set_policy(BlockAll()) + + if credentials is not None: + warnings.warn( + "The 'credentials' argument is now deprecated in favor of 'auth'.", + DeprecationWarning + ) + auth = DomainCredentials(credentials) + if request_callback is not None or response_callback is not None: + warnings.warn( + "The 'request_callback' and 'response_callback' arguments are now deprecated. " + "Use a custom 'session' instance instead.", + DeprecationWarning + ) + session.mount('https://', CallbackAdapter(request_callback, response_callback)) + session.mount('http://', CallbackAdapter(request_callback, response_callback)) + + self._headers = itypes.Dict(headers or {}) + self._session = session + + @property + def headers(self): + return self._headers + + def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False): + session = self._session + method = _get_method(link.action) + encoding = _get_encoding(link.encoding) + params = _get_params(method, encoding, link.fields, params) + url = _get_url(link.url, params.path) + headers = _get_headers(url, decoders) + headers.update(self.headers) + + request = _build_http_request(session, url, method, headers, encoding, params) + response = session.send(request) + result = _decode_result(response, decoders, force_codec) + + if isinstance(result, Document) and link_ancestors: + result = _handle_inplace_replacements(result, link, link_ancestors) + + if isinstance(result, Error): + raise exceptions.ErrorMessage(result) + + return result diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreapi/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..fb7ade41dbeb142579a03689a31bbaa7d5878615 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreapi/utils.py @@ -0,0 +1,336 @@ +from coreapi import exceptions +from coreapi.compat import string_types, text_type, urlparse, _TemporaryFileWrapper +from collections import namedtuple +import os +import pkg_resources +import tempfile + + +def domain_matches(request, domain): + """ + Domain string matching against an outgoing request. + Patterns starting with '*' indicate a wildcard domain. + """ + if (domain is None) or (domain == '*'): + return True + + host = urlparse.urlparse(request.url).hostname + if domain.startswith('*'): + return host.endswith(domain[1:]) + return host == domain + + +def get_installed_codecs(): + packages = [ + (package, package.load()) for package in + pkg_resources.iter_entry_points(group='coreapi.codecs') + ] + return { + package.name: cls() for (package, cls) in packages + } + + +# File utilities for upload and download support. + +File = namedtuple('File', 'name content content_type') +File.__new__.__defaults__ = (None,) + + +def is_file(obj): + if isinstance(obj, File): + return True + + if hasattr(obj, '__iter__') and not isinstance(obj, (string_types, list, tuple, dict)): + # A stream object. + return True + + return False + + +def guess_filename(obj): + name = getattr(obj, 'name', None) + if name and isinstance(name, string_types) and name[0] != '<' and name[-1] != '>': + return os.path.basename(name) + return None + + +def guess_extension(content_type): + """ + Python's `mimetypes.guess_extension` is no use because it simply returns + the first of an unordered set. We use the same set of media types here, + but take a reasonable preference on what extension to map to. + """ + return { + 'application/javascript': '.js', + 'application/msword': '.doc', + 'application/octet-stream': '.bin', + 'application/oda': '.oda', + 'application/pdf': '.pdf', + 'application/pkcs7-mime': '.p7c', + 'application/postscript': '.ps', + 'application/vnd.apple.mpegurl': '.m3u', + 'application/vnd.ms-excel': '.xls', + 'application/vnd.ms-powerpoint': '.ppt', + 'application/x-bcpio': '.bcpio', + 'application/x-cpio': '.cpio', + 'application/x-csh': '.csh', + 'application/x-dvi': '.dvi', + 'application/x-gtar': '.gtar', + 'application/x-hdf': '.hdf', + 'application/x-latex': '.latex', + 'application/x-mif': '.mif', + 'application/x-netcdf': '.nc', + 'application/x-pkcs12': '.p12', + 'application/x-pn-realaudio': '.ram', + 'application/x-python-code': '.pyc', + 'application/x-sh': '.sh', + 'application/x-shar': '.shar', + 'application/x-shockwave-flash': '.swf', + 'application/x-sv4cpio': '.sv4cpio', + 'application/x-sv4crc': '.sv4crc', + 'application/x-tar': '.tar', + 'application/x-tcl': '.tcl', + 'application/x-tex': '.tex', + 'application/x-texinfo': '.texinfo', + 'application/x-troff': '.tr', + 'application/x-troff-man': '.man', + 'application/x-troff-me': '.me', + 'application/x-troff-ms': '.ms', + 'application/x-ustar': '.ustar', + 'application/x-wais-source': '.src', + 'application/xml': '.xml', + 'application/zip': '.zip', + 'audio/basic': '.au', + 'audio/mpeg': '.mp3', + 'audio/x-aiff': '.aif', + 'audio/x-pn-realaudio': '.ra', + 'audio/x-wav': '.wav', + 'image/gif': '.gif', + 'image/ief': '.ief', + 'image/jpeg': '.jpe', + 'image/png': '.png', + 'image/svg+xml': '.svg', + 'image/tiff': '.tiff', + 'image/vnd.microsoft.icon': '.ico', + 'image/x-cmu-raster': '.ras', + 'image/x-ms-bmp': '.bmp', + 'image/x-portable-anymap': '.pnm', + 'image/x-portable-bitmap': '.pbm', + 'image/x-portable-graymap': '.pgm', + 'image/x-portable-pixmap': '.ppm', + 'image/x-rgb': '.rgb', + 'image/x-xbitmap': '.xbm', + 'image/x-xpixmap': '.xpm', + 'image/x-xwindowdump': '.xwd', + 'message/rfc822': '.eml', + 'text/css': '.css', + 'text/csv': '.csv', + 'text/html': '.html', + 'text/plain': '.txt', + 'text/richtext': '.rtx', + 'text/tab-separated-values': '.tsv', + 'text/x-python': '.py', + 'text/x-setext': '.etx', + 'text/x-sgml': '.sgml', + 'text/x-vcard': '.vcf', + 'text/xml': '.xml', + 'video/mp4': '.mp4', + 'video/mpeg': '.mpeg', + 'video/quicktime': '.mov', + 'video/webm': '.webm', + 'video/x-msvideo': '.avi', + 'video/x-sgi-movie': '.movie' + }.get(content_type, '') + + +if _TemporaryFileWrapper: + # Ideally we subclass this so that we can present a custom representation. + class DownloadedFile(_TemporaryFileWrapper): + basename = None + + def __repr__(self): + state = "closed" if self.closed else "open" + mode = "" if self.closed else " '%s'" % self.file.mode + return "<DownloadedFile '%s', %s%s>" % (self.name, state, mode) + + def __str__(self): + return self.__repr__() +else: + # On some platforms (eg GAE) the private _TemporaryFileWrapper may not be + # available, just use the standard `NamedTemporaryFile` function + # in this case. + DownloadedFile = tempfile.NamedTemporaryFile + + +# Negotiation utilities. USed to determine which codec or transport class +# should be used, given a list of supported instances. + +def determine_transport(transports, url): + """ + Given a URL determine the appropriate transport instance. + """ + url_components = urlparse.urlparse(url) + scheme = url_components.scheme.lower() + netloc = url_components.netloc + + if not scheme: + raise exceptions.NetworkError("URL missing scheme '%s'." % url) + + if not netloc: + raise exceptions.NetworkError("URL missing hostname '%s'." % url) + + for transport in transports: + if scheme in transport.schemes: + return transport + + raise exceptions.NetworkError("Unsupported URL scheme '%s'." % scheme) + + +def negotiate_decoder(decoders, content_type=None): + """ + Given the value of a 'Content-Type' header, return the appropriate + codec for decoding the request content. + """ + if content_type is None: + return decoders[0] + + content_type = content_type.split(';')[0].strip().lower() + main_type = content_type.split('/')[0] + '/*' + wildcard_type = '*/*' + + for codec in decoders: + for media_type in codec.get_media_types(): + if media_type in (content_type, main_type, wildcard_type): + return codec + + msg = "Unsupported media in Content-Type header '%s'" % content_type + raise exceptions.NoCodecAvailable(msg) + + +def negotiate_encoder(encoders, accept=None): + """ + Given the value of a 'Accept' header, return the appropriate codec for + encoding the response content. + """ + if accept is None: + return encoders[0] + + acceptable = set([ + item.split(';')[0].strip().lower() + for item in accept.split(',') + ]) + + for codec in encoders: + for media_type in codec.get_media_types(): + if media_type in acceptable: + return codec + + for codec in encoders: + for media_type in codec.get_media_types(): + if codec.media_type.split('/')[0] + '/*' in acceptable: + return codec + + if '*/*' in acceptable: + return encoders[0] + + msg = "Unsupported media in Accept header '%s'" % accept + raise exceptions.NoCodecAvailable(msg) + + +# Validation utilities. Used to ensure that we get consistent validation +# exceptions when invalid types are passed as a parameter, rather than +# an exception occuring when the request is made. + +def validate_path_param(value): + value = _validate_form_field(value, allow_list=False) + if not value: + msg = 'Parameter %s: May not be empty.' + raise exceptions.ParameterError(msg) + return value + + +def validate_query_param(value): + return _validate_form_field(value) + + +def validate_body_param(value, encoding): + if encoding == 'application/json': + return _validate_json_data(value) + elif encoding == 'multipart/form-data': + return _validate_form_object(value, allow_files=True) + elif encoding == 'application/x-www-form-urlencoded': + return _validate_form_object(value) + elif encoding == 'application/octet-stream': + if not is_file(value): + msg = 'Must be an file upload.' + raise exceptions.ParameterError(msg) + return value + msg = 'Unsupported encoding "%s" for outgoing request.' + raise exceptions.NetworkError(msg % encoding) + + +def validate_form_param(value, encoding): + if encoding == 'application/json': + return _validate_json_data(value) + elif encoding == 'multipart/form-data': + return _validate_form_field(value, allow_files=True) + elif encoding == 'application/x-www-form-urlencoded': + return _validate_form_field(value) + msg = 'Unsupported encoding "%s" for outgoing request.' + raise exceptions.NetworkError(msg % encoding) + + +def _validate_form_object(value, allow_files=False): + """ + Ensure that `value` can be encoded as form data or as query parameters. + """ + if not isinstance(value, dict): + msg = 'Must be an object.' + raise exceptions.ParameterError(msg) + return { + text_type(item_key): _validate_form_field(item_val, allow_files=allow_files) + for item_key, item_val in value.items() + } + + +def _validate_form_field(value, allow_files=False, allow_list=True): + """ + Ensure that `value` can be encoded as a single form data or a query parameter. + Basic types that has a simple string representation are supported. + A list of basic types is also valid. + """ + if isinstance(value, string_types): + return value + elif isinstance(value, bool) or (value is None): + return {True: 'true', False: 'false', None: ''}[value] + elif isinstance(value, (int, float)): + return "%s" % value + elif allow_list and isinstance(value, (list, tuple)) and not is_file(value): + # Only the top-level element may be a list. + return [ + _validate_form_field(item, allow_files=False, allow_list=False) + for item in value + ] + elif allow_files and is_file(value): + return value + + msg = 'Must be a primitive type.' + raise exceptions.ParameterError(msg) + + +def _validate_json_data(value): + """ + Ensure that `value` can be encoded into JSON. + """ + if (value is None) or isinstance(value, (bool, int, float, string_types)): + return value + elif isinstance(value, (list, tuple)) and not is_file(value): + return [_validate_json_data(item) for item in value] + elif isinstance(value, dict): + return { + text_type(item_key): _validate_json_data(item_val) + for item_key, item_val in value.items() + } + + msg = 'Must be a JSON primitive.' + raise exceptions.ParameterError(msg) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/PKG-INFO b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/PKG-INFO new file mode 100644 index 0000000000000000000000000000000000000000..d1309a580ae38c6dec3de39ff58f1f4c86b5bfad --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/PKG-INFO @@ -0,0 +1,15 @@ +Metadata-Version: 2.1 +Name: coreschema +Version: 0.0.4 +Summary: Core Schema. +Home-page: https://github.com/core-api/python-coreschema +Author: Tom Christie +Author-email: tom@tomchristie.com +License: BSD +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/SOURCES.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/SOURCES.txt new file mode 100644 index 0000000000000000000000000000000000000000..76ed7754d8c58ed0ff9ef57671ff902fdf13cf26 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/SOURCES.txt @@ -0,0 +1,24 @@ +setup.cfg +setup.py +coreschema/__init__.py +coreschema/compat.py +coreschema/formats.py +coreschema/schemas.py +coreschema/utils.py +coreschema.egg-info/PKG-INFO +coreschema.egg-info/SOURCES.txt +coreschema.egg-info/dependency_links.txt +coreschema.egg-info/requires.txt +coreschema.egg-info/top_level.txt +coreschema/encodings/__init__.py +coreschema/encodings/corejson.py +coreschema/encodings/html.py +coreschema/encodings/jsonschema.py +coreschema/templates/base.html +coreschema/templates/form.html +coreschema/templates/bootstrap3/form.html +coreschema/templates/bootstrap3/inputs/checkbox.html +coreschema/templates/bootstrap3/inputs/input.html +coreschema/templates/bootstrap3/inputs/select.html +coreschema/templates/bootstrap3/inputs/select_multiple.html +coreschema/templates/bootstrap3/inputs/textarea.html \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/dependency_links.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/dependency_links.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/installed-files.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/installed-files.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc415e4f70001a7cb4b8c284e1b9653fe146e6f6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/installed-files.txt @@ -0,0 +1,31 @@ +..\coreschema\__init__.py +..\coreschema\__pycache__\__init__.cpython-310.pyc +..\coreschema\__pycache__\compat.cpython-310.pyc +..\coreschema\__pycache__\formats.cpython-310.pyc +..\coreschema\__pycache__\schemas.cpython-310.pyc +..\coreschema\__pycache__\utils.cpython-310.pyc +..\coreschema\compat.py +..\coreschema\encodings\__init__.py +..\coreschema\encodings\__pycache__\__init__.cpython-310.pyc +..\coreschema\encodings\__pycache__\corejson.cpython-310.pyc +..\coreschema\encodings\__pycache__\html.cpython-310.pyc +..\coreschema\encodings\__pycache__\jsonschema.cpython-310.pyc +..\coreschema\encodings\corejson.py +..\coreschema\encodings\html.py +..\coreschema\encodings\jsonschema.py +..\coreschema\formats.py +..\coreschema\schemas.py +..\coreschema\templates\base.html +..\coreschema\templates\bootstrap3\form.html +..\coreschema\templates\bootstrap3\inputs\checkbox.html +..\coreschema\templates\bootstrap3\inputs\input.html +..\coreschema\templates\bootstrap3\inputs\select.html +..\coreschema\templates\bootstrap3\inputs\select_multiple.html +..\coreschema\templates\bootstrap3\inputs\textarea.html +..\coreschema\templates\form.html +..\coreschema\utils.py +PKG-INFO +SOURCES.txt +dependency_links.txt +requires.txt +top_level.txt diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/requires.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/requires.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f7afbf3bf54b346092be6a72070fcbd305ead1e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/requires.txt @@ -0,0 +1 @@ +jinja2 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f7a1faa1f582672651c4881b677a1062d9867cd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema-0.0.4-py3.10.egg-info/top_level.txt @@ -0,0 +1,2 @@ +coreschema +coreschema\encodings diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ccbc0cee65ee3ddcd4f5d908c8d171252c45c34d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__init__.py @@ -0,0 +1,16 @@ +from coreschema.schemas import ( + Object, Array, Integer, Number, String, Boolean, Null, + Enum, Anything, Ref, RefSpace, + Union, Intersection, ExclusiveUnion, Not +) +from coreschema.encodings.html import render_to_form + + +__version__ = '0.0.4' + +__all__ = [ + Object, Array, Integer, Number, String, Boolean, Null, + Enum, Anything, Ref, RefSpace, + Union, Intersection, ExclusiveUnion, Not, + render_to_form +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dee6aef8416a174e917477d8b045595115ab36df Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b1b4bc48c5f2313670f43261ffbeac114e95b4b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/formats.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/formats.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3256b2da329320a4cd3081643efaedfdbf76fe12 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/formats.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/schemas.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/schemas.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc6676d74da9c376c839f045571078802ad81b36 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/schemas.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fee902a4a2a66ed678201c2ab338534ddaf6023 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..a998663922aa9ced22c226e4f87b28f5ce2b7db5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/compat.py @@ -0,0 +1,8 @@ +import sys + +if sys.version_info.major == 2: + text_types = (str, unicode) + numeric_types = (float, int, long) +else: + text_types = (str,) + numeric_types = (float, int) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2931c99f80d54aae2d9d32f5342a5c0e9ffc10f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/corejson.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/corejson.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37c83209c9195597cb978e9ffb9dd2a582a83ec6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/corejson.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/html.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/html.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34d09da511455b5455f4470d9c30f9df8ae70d8b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/html.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/jsonschema.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/jsonschema.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b6d9ce3f109df8e460cd3a2ce6449ad50403e59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/__pycache__/jsonschema.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/corejson.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/corejson.py new file mode 100644 index 0000000000000000000000000000000000000000..ad2b4607bf5928f99e91dcc29bbb54dbe6fe7040 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/corejson.py @@ -0,0 +1,19 @@ +jsonschema = coreschema.RefSpace({ + 'Document': coreschema.Object( + properties={ + '_type': coreschema.Enum(['document']), + '_meta': coreschema.Object( + properties={ + 'url': coreschema.String(), + 'title': coreschema.String(), + 'description': coreschema.String(), + } + ) + } + ), + 'Link': coreschema.Object( + properties={ + '_type': coreschema.Enum(['link']) + } + ) +}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/html.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/html.py new file mode 100644 index 0000000000000000000000000000000000000000..4cad462aca1778ae9fc5e87ea72abc0708f681d9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/html.py @@ -0,0 +1,74 @@ +from coreschema import Object, Array, String, Integer, Number, Boolean, Enum +import jinja2 + + +env = jinja2.Environment(loader=jinja2.PackageLoader('coreschema', 'templates')) + + +# TODO: required +# TODO: initial values, errors, input control + + +def render_to_form(schema): + template = env.get_template('form.html') + return template.render({ + 'parent': schema, + 'determine_html_template': determine_html_template, + 'get_textarea_value': get_textarea_value, + 'get_attrs': get_attrs + }) + + +def determine_html_template(schema): + if isinstance(schema, Array): + if schema.unique_items and isinstance(schema.items, Enum): + # Actually only for *unordered* input + return 'bootstrap3/inputs/select_multiple.html' + # TODO: Comma seperated inputs + return 'bootstrap3/inputs/textarea.html' + elif isinstance(schema, Object): + # TODO: Fieldsets + return 'bootstrap3/inputs/textarea.html' + elif isinstance(schema, Number): + return 'bootstrap3/inputs/input.html' + elif isinstance(schema, Boolean): + # TODO: nullable boolean + return 'bootstrap3/inputs/checkbox.html' + elif isinstance(schema, Enum): + # TODO: display values + return 'bootstrap3/inputs/select.html' + # String: + if schema.format == 'textarea': + return 'bootstrap3/inputs/textarea.html' + return 'bootstrap3/inputs/input.html' + + +def get_textarea_value(schema): + if isinstance(schema, Array): + return "[ ]" + elif isinstance(schema, Object): + return "{ }" + return "" + + +def get_attrs(schema): + if isinstance(schema, Array): + # TODO: Add data-child-type and use with selects + return "data-empty=[] data-type='array'" + elif isinstance(schema, Object): + return "data-empty={} data-type='object'" + elif isinstance(schema, Integer): + return "data-empty=null data-type='integer' type='number' step=1" + elif isinstance(schema, Number): + return "data-empty=null data-type='number' type='number' step=any" + elif isinstance(schema, Boolean): + return "data-empty=false data-type='boolean'" + elif isinstance(schema, Enum): + # TODO: Non-string Enum + return "data-empty='' data-type='string'" + # String: + if schema.format: + # TODO: Only include valid HTML5 formats. + # Coerce datetime to datetime-local. + return "data-empty='' data-type='string' type='%s'" % schema.format + return "data-empty='' data-type='string'" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/jsonschema.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/jsonschema.py new file mode 100644 index 0000000000000000000000000000000000000000..df6e76b6e7e015c2d258896deed1732509169fc4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/encodings/jsonschema.py @@ -0,0 +1,215 @@ +from coreschema.compat import text_types +import coreschema +import re + + +jsonschema = coreschema.RefSpace({ + 'Schema': coreschema.Object( + properties={ + # Meta + 'id': coreschema.String(format='uri'), + '$schema': coreschema.String(format='uri'), + 'title': coreschema.String(), + 'description': coreschema.String(), + 'default': coreschema.Anything(), + 'definitions': coreschema.Ref('SchemaMap'), + # Type + 'type': coreschema.Ref('SimpleTypes') | coreschema.Array(items=coreschema.Ref('SimpleTypes'), min_items=1, unique_items=True), + # Number validators + 'minimum': coreschema.Number(), + 'maximum': coreschema.Number(), + 'exclusiveMinimum': coreschema.Boolean(default=False), + 'exclusiveMaximum': coreschema.Boolean(default=False), + 'multipleOf': coreschema.Number(minimum=0, exclusive_minimum=True), + # String validators + 'minLength': coreschema.Integer(minimum=0, default=0), + 'maxLength': coreschema.Integer(minimum=0), + 'pattern': coreschema.String(format='regex'), + 'format': coreschema.String(), + # Array validators + 'items': coreschema.Ref('Schema') | coreschema.Ref('SchemaArray'), # TODO: default={} + 'additionalItems': coreschema.Boolean() | coreschema.Ref('Schema'), # TODO: default={} + 'minItems': coreschema.Integer(minimum=0, default=0), + 'maxItems': coreschema.Integer(minimum=0), + 'uniqueItems': coreschema.Boolean(default=False), + # Object validators + 'properties': coreschema.Ref('SchemaMap'), + 'patternProperties': coreschema.Ref('SchemaMap'), + 'additionalProperties': coreschema.Boolean() | coreschema.Ref('Schema'), + 'minProperties': coreschema.Integer(minimum=0, default=0), + 'maxProperties': coreschema.Integer(minimum=0), + 'required': coreschema.Ref('StringArray'), + 'dependancies': coreschema.Object(additional_properties=coreschema.Ref('Schema') | coreschema.Ref('StringArray')), + # Enum validators + 'enum': coreschema.Array(min_items=1, unique_items=True), + # Composites + 'allOf': coreschema.Ref('SchemaArray'), + 'anyOf': coreschema.Ref('SchemaArray'), + 'oneOf': coreschema.Ref('SchemaArray'), + 'not': coreschema.Ref('Schema') + }, + # dependancies=..., TODO + default={}, + ), + 'SchemaArray': coreschema.Array( + items=coreschema.Ref('Schema'), + min_items=1, + ), + 'SchemaMap': coreschema.Object( + additional_properties=coreschema.Ref('Schema'), + default={}, + ), + 'SimpleTypes': coreschema.Enum( + enum=['array', 'boolean', 'integer', 'null', 'number', 'object', 'string'] + ), + 'StringArray': coreschema.Array( + items=coreschema.String(), + min_items=1, + unique_items=True, + ) +}, root='Schema') + + +KEYWORD_TO_TYPE = { + 'minimum': 'number', + 'maximum': 'number', + 'exclusiveMinimum': 'number', + 'exclusiveMaximum': 'number', + 'multipleOf': 'number', + # + 'minLength': 'string', + 'maxLength': 'string', + 'pattern': 'string', + 'format': 'string', + # + 'items': 'array', + 'maxItems': 'array', + 'minItems': 'array', + 'uniqueItems': 'array', + 'additionalItems': 'array', + # + 'properties': 'object', + 'maxProperties': 'object', + 'minProperties': 'object', + 'additionalProperties': 'object', + 'patternProperties': 'object', + 'required': 'object', +} +TYPE_NAMES = [ + 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string' +] +CLS_MAP = { + 'array': coreschema.Array, + 'boolean': coreschema.Boolean, + 'integer': coreschema.Integer, + 'null': coreschema.Null, + 'number': coreschema.Number, + 'object': coreschema.Object, + 'string': coreschema.String, +} + + +def camelcase_to_snakecase(name): + s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + + +def get_typed_schemas(data): + """ + Return a list of schemas for any primitive type restrictions. + """ + has_type = False + type_kwargs = {type_name: {} for type_name in TYPE_NAMES} + for keyword, value in data.items(): + if keyword not in KEYWORD_TO_TYPE: + continue + + # Load any nested schemas + if keyword == 'items' and isinstance(value, dict): + value = load_jsonschema(value) + elif keyword == 'items' and isinstance(value, list): + value = [load_jsonschema(item) for item in value] + elif keyword == 'additionalItems' and isinstance(value, dict): + value = load_jsonschema(value) + elif keyword == 'properties' and isinstance(value, dict): + value = {key: load_jsonschema(item) for key, item in value.items()} + elif keyword == 'additionalProperties' and isinstance(value, dict): + value = load_jsonschema(value) + elif keyword == 'patternProperties' and isinstance(value, dict): + value = {key: load_jsonschema(item) for key, item in value.items()} + + type_name = KEYWORD_TO_TYPE[keyword] + has_type = True + argument_name = camelcase_to_snakecase(keyword) + type_kwargs[type_name][argument_name] = value + + type_kwargs['integer'] = type_kwargs['number'] + + if 'type' in data: + has_type = True + types = data.get('type') + types = types if isinstance(types, list) else [types] + for type_name in list(type_kwargs.keys()): + if type_name not in types: + type_kwargs.pop(type_name) + + schemas = [] + if has_type: + for type_name, kwargs in type_kwargs.items(): + cls = CLS_MAP[type_name] + schemas.append(cls(**kwargs)) + + return schemas + + +def get_composite_schemas(data): + schemas = [] + if 'anyOf' in data: + value = data['anyOf'] + schema = coreschema.Union([ + load_jsonschema(item) for item in value + ]) + schemas.append(schema) + if 'allOf' in data: + value = data['allOf'] + schema = coreschema.Intersection([ + load_jsonschema(item) for item in value + ]) + schemas.append(schema) + if 'oneOf' in data: + value = data['oneOf'] + schema = coreschema.ExclusiveUnion([ + load_jsonschema(item) for item in value + ]) + schemas.append(schema) + if 'not' in data: + value = data['not'] + schema = coreschema.Not(load_jsonschema(value)) + schemas.append(schema) + return schemas + + + +def load_jsonschema(data): + schemas = get_typed_schemas(data) + if len(schemas) > 1: + schemas = [coreschema.Union(schemas)] + schemas += get_composite_schemas(data) + + if not schemas: + schema = coreschema.Anything() + elif len(schemas) == 1: + schema = schemas[0] + else: + schema = coreschema.Intersection(schemas) + + if 'enum' in data: + # Restrict enum values by any existing type constraints, + # and then use an Enum type. + enum_values = [ + value for value in data['enum'] + if schema.validate(value) == [] + ] + return coreschema.Enum(enum_values) + + return schema diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/formats.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/formats.py new file mode 100644 index 0000000000000000000000000000000000000000..2b5417a9e5f4b84c83adfc2d59d5f1660573437f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/formats.py @@ -0,0 +1,25 @@ +import re + + +email_pattern = re.compile('^[^@]+@[^@]') +uri_pattern = re.compile('^[A-Za-z][A-Za-z0-9+.-]+:') + + +def validate_format(value, format): + function = { + 'email': validate_email, + 'uri': validate_uri + }.get(format, unknown_format) + return function(value) + + +def unknown_format(value): + return value + + +def validate_email(value): + return bool(re.match(email_pattern, value)) + + +def validate_uri(value): + return bool(re.match(uri_pattern, value)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/schemas.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/schemas.py new file mode 100644 index 0000000000000000000000000000000000000000..8a6038022987b96ddb7bc355f9092717937ef1ac --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/schemas.py @@ -0,0 +1,506 @@ +from collections import namedtuple +from coreschema.compat import text_types, numeric_types +from coreschema.formats import validate_format +from coreschema.utils import uniq +import re + + +Error = namedtuple('Error', ['text', 'index']) + + +def push_index(errors, key): + return [ + Error(error.text, [key] + error.index) + for error in errors + ] + + +# TODO: Properties as OrderedDict if from list of tuples. +# TODO: null keyword / Nullable +# TODO: dependancies +# TODO: remote ref +# TODO: remaining formats +# LATER: Enum display values +# LATER: File +# LATER: strict, coerce float etc... +# LATER: decimals +# LATER: override errors + + +class Schema(object): + errors = {} + + def __init__(self, title='', description='', default=None): + self.title = title + self.description = description + self.default = default + + def make_error(self, code): + error_string = self.errors[code] + params = self.__dict__ + return Error(error_string.format(**params), []) + + def __or__(self, other): + if isinstance(self, Union): + self_children = self.children + else: + self_children = [self] + + if isinstance(other, Union): + other_children = other.children + else: + other_children = [other] + + return Union(self_children + other_children) + + def __and__(self, other): + if isinstance(self, Intersection): + self_children = self.children + else: + self_children = [self] + + if isinstance(other, Intersection): + other_children = other.children + else: + other_children = [other] + + return Intersection(self_children + other_children) + + def __xor__(self, other): + return ExclusiveUnion([self, other]) + + def __invert__(self): + return Not(self) + + def __eq__(self, other): + return ( + self.__class__ == other.__class__ and + self.__dict__ == other.__dict__ + ) + + +class Object(Schema): + errors = { + 'type': 'Must be an object.', + 'invalid_key': 'Object keys must be strings.', + 'empty': 'Must not be empty.', + 'required': 'This field is required.', + 'max_properties': 'Must have no more than {max_properties} properties.', + 'min_properties': 'Must have at least {min_properties} properties.', + 'invalid_property': 'Invalid property.' + } + + def __init__(self, properties=None, required=None, max_properties=None, min_properties=None, pattern_properties=None, additional_properties=True, **kwargs): + super(Object, self).__init__(**kwargs) + + if isinstance(additional_properties, bool): + # Handle `additional_properties` set to a boolean. + self.additional_properties_schema = Anything() + else: + # Handle `additional_properties` set to a schema. + self.additional_properties_schema = additional_properties + additional_properties = True + + self.properties = properties + self.required = required or [] + self.max_properties = max_properties + self.min_properties = min_properties + self.pattern_properties = pattern_properties + self.additional_properties = additional_properties + + # Compile pattern regexes. + self.pattern_properties_regex = None + if pattern_properties is not None: + self.pattern_properties_regex = { + re.compile(key): value + for key, value + in pattern_properties.items() + } + + def validate(self, value, context=None): + if not isinstance(value, dict): + return [self.make_error('type')] + + errors = [] + if any(not isinstance(key, text_types) for key in value.keys()): + errors += [self.make_error('invalid_key')] + if self.required is not None: + for key in self.required: + if key not in value: + error_items = [self.make_error('required')] + errors += push_index(error_items, key) + if self.min_properties is not None: + if len(value) < self.min_properties: + if self.min_properties == 1: + errors += [self.make_error('empty')] + else: + errors += [self.make_error('min_properties')] + if self.max_properties is not None: + if len(value) > self.max_properties: + errors += [self.make_error('max_properties')] + + # Properties + remaining_keys = set(value.keys()) + if self.properties is not None: + remaining_keys -= set(self.properties.keys()) + for key, property_item in self.properties.items(): + if key not in value: + continue + error_items = property_item.validate(value[key], context) + errors += push_index(error_items, key) + + # Pattern properties + if self.pattern_properties is not None: + for key in list(remaining_keys): + for pattern, schema in self.pattern_properties_regex.items(): + if re.search(pattern, key): + error_items = schema.validate(value[key], context) + errors += push_index(error_items, key) + remaining_keys.discard(key) + + # Additional properties + if self.additional_properties: + for key in remaining_keys: + error_items = self.additional_properties_schema.validate(value[key], context) + errors += push_index(error_items, key) + else: + for key in remaining_keys: + error_items = [self.make_error('invalid_property')] + errors += push_index(error_items, key) + + return errors + + +class Array(Schema): + errors = { + 'type': 'Must be an array.', + 'empty': 'Must not be empty.', + 'max_items': 'Must have no more than {max_items} items.', + 'min_items': 'Must have at least {min_items} items.', + 'unique': 'Must not contain duplicate items.' + } + + def __init__(self, items=None, max_items=None, min_items=None, unique_items=False, additional_items=True, **kwargs): + super(Array, self).__init__(**kwargs) + + if items is None: + items = Anything() + + if isinstance(items, list) and additional_items is False: + # Setting additional_items==False implies a value for max_items. + if max_items is None or max_items > len(items): + max_items = len(items) + + self.items = items + self.max_items = max_items + self.min_items = min_items + self.unique_items = unique_items + self.additional_items = additional_items + + def validate(self, value, context=None): + if not isinstance(value, list): + return [self.make_error('type')] + + errors = [] + if self.items is not None: + child_schema = self.items + is_list = isinstance(self.items, list) + for idx, item in enumerate(value): + if is_list: + # Case where `items` is a list of schemas. + if idx < len(self.items): + # Handle each item in the list. + child_schema = self.items[idx] + else: + # Handle any additional items. + if isinstance(self.additional_items, bool): + break + else: + child_schema = self.additional_items + error_items = child_schema.validate(item, context) + errors += push_index(error_items, idx) + if self.min_items is not None: + if len(value) < self.min_items: + if self.min_items == 1: + errors += [self.make_error('empty')] + else: + errors += [self.make_error('min_items')] + if self.max_items is not None: + if len(value) > self.max_items: + errors += [self.make_error('max_items')] + if self.unique_items: + if not(uniq(value)): + errors += [self.make_error('unique')] + + return errors + + +class Number(Schema): + integer_only = False + errors = { + 'type': 'Must be a number.', + 'minimum': 'Must be greater than or equal to {minimum}.', + 'exclusive_minimum': 'Must be greater than {minimum}.', + 'maximum': 'Must be less than or equal to {maximum}.', + 'exclusive_maximum': 'Must be less than {maximum}.', + 'multiple_of': 'Must be a multiple of {multiple_of}.', + } + + def __init__(self, minimum=None, maximum=None, exclusive_minimum=False, exclusive_maximum=False, multiple_of=None, **kwargs): + super(Number, self).__init__(**kwargs) + self.minimum = minimum + self.maximum = maximum + self.exclusive_minimum = exclusive_minimum + self.exclusive_maximum = exclusive_maximum + self.multiple_of = multiple_of + + def validate(self, value, context=None): + if isinstance(value, bool): + # In Python `bool` subclasses `int`, so handle that case explicitly. + return [self.make_error('type')] + if not isinstance(value, numeric_types): + return [self.make_error('type')] + if self.integer_only and isinstance(value, float) and not value.is_integer(): + return [self.make_error('type')] + + errors = [] + if self.minimum is not None: + if self.exclusive_minimum: + if value <= self.minimum: + errors += [self.make_error('exclusive_minimum')] + else: + if value < self.minimum: + errors += [self.make_error('minimum')] + if self.maximum is not None: + if self.exclusive_maximum: + if value >= self.maximum: + errors += [self.make_error('exclusive_maximum')] + else: + if value > self.maximum: + errors += [self.make_error('maximum')] + if self.multiple_of is not None: + if isinstance(self.multiple_of, float): + failed = not (float(value) / self.multiple_of).is_integer() + else: + failed = value % self.multiple_of + if failed: + errors += [self.make_error('multiple_of')] + return errors + + +class Integer(Number): + errors = { + 'type': 'Must be an integer.', + 'minimum': 'Must be greater than or equal to {minimum}.', + 'exclusive_minimum': 'Must be greater than {minimum}.', + 'maximum': 'Must be less than or equal to {maximum}.', + 'exclusive_maximum': 'Must be less than {maximum}.', + 'multiple_of': 'Must be a multiple of {multiple_of}.', + } + integer_only = True + + +class String(Schema): + errors = { + 'type': 'Must be a string.', + 'blank': 'Must not be blank.', + 'max_length': 'Must have no more than {max_length} characters.', + 'min_length': 'Must have at least {min_length} characters.', + 'pattern': 'Must match the pattern /{pattern}/.', + 'format': 'Must be a valid {format}.', + } + + def __init__(self, max_length=None, min_length=None, pattern=None, format=None, **kwargs): + super(String, self).__init__(**kwargs) + self.max_length = max_length + self.min_length = min_length + self.pattern = pattern + self.format = format + + self.pattern_regex = None + if self.pattern is not None: + self.pattern_regex = re.compile(pattern) + + def validate(self, value, context=None): + if not isinstance(value, text_types): + return [self.make_error('type')] + + errors = [] + if self.min_length is not None: + if len(value) < self.min_length: + if self.min_length == 1: + errors += [self.make_error('blank')] + else: + errors += [self.make_error('min_length')] + if self.max_length is not None: + if len(value) > self.max_length: + errors += [self.make_error('max_length')] + if self.pattern is not None: + if not re.search(self.pattern_regex, value): + errors += [self.make_error('pattern')] + if self.format is not None: + if not validate_format(value, self.format): + errors += [self.make_error('format')] + return errors + + +class Boolean(Schema): + errors = { + 'type': 'Must be a boolean.' + } + + def validate(self, value, context=None): + if not isinstance(value, bool): + return [self.make_error('type')] + return [] + + +class Null(Schema): + errors = { + 'type': 'Must be null.' + } + + def validate(self, value, context=None): + if value is not None: + return [self.make_error('type')] + return [] + + +class Enum(Schema): + errors = { + 'enum': 'Must be one of {enum}.', + 'exact': 'Must be {exact}.', + } + + def __init__(self, enum, **kwargs): + super(Enum, self).__init__(**kwargs) + + self.enum = enum + if len(enum) == 1: + self.exact = repr(enum[0]) + + def validate(self, value, context=None): + if value not in self.enum: + if len(self.enum) == 1: + return [self.make_error('exact')] + return [self.make_error('enum')] + return [] + + +class Anything(Schema): + errors = { + 'type': 'Must be a valid primitive type.' + } + types = text_types + (dict, list, int, float, bool, type(None)) + + def validate(self, value, context=None): + if not isinstance(value, self.types): + return [self.make_error('type')] + + errors = [] + if isinstance(value, list): + schema = Array() + errors += schema.validate(value, context) + elif isinstance(value, dict): + schema = Object() + errors += schema.validate(value, context) + return errors + + +# Composites + +class Union(Schema): + errors = { + 'match': 'Must match one of the options.' + } + + def __init__(self, children, **kwargs): + super(Union, self).__init__(**kwargs) + + self.children = children + + def validate(self, value, context=None): + for child in self.children: + if child.validate(value, context) == []: + return [] + return [self.make_error('match')] + + +class Intersection(Schema): + def __init__(self, children, **kwargs): + super(Intersection, self).__init__(**kwargs) + self.children = children + + def validate(self, value, context=None): + errors = [] + for child in self.children: + errors.extend(child.validate(value, context)) + return errors + + +class ExclusiveUnion(Schema): + errors = { + 'match': 'Must match one of the options.', + 'match_only_one': 'Must match only one of the options.' + } + + def __init__(self, children, **kwargs): + super(ExclusiveUnion, self).__init__(**kwargs) + + self.children = children + + def validate(self, value, context=None): + matches = 0 + for child in self.children: + if child.validate(value, context) == []: + matches += 1 + if not matches: + return [self.make_error('match')] + elif matches > 1: + return [self.make_error('match_only_one')] + return [] + + +class Not(Schema): + errors = { + 'must_not_match': 'Must not match the option.' + } + + def __init__(self, child, **kwargs): + super(Not, self).__init__(**kwargs) + self.child = child + + def validate(self, value, context=None): + errors = [] + if self.child.validate(value, context): + return [] + return [self.make_error('must_not_match')] + + +# References + +class Ref(Schema): + def __init__(self, ref_name): + self.ref_name = ref_name + + def dereference(self, context): + assert isinstance(context, dict) + assert 'refs' in context + assert self.ref_name in context['refs'] + return context['refs'][self.ref_name] + + def validate(self, value, context=None): + schema = self.dereference(context) + return schema.validate(value, context) + + +class RefSpace(Schema): + def __init__(self, refs, root): + assert root in refs + self.refs = refs + self.root = root + self.root_validator = refs[root] + + def validate(self, value): + context = {'refs': self.refs} + return self.root_validator.validate(value, context) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/base.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/base.html new file mode 100644 index 0000000000000000000000000000000000000000..e1431be8ba24eccb1898955986fa52434081bf63 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/base.html @@ -0,0 +1,162 @@ + +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> + <meta name="description" content=""> + <meta name="author" content=""> + <link rel="icon" href="../../favicon.ico"> + + <title>Theme Template for Bootstrap</title> + + <!-- Bootstrap core CSS --> + <link href="../../dist/css/bootstrap.min.css" rel="stylesheet"> + <!-- Bootstrap theme --> + <link href="../../dist/css/bootstrap-theme.min.css" rel="stylesheet"> + <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> + <link href="../../assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> + + <!-- Custom styles for this template --> + <link href="theme.css" rel="stylesheet"> + <link href="chosen.css" rel="stylesheet"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + + <style> + .checkbox label.control-label {font-weight: bold} + body {padding-top: 0} + </style> + </head> + + <body> + <div class="container col-md-4 col-md-offset-4" role="main"> + <h1>CoreSchema</h1> + <form id="coreschema" novalidate> + {% for key, schema in parent.properties.items() %} + {% set template_path = determine_html_template(schema) %} + {% set required = key in parent.required %} + {% include template_path %} + {% endfor %} + </form> + <pre> + </pre> + </div> <!-- /container --> + + + <!-- Bootstrap core JavaScript + ================================================== --> + <!-- Placed at the end of the document so the pages load faster --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> + <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script> + <script src="../../dist/js/bootstrap.min.js"></script> + <script src="../../assets/js/docs.min.js"></script> + <script src="chosen.jquery.js"></script> + <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> + <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script> + <script> + const options = { + placeholder_text_single: '', + placeholder_text_multiple: '', + allow_single_deselect: true + } + $('select').chosen(options) + + $('#coreschema :input').on('input propertychange', function() { + const form = $(this).closest('form') + formToData(form) + }) + $('#coreschema :input').change(function() { + const form = $(this).closest('form') + formToData(form) + }) + + function formToData(form) { + const formData = new FormData(form.get()[0]) + var params = new Map() + var errors = [] + var inputElements = {} + + // Initially iterate through all the inputs + form.find(':input').each(function(key, value) { + var elem = $(this) + var name = elem.attr('name') + if (name !== undefined) { + inputElements[name] = elem + var emptyValue = elem.data('empty') + if (emptyValue !== undefined) { + params[name] = emptyValue + } + } + }) + + // Now iterate through all the supplied form values + for (let [paramKey, paramValue] of formData.entries()) { + let inputElement = inputElements[paramKey] + let dataType = inputElement.data('type') + try { + if (!inputElement[0].checkValidity()) { + // Invalid inputs return paramValue of '', + // so we need to differentiate between that + // and an actually empty input + throw Error() + } else if (dataType === 'integer') { + if (!paramValue) { + params[paramKey] = null + } else { + if (paramValue.includes('.')) { + throw Error() + } + paramValue = parseInt(paramValue) + if (paramValue != paramValue) { + throw Error() + } + params[paramKey] = paramValue + } + } else if (dataType === 'number') { + if (!paramValue) { + params[paramKey] = null + } else { + paramValue = parseFloat(paramValue) + if (paramValue != paramValue) { + throw Error() + } + params[paramKey] = paramValue + } + } else if (dataType === 'boolean') { + params[paramKey] = true + } else if (dataType === 'array') { + if (inputElement.is('select')) { + params[paramKey] = params[paramKey].concat([paramValue]) + } else { + params[paramKey] = JSON.parse(paramValue) + } + } else if (dataType === 'object') { + params[paramKey] = JSON.parse(paramValue) + } else { + params[paramKey] = paramValue + } + } catch(e) { + errors.push(paramKey) + } + } + + form.find('.form-group').removeClass('has-error') + for (let name of errors) { + let inputElement = inputElements[name] + let formGroup = inputElement.closest('.form-group') + formGroup.addClass('has-error') + } + + const text = JSON.stringify(params, null, 2) + form.next('pre').text(text) + } + </script> + </body> +</html> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/form.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/form.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/checkbox.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/checkbox.html new file mode 100644 index 0000000000000000000000000000000000000000..047e77fb9156eb462353b57829f6891b95132dd9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/checkbox.html @@ -0,0 +1,14 @@ +<div class="form-group"> + <div class="checkbox"> + <label class="control-label"> + <input type="checkbox" name="{{ key }}" value="true" {{ get_attrs(schema) }}> + {{ schema.title or key }} + {% if required %} + <span class="text-danger">*</span> + {% endif %} + </label> + </div> + {% if schema.description %} + <span class="help-block">{{ schema.description }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/input.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/input.html new file mode 100644 index 0000000000000000000000000000000000000000..41c14777df9539f244abe7533d6a2dd85234d6a4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/input.html @@ -0,0 +1,12 @@ +<div class="form-group"> + <label for="{{ key }}" class="control-label"> + {{ schema.title or key }} + {% if required %} + <span class="text-danger">*</span> + {% endif %} + </label> + <input name="{{ key }}" class="form-control" {{ get_attrs(schema) }} {% if required %}required{% endif %}> + {% if schema.description %} + <p class="help-block">{{ schema.description }}</p> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select.html new file mode 100644 index 0000000000000000000000000000000000000000..6f4a7256d22b46b134d9183dd73cf5c32c24ee9f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select.html @@ -0,0 +1,16 @@ +<div class="form-group"> + <label> + {{ schema.title or key }} + </label> + + <select class="form-control" name="{{ key }}" {{ get_attrs(schema) }}> + <option></option> + {% for value in schema.enum %} + <option value="{{ value }}">{{ value }}</option> + {% endfor %} + </select> + + {% if schema.description %} + <span class="help-block">{{ schema.description }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..5126848664a4c5c4afc452632ae979ab40978de2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/select_multiple.html @@ -0,0 +1,15 @@ +<div class="form-group"> + <label> + {{ schema.title or key }} + </label> + + <select class="form-control" name="{{ key }}" {{ get_attrs(schema) }} multiple> + {% for value in schema.items.enum %} + <option value="{{ value }}">{{ value }}</option> + {% endfor %} + </select> + + {% if schema.description %} + <span class="help-block">{{ schema.description }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/textarea.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/textarea.html new file mode 100644 index 0000000000000000000000000000000000000000..172a3d7ecd4de95d05d17d6474a2dd37ba55483e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/bootstrap3/inputs/textarea.html @@ -0,0 +1,12 @@ +<div class="form-group"> + <label for="{{ key }}" class="control-label"> + {{ schema.title or key }} + {% if required %} + <span class="text-danger">*</span> + {% endif %} + </label> + <textarea name="{{ key }}" class="form-control" {{ get_attrs(schema) }} {% if required %}required{% endif %}>{{ get_textarea_value(schema) }}</textarea> + {% if schema.description %} + <p class="help-block">{{ schema.description }}</p> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/form.html b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/form.html new file mode 100644 index 0000000000000000000000000000000000000000..f9b0995a613483ebde0b7496ffa71e416203cce2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/templates/form.html @@ -0,0 +1,5 @@ +{% for key, schema in parent.properties.items() %} + {% set template_path = determine_html_template(schema) %} + {% set required = key in parent.required %} + {% include template_path %} +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/coreschema/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1b64d1931d4222da2a0a0671fa54d656d72896f0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/coreschema/utils.py @@ -0,0 +1,63 @@ +# This `uniq` implementation is taken from the Python `jsonschema` package. +# +# https://github.com/Julian/jsonschema +# +# Copyright (c) 2013 Julian Berman +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +import itertools + + +def unbool(element, true=object(), false=object()): + """ + A hack to make True and 1 and False and 0 unique for ``uniq``. + """ + + if element is True: + return true + elif element is False: + return false + return element + + +def uniq(container): + """ + Check if all of a container's elements are unique. + Successively tries first to rely that the elements are hashable, then + falls back on them being sortable, and finally falls back on brute + force. + """ + + try: + return len(set(unbool(i) for i in container)) == len(container) + except TypeError: + try: + sort = sorted(unbool(i) for i in container) + sliced = itertools.islice(sort, 1, None) + for i, j in zip(sort, sliced): + if i == j: + return False + except (NotImplementedError, TypeError): + seen = [] + for e in container: + e = unbool(e) + if e in seen: + return False + seen.append(e) + return True diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..07074259b61a65feff513bce8b3bd31b30426758 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE @@ -0,0 +1,6 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made +under the terms of *both* these licenses. + +The code used in the OS random engine is derived from CPython, and is licensed +under the terms of the PSF License Agreement. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.APACHE b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.APACHE new file mode 100644 index 0000000000000000000000000000000000000000..62589edd12a37dd28b6b6fed1e2d728ac9f05c8d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.BSD b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.BSD new file mode 100644 index 0000000000000000000000000000000000000000..ec1a29d34d6e419411c75523408aca72f705345c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.BSD @@ -0,0 +1,27 @@ +Copyright (c) Individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of PyCA Cryptography nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.PSF b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.PSF new file mode 100644 index 0000000000000000000000000000000000000000..4d3a4f57dea90ef89b53b97499b74ce5296f41ef --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/LICENSE.PSF @@ -0,0 +1,41 @@ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 2.7.12 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 2.7.12 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights + Reserved" are retained in Python 2.7.12 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 2.7.12 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 2.7.12. + +4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees + to be bound by the terms and conditions of this License Agreement. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..ae853aed03e453d7f66159ae31e70e7cb73f729f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/METADATA @@ -0,0 +1,139 @@ +Metadata-Version: 2.1 +Name: cryptography +Version: 40.0.1 +Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. +Home-page: https://github.com/pyca/cryptography +Author: The Python Cryptographic Authority and individual contributors +Author-email: cryptography-dev@python.org +License: (Apache-2.0 OR BSD-3-Clause) AND PSF-2.0 +Project-URL: Documentation, https://cryptography.io/ +Project-URL: Source, https://github.com/pyca/cryptography/ +Project-URL: Issues, https://github.com/pyca/cryptography/issues +Project-URL: Changelog, https://cryptography.io/en/latest/changelog/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Natural Language :: English +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: LICENSE.APACHE +License-File: LICENSE.BSD +License-File: LICENSE.PSF +Requires-Dist: cffi (>=1.12) +Provides-Extra: docs +Requires-Dist: sphinx (>=5.3.0) ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme (>=1.1.1) ; extra == 'docs' +Provides-Extra: docstest +Requires-Dist: pyenchant (>=1.6.11) ; extra == 'docstest' +Requires-Dist: twine (>=1.12.0) ; extra == 'docstest' +Requires-Dist: sphinxcontrib-spelling (>=4.0.1) ; extra == 'docstest' +Provides-Extra: pep8test +Requires-Dist: black ; extra == 'pep8test' +Requires-Dist: ruff ; extra == 'pep8test' +Requires-Dist: mypy ; extra == 'pep8test' +Requires-Dist: check-manifest ; extra == 'pep8test' +Provides-Extra: sdist +Requires-Dist: setuptools-rust (>=0.11.4) ; extra == 'sdist' +Provides-Extra: ssh +Requires-Dist: bcrypt (>=3.1.5) ; extra == 'ssh' +Provides-Extra: test +Requires-Dist: pytest (>=6.2.0) ; extra == 'test' +Requires-Dist: pytest-shard (>=0.1.2) ; extra == 'test' +Requires-Dist: pytest-benchmark ; extra == 'test' +Requires-Dist: pytest-cov ; extra == 'test' +Requires-Dist: pytest-subtests ; extra == 'test' +Requires-Dist: pytest-xdist ; extra == 'test' +Requires-Dist: pretend ; extra == 'test' +Requires-Dist: iso8601 ; extra == 'test' +Provides-Extra: test-randomorder +Requires-Dist: pytest-randomly ; extra == 'test-randomorder' +Provides-Extra: tox +Requires-Dist: tox ; extra == 'tox' + +pyca/cryptography +================= + +.. image:: https://img.shields.io/pypi/v/cryptography.svg + :target: https://pypi.org/project/cryptography/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + +.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=main + :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amain + + +``cryptography`` is a package which provides cryptographic recipes and +primitives to Python developers. Our goal is for it to be your "cryptographic +standard library". It supports Python 3.6+ and PyPy3 7.3.10+. + +``cryptography`` includes both high level recipes and low level interfaces to +common cryptographic algorithms such as symmetric ciphers, message digests, and +key derivation functions. For example, to encrypt something with +``cryptography``'s high level symmetric encryption recipe: + +.. code-block:: pycon + + >>> from cryptography.fernet import Fernet + >>> # Put this somewhere safe! + >>> key = Fernet.generate_key() + >>> f = Fernet(key) + >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") + >>> token + b'...' + >>> f.decrypt(token) + b'A really secret message. Not for prying eyes.' + +You can find more information in the `documentation`_. + +You can install ``cryptography`` with: + +.. code-block:: console + + $ pip install cryptography + +For full details see `the installation documentation`_. + +Discussion +~~~~~~~~~~ + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a `cryptography-dev`_ mailing list for development discussion. + +You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get +involved. + +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + + +.. _`documentation`: https://cryptography.io/ +.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ +.. _`issue tracker`: https://github.com/pyca/cryptography/issues +.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..7416ddc3b710741797a9c2278d620617cb5dab63 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/RECORD @@ -0,0 +1,179 @@ +cryptography-40.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cryptography-40.0.1.dist-info/LICENSE,sha256=Q9rSzHUqtyHNmp827OcPtTq3cTVR8tPYaU2OjFoG1uI,323 +cryptography-40.0.1.dist-info/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 +cryptography-40.0.1.dist-info/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 +cryptography-40.0.1.dist-info/LICENSE.PSF,sha256=aT7ApmKzn5laTyUrA6YiKUVHDBtvEsoCkY5O_g32S58,2415 +cryptography-40.0.1.dist-info/METADATA,sha256=j7Z2wCRyRNOpOlha1OTTRhMvaQ_rjfsmen_XpFsIt64,5568 +cryptography-40.0.1.dist-info/RECORD,, +cryptography-40.0.1.dist-info/WHEEL,sha256=qi1qnZVJNA-eqQGyIUiqdB8PJ6SyNN6tgdz26F9iFzc,100 +cryptography-40.0.1.dist-info/top_level.txt,sha256=KNaT-Sn2K4uxNaEbe6mYdDn3qWDMlp4y-MtWfB73nJc,13 +cryptography/__about__.py,sha256=x_FC0TWvsfl4LQSs3FdbgxOFhaXG7jg7rdpZKkC7eRQ,409 +cryptography/__init__.py,sha256=v4pF_XcZ6sp_b7YlfP2eJA4lNCckeH2NCzN6WYXNnEc,759 +cryptography/__pycache__/__about__.cpython-310.pyc,, +cryptography/__pycache__/__init__.cpython-310.pyc,, +cryptography/__pycache__/exceptions.cpython-310.pyc,, +cryptography/__pycache__/fernet.cpython-310.pyc,, +cryptography/__pycache__/utils.cpython-310.pyc,, +cryptography/exceptions.py,sha256=GNQJUZ9hpKs2ISYLQfA3FlwGjuWRTdhpsSXLmOex6j4,1405 +cryptography/fernet.py,sha256=qO4sQurx79k-5yOh4UnUZGm51zod0wRXJchz0l063To,6851 +cryptography/hazmat/__init__.py,sha256=OYlvgprzULzZlsf3yYTsd6VUVyQmpsbHjgJdNnsyRwE,418 +cryptography/hazmat/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/__pycache__/_oid.cpython-310.pyc,, +cryptography/hazmat/_oid.py,sha256=rCvnwb0z0VCKn7Y92IEQAoPErrANWREydYflZSNRrao,14155 +cryptography/hazmat/backends/__init__.py,sha256=bgrjB1SX2vXX-rmfG7A4PqGkq-isqQVXGaZtjWHAgj0,324 +cryptography/hazmat/backends/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__init__.py,sha256=oCa7eZbqvHsQ1pBeD_OOfnGxVaZbCfWnAKnHqOyPf1c,270 +cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-310.pyc,, +cryptography/hazmat/backends/openssl/aead.py,sha256=wzIsASMPfFuTEoCPSbfbuN67BglLdvENTft8j-fQDOM,10025 +cryptography/hazmat/backends/openssl/backend.py,sha256=ENYxxus4QtRhQFJBN5ezgKgris87MGj8nzVhcuE3Eyg,91919 +cryptography/hazmat/backends/openssl/ciphers.py,sha256=uCd2tiwF_-wdjgr2GSMHB6o6EKutHFh053feOjJkKWg,10346 +cryptography/hazmat/backends/openssl/cmac.py,sha256=cFZtDpqN5PNzo1X9tm8N8WDV5X81GRFXuXRUsjyFtF4,3005 +cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=nSqtgO5MJVf_UUkvw9tez10zhGnsGHq24OP1X2GKOe4,1113 +cryptography/hazmat/backends/openssl/dh.py,sha256=1CNiNiqxAhzwfzaJcFT0M1vta_iEKPkiyO36ercd1dw,12186 +cryptography/hazmat/backends/openssl/dsa.py,sha256=SQwoCTiNHrWjDQOFag3GznWG5K9CWM1AizqJ4usTRbY,8927 +cryptography/hazmat/backends/openssl/ec.py,sha256=Wh83LtvxRfPHC-ZIxSUuCOFqIx1KT_jeC9gwCtLr1fY,11197 +cryptography/hazmat/backends/openssl/ed25519.py,sha256=adWaawleloe9T0BctejcclybE51dwb-CmL_b0f6zBiU,5921 +cryptography/hazmat/backends/openssl/ed448.py,sha256=Ja_GMzDBcs_8N2PpmU2dd6sszbJh3xP-TrN88MkQLBI,5875 +cryptography/hazmat/backends/openssl/hashes.py,sha256=yFuHeO8qDPRbH2B9JJtW51wEVfhu11SFs3lhHBHGyPA,3240 +cryptography/hazmat/backends/openssl/hmac.py,sha256=mN7irlzO6Rbc3UIDqlySwaW5KoCn28N8gKS3lh9WEUg,3094 +cryptography/hazmat/backends/openssl/poly1305.py,sha256=Oivx5k9DcAU_BSySxEQiw5tE1pcz-ljmFpmXAPZqJrI,2513 +cryptography/hazmat/backends/openssl/rsa.py,sha256=zrFVhttn-pc8HHmRZjR42z-XinFRvBZTftGLrPjqMMA,21580 +cryptography/hazmat/backends/openssl/utils.py,sha256=VZHD8U8p3G00LyeS0ImY36iu7TC0RW7nx9f2BCOAyQs,2156 +cryptography/hazmat/backends/openssl/x448.py,sha256=6tZgh44ipS_UWJ6amueXxc8xIXdIfFtdpvnhri-oxXs,4339 +cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/bindings/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/bindings/_rust.pyd,sha256=sVl8LH5wkWBKnin0h5AAzkYx4itOrMl8iOROb4jOBpc,6544896 +cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=IumK7zP9Ko3HjLLb5hwZiY2rbfmfsuyTZLLcHOMvSdk,981 +cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=mpNJLuYLbCVrd5i33FBTmWwL_55Dw7JPkSLlSX9Q7oI,230 +cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=9CyI-grOsLQB_hfnhJPoG9dNOdJ7Zg6B0iUpzCowh44,592 +cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=RzVaLkY0y9L8W8opAL_uVD8bySKxP23pSQtEbLOStXI,905 +cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=sSz-RQXVQZ5EDbmEr0e5Km4OqrBKxHXUQwUQmRRkfdw,701 +cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=-1F5QDZfrdhmDLKTeSERuuDUHBTV-EhxIYk9mjpwcG4,616 +cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=VkTC78wjJgb_qrboOYIFPuFZ3W46zsr6zsxnlrOMwao,460 +cryptography/hazmat/bindings/_rust/x509.pyi,sha256=RaSbjBtObgnM66n1IudB34cFXrXamNpk_b2agiT99qE,1743 +cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-310.pyc,, +cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-310.pyc,, +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=uruUpaLLjgG5z2sckNFxS5TyJRhLcQ4zacklfdiEo8A,9165 +cryptography/hazmat/bindings/openssl/binding.py,sha256=2tiCAZziG2bMsa9Ke05hYY8EAiyczxOrvoCMFS_Ly38,7893 +cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/primitives/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/_serialization.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/cmac.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/constant_time.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/hashes.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/hmac.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/keywrap.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/padding.cpython-310.pyc,, +cryptography/hazmat/primitives/__pycache__/poly1305.cpython-310.pyc,, +cryptography/hazmat/primitives/_asymmetric.py,sha256=QacvnyA1fcXWbSAASCiodHVcTYwkaMdzq6KUIlaO7H0,496 +cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=TAlnDCAdYaa23-mb0TTbFLFhWwfdBF1DtXQdY9Koqf0,1057 +cryptography/hazmat/primitives/_serialization.py,sha256=r2ECtWEJ3JEgSpGkpaZrMfGhoQWdTHIn4gyLCB71fMg,5188 +cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-310.pyc,, +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=qm9VWIMPIaWUlCxlscb5bAM2aCe11fu-y85Y6nYjC7I,6619 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=JufsxrrxeJQlsiWMmx_44l90FNRw19o9kcKtk4rO8TU,7885 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=CdxppDV1lV2QlrQ0EhniqvFi8wp8PDYsvFWdpzyyVIY,12725 +cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=MqgOJFdMOXcMBJ-b84tJYOOkORL9xmEUHwCpVpa1k2o,3344 +cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=6XjKKEvLQUzZgOFyLZCRkK4Tl0sKMrxfL8CYx8_omxM,3264 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=EkKuY9e6UFqSuQ0LvyKYKl_L19tOfNCTlHWEiKgHeUc,2690 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=njFky5AkSrsBh47PeVLjj81SOLOiZaxAUSzGWD2Znxw,11479 +cryptography/hazmat/primitives/asymmetric/types.py,sha256=_etLWzFIYf01_NHTi3lg5q593wckK2LXxAK_SF94Dpk,2960 +cryptography/hazmat/primitives/asymmetric/utils.py,sha256=p6nF7EzF0sp5GYFTw1HEhPYYjuTik53WTUkvuPIfDRk,755 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=H9gXtrvoO8qJutrDJ-rQNW1kjdbydkp6MD3PWxDWDiQ,3289 +cryptography/hazmat/primitives/asymmetric/x448.py,sha256=u9Ma5viyGMVjil4tv9GKsBxcT0rikom9MigjoJ3OgQ4,3189 +cryptography/hazmat/primitives/ciphers/__init__.py,sha256=2K5I_haxK0BLNqSZcQUqcjf8FmHY8xV1U-XjfgUmkM8,645 +cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-310.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-310.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-310.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-310.pyc,, +cryptography/hazmat/primitives/ciphers/aead.py,sha256=c1wfOJ5alX-pDkWxz9cSq5M7ug2CtNc6gCovyMoy_bY,12032 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=vR1tcKRpaYbQhv3dLIiQNmaZpq7x9kLCdUvOgrWIG0I,4965 +cryptography/hazmat/primitives/ciphers/base.py,sha256=RYTyXd8gXgBggdEl0cWcEnx6mkd1YsdRT_3tLEV4iGU,8269 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=U_flGFnHih452GO9X66BSN8U9xUmYh12wB6FFEIk6Xc,8326 +cryptography/hazmat/primitives/cmac.py,sha256=ZbpwI87EhO3maiwqzttN1z0ObsAO1ufnl2Px5b9uJ1c,2036 +cryptography/hazmat/primitives/constant_time.py,sha256=6bkW00QjhKusdgsQbexXhMlGX0XRN59XNmxWS2W38NA,387 +cryptography/hazmat/primitives/hashes.py,sha256=cwMQYC0An0UOVTFWqeDIXiokSBorSh4BwHKSWxz8HB0,6041 +cryptography/hazmat/primitives/hmac.py,sha256=pKiyxmJVcixW7Xk7w4ofde6Z7F8UohqGZa01PoxRotc,2122 +cryptography/hazmat/primitives/kdf/__init__.py,sha256=DcZhzfLG8d8IYBH771lGTVU5S87OQDpu3nrfOwZnsmA,715 +cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-310.pyc,, +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=giEvBnD5eAB6ymUcYKSgd_2D_qRznOUSaplS1CQoE_A,3691 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=cKBjtCVaKVRhUzbNK99HDEyWUxvPwSfOIygKAMyyb3g,3010 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=Ys2ITSbEw49V1v_DagQBd17owQr2A2iyPue4mot4Z_g,9196 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=wEMH4CJfPccCg9apQLXyWUWBrZLTpYLLnoZEnzvaHQo,2032 +cryptography/hazmat/primitives/kdf/scrypt.py,sha256=Wt7jj51vsedNtQX-LZI41geqUZnBFYnrhOXpoheLsOM,2227 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=bDhxg0gllboQ--a9gdDaiTbO6XMemZPlu3TW91dRp8o,1967 +cryptography/hazmat/primitives/keywrap.py,sha256=TWqyG9K7k-Ymq4kcIw7u3NIKUPVDtv6bimwxIJYTe20,5643 +cryptography/hazmat/primitives/padding.py,sha256=xruasOE5Cd8KEQ-yp9W6v9WKPvKH-GudHCPKQ7A8HfI,6207 +cryptography/hazmat/primitives/poly1305.py,sha256=QvxPMrqjgKJt0mOZSeZKk4NcxsNCd2kgfI-X1CmyUW4,1837 +cryptography/hazmat/primitives/serialization/__init__.py,sha256=G-BRfGpQzYrRf5r9QS9BN7QdgpF1k5cLCfdlMH_Z0yw,1618 +cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-310.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-310.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-310.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-310.pyc,, +cryptography/hazmat/primitives/serialization/base.py,sha256=5ebkgRqVHpVOST3OkcWkdoqo-0sVfdIuZUoyL8tj0es,1955 +cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=p8ZWAxNEat-MRov2JaRR3TUAtcp8MAE6v4DDodNQURA,6731 +cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=AeyFKpvoll-AUHkLKMGh5lZg7xGwVWl9Y6fXyxdhXFs,7362 +cryptography/hazmat/primitives/serialization/ssh.py,sha256=Tgt8fK1F4OyZngYPINW2zor8iUosv2yrQ7qLlJrztlo,48438 +cryptography/hazmat/primitives/twofactor/__init__.py,sha256=ZHo4zwWidFP2RWFl8luiNuYkVMZPghzx54izPNSCtD4,222 +cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-310.pyc,, +cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-310.pyc,, +cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-310.pyc,, +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=LLMBoHczZen-hfUd6NmECPjGIc5kyys7pvbHiZOpkKE,2977 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=hEsH9rd8AdTEjVjswPrB9HzRiZZSV9qfpJDmyEPppg4,1437 +cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +cryptography/utils.py,sha256=y3KjdVAv2vW_42r3TJs4YGq9IMPWAjQhamV9UzPU31k,3981 +cryptography/x509/__init__.py,sha256=4WL6dxMLEWM9Wa9f_SpNbwcQNg76dut5zigRcHpRoTA,7719 +cryptography/x509/__pycache__/__init__.cpython-310.pyc,, +cryptography/x509/__pycache__/base.cpython-310.pyc,, +cryptography/x509/__pycache__/certificate_transparency.cpython-310.pyc,, +cryptography/x509/__pycache__/extensions.cpython-310.pyc,, +cryptography/x509/__pycache__/general_name.cpython-310.pyc,, +cryptography/x509/__pycache__/name.cpython-310.pyc,, +cryptography/x509/__pycache__/ocsp.cpython-310.pyc,, +cryptography/x509/__pycache__/oid.cpython-310.pyc,, +cryptography/x509/base.py,sha256=N24nEkrizgtWi5Acd1M9gCbyp8mGdw5srTq_wgTkEzo,34966 +cryptography/x509/certificate_transparency.py,sha256=jkjOvVu8bS5ljHov2AWdWScENQxylmDgESk01koC0Rs,2226 +cryptography/x509/extensions.py,sha256=XWx_WnFCu4s_GA_aalW3OZwhjkyttW6OGJsBaz3IDbs,65516 +cryptography/x509/general_name.py,sha256=EExe3dR0lBj6V8i4R_nEhj-Vj1B0UIRmRil3wqMBaDA,7853 +cryptography/x509/name.py,sha256=krFYM8XyZrEHMDFChMwVDd3D-5cq40VmSWrZF2lqXZc,14821 +cryptography/x509/ocsp.py,sha256=gfVQzFPPmUh8SYzVX000GeWNSLka6EYq3AUBvANTk8c,18513 +cryptography/x509/oid.py,sha256=dAllMplMi_Kc_lEiQKnSM-rTN5w--a1UZucV-HvQOb0,793 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..bfe70f4e36c28050ee2e4be83cea3cea32ff96db --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: false +Tag: cp36-abi3-win_amd64 + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d38bc5ea2591b0363e24090a1631afa3da2c14e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography-40.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +cryptography diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__about__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__about__.py new file mode 100644 index 0000000000000000000000000000000000000000..de686bbc6952410942f758c7cbdb599008826b38 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__about__.py @@ -0,0 +1,15 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +__all__ = [ + "__version__", + "__author__", + "__copyright__", +] + +__version__ = "40.0.1" + +__author__ = "The Python Cryptographic Authority and individual contributors" +__copyright__ = f"Copyright 2013-2023 {__author__}" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7f8a25c6ed9c463f992e1a3ea1e4c214db85ef25 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__init__.py @@ -0,0 +1,24 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import sys +import warnings + +from cryptography.__about__ import __author__, __copyright__, __version__ +from cryptography.utils import CryptographyDeprecationWarning + +__all__ = [ + "__version__", + "__author__", + "__copyright__", +] + +if sys.version_info[:2] == (3, 6): + warnings.warn( + "Python 3.6 is no longer supported by the Python core team. " + "Therefore, support for it is deprecated in cryptography. The next " + "release of cryptography will remove support for Python 3.6.", + CryptographyDeprecationWarning, + stacklevel=2, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be94bc9bf4900e780d5c99e5a0700b02764159ad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67f1c23a0533b0c3a829f4bf9f40437a65a9726d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ae624a85d4e77c19b4a969fcb34dac2aacb9658 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..550f53b64300ecee316da5d0e191f2df04991eaf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc6c186a10f69076cbfe652707f8899e83acb5cf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..5e69c11924344666e450f9449c65cf80e0f8d578 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/exceptions.py @@ -0,0 +1,66 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils + +if typing.TYPE_CHECKING: + from cryptography.hazmat.bindings._rust import openssl as rust_openssl + + +class _Reasons(utils.Enum): + BACKEND_MISSING_INTERFACE = 0 + UNSUPPORTED_HASH = 1 + UNSUPPORTED_CIPHER = 2 + UNSUPPORTED_PADDING = 3 + UNSUPPORTED_MGF = 4 + UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 + UNSUPPORTED_ELLIPTIC_CURVE = 6 + UNSUPPORTED_SERIALIZATION = 7 + UNSUPPORTED_X509 = 8 + UNSUPPORTED_EXCHANGE_ALGORITHM = 9 + UNSUPPORTED_DIFFIE_HELLMAN = 10 + UNSUPPORTED_MAC = 11 + + +class UnsupportedAlgorithm(Exception): + def __init__( + self, message: str, reason: typing.Optional[_Reasons] = None + ) -> None: + super().__init__(message) + self._reason = reason + + +class AlreadyFinalized(Exception): + pass + + +class AlreadyUpdated(Exception): + pass + + +class NotYetFinalized(Exception): + pass + + +class InvalidTag(Exception): + pass + + +class InvalidSignature(Exception): + pass + + +class InternalError(Exception): + def __init__( + self, msg: str, err_code: typing.List["rust_openssl.OpenSSLError"] + ) -> None: + super().__init__(msg) + self.err_code = err_code + + +class InvalidKey(Exception): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/fernet.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/fernet.py new file mode 100644 index 0000000000000000000000000000000000000000..a2601f80f6803fab8c4385244a02f60961c8fdcb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/fernet.py @@ -0,0 +1,220 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import base64 +import binascii +import os +import time +import typing + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import hashes, padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.hmac import HMAC + + +class InvalidToken(Exception): + pass + + +_MAX_CLOCK_SKEW = 60 + + +class Fernet: + def __init__( + self, + key: typing.Union[bytes, str], + backend: typing.Any = None, + ) -> None: + try: + key = base64.urlsafe_b64decode(key) + except binascii.Error as exc: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) from exc + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + self._signing_key = key[:16] + self._encryption_key = key[16:] + + @classmethod + def generate_key(cls) -> bytes: + return base64.urlsafe_b64encode(os.urandom(32)) + + def encrypt(self, data: bytes) -> bytes: + return self.encrypt_at_time(data, int(time.time())) + + def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + def _encrypt_from_parts( + self, data: bytes, current_time: int, iv: bytes + ) -> bytes: + utils._check_bytes("data", data) + + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher( + algorithms.AES(self._encryption_key), + modes.CBC(iv), + ).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + basic_parts = ( + b"\x80" + + current_time.to_bytes(length=8, byteorder="big") + + iv + + ciphertext + ) + + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + def decrypt( + self, token: typing.Union[bytes, str], ttl: typing.Optional[int] = None + ) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(token) + if ttl is None: + time_info = None + else: + time_info = (ttl, int(time.time())) + return self._decrypt_data(data, timestamp, time_info) + + def decrypt_at_time( + self, token: typing.Union[bytes, str], ttl: int, current_time: int + ) -> bytes: + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, (ttl, current_time)) + + def extract_timestamp(self, token: typing.Union[bytes, str]) -> int: + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data( + token: typing.Union[bytes, str] + ) -> typing.Tuple[int, bytes]: + if not isinstance(token, (str, bytes)): + raise TypeError("token must be bytes or str") + + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + if not data or data[0] != 0x80: + raise InvalidToken + + if len(data) < 9: + raise InvalidToken + + timestamp = int.from_bytes(data[1:9], byteorder="big") + return timestamp, data + + def _verify_signature(self, data: bytes) -> None: + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(data[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + def _decrypt_data( + self, + data: bytes, + timestamp: int, + time_info: typing.Optional[typing.Tuple[int, int]], + ) -> bytes: + if time_info is not None: + ttl, current_time = time_info + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + + iv = data[9:25] + ciphertext = data[25:-32] + decryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv) + ).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded + + +class MultiFernet: + def __init__(self, fernets: typing.Iterable[Fernet]): + fernets = list(fernets) + if not fernets: + raise ValueError( + "MultiFernet requires at least one Fernet instance" + ) + self._fernets = fernets + + def encrypt(self, msg: bytes) -> bytes: + return self.encrypt_at_time(msg, int(time.time())) + + def encrypt_at_time(self, msg: bytes, current_time: int) -> bytes: + return self._fernets[0].encrypt_at_time(msg, current_time) + + def rotate(self, msg: typing.Union[bytes, str]) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + + def decrypt( + self, msg: typing.Union[bytes, str], ttl: typing.Optional[int] = None + ) -> bytes: + for f in self._fernets: + try: + return f.decrypt(msg, ttl) + except InvalidToken: + pass + raise InvalidToken + + def decrypt_at_time( + self, msg: typing.Union[bytes, str], ttl: int, current_time: int + ) -> bytes: + for f in self._fernets: + try: + return f.decrypt_at_time(msg, ttl, current_time) + except InvalidToken: + pass + raise InvalidToken diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..007694bc5060db538c6f6a0e9e2ca3549e9e67ba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +Hazardous Materials + +This is a "Hazardous Materials" module. You should ONLY use it if you're +100% absolutely sure that you know what you're doing because this module +is full of land mines, dragons, and dinosaurs with laser guns. +""" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91bb0598256daa7de3ceb416717ebfe004e44552 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99845a4231148b15707163d5aa61a44216b0b8c6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/_oid.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/_oid.py new file mode 100644 index 0000000000000000000000000000000000000000..927ffc4c54122c8af7e6fae852448a369395cf7d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/_oid.py @@ -0,0 +1,293 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.bindings._rust import ( + ObjectIdentifier as ObjectIdentifier, +) +from cryptography.hazmat.primitives import hashes + + +class ExtensionOID: + SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") + SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") + KEY_USAGE = ObjectIdentifier("2.5.29.15") + SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") + ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") + BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") + NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") + CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") + CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") + POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") + AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") + POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") + EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") + FRESHEST_CRL = ObjectIdentifier("2.5.29.46") + INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") + ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") + AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") + SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") + OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") + TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") + CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") + PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( + "1.3.6.1.4.1.11129.2.4.2" + ) + PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") + + +class OCSPExtensionOID: + NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") + + +class CRLEntryExtensionOID: + CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") + CRL_REASON = ObjectIdentifier("2.5.29.21") + INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") + + +class NameOID: + COMMON_NAME = ObjectIdentifier("2.5.4.3") + COUNTRY_NAME = ObjectIdentifier("2.5.4.6") + LOCALITY_NAME = ObjectIdentifier("2.5.4.7") + STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") + STREET_ADDRESS = ObjectIdentifier("2.5.4.9") + ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") + ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") + SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") + SURNAME = ObjectIdentifier("2.5.4.4") + GIVEN_NAME = ObjectIdentifier("2.5.4.42") + TITLE = ObjectIdentifier("2.5.4.12") + GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") + X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") + DN_QUALIFIER = ObjectIdentifier("2.5.4.46") + PSEUDONYM = ObjectIdentifier("2.5.4.65") + USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") + DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") + EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") + JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") + JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") + JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( + "1.3.6.1.4.1.311.60.2.1.2" + ) + BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") + POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") + POSTAL_CODE = ObjectIdentifier("2.5.4.17") + INN = ObjectIdentifier("1.2.643.3.131.1.1") + OGRN = ObjectIdentifier("1.2.643.100.1") + SNILS = ObjectIdentifier("1.2.643.100.3") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +class SignatureAlgorithmOID: + RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") + RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") + # This is an alternate OID for RSA with SHA1 that is occasionally seen + _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") + RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") + RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") + RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") + RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") + RSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.13") + RSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.14") + RSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.15") + RSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.16") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") + ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") + ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") + ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") + ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") + ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") + ECDSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.9") + ECDSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.10") + ECDSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.11") + ECDSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.12") + DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") + DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") + DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + DSA_WITH_SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.3.3") + DSA_WITH_SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.3.4") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") + GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") + GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") + + +_SIG_OIDS_TO_HASH: typing.Dict[ + ObjectIdentifier, typing.Optional[hashes.HashAlgorithm] +] = { + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.RSA_WITH_SHA3_224: hashes.SHA3_224(), + SignatureAlgorithmOID.RSA_WITH_SHA3_256: hashes.SHA3_256(), + SignatureAlgorithmOID.RSA_WITH_SHA3_384: hashes.SHA3_384(), + SignatureAlgorithmOID.RSA_WITH_SHA3_512: hashes.SHA3_512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_224: hashes.SHA3_224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_256: hashes.SHA3_256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_384: hashes.SHA3_384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_512: hashes.SHA3_512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, +} + + +class ExtendedKeyUsageOID: + SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") + CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") + CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") + EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") + TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") + OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") + ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") + KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") + IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") + CERTIFICATE_TRANSPARENCY = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4") + + +class AuthorityInformationAccessOID: + CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") + OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + + +class SubjectInformationAccessOID: + CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") + + +class CertificatePoliciesOID: + CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") + CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + + +class AttributeOID: + CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +_OID_NAMES = { + NameOID.COMMON_NAME: "commonName", + NameOID.COUNTRY_NAME: "countryName", + NameOID.LOCALITY_NAME: "localityName", + NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", + NameOID.STREET_ADDRESS: "streetAddress", + NameOID.ORGANIZATION_NAME: "organizationName", + NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", + NameOID.SERIAL_NUMBER: "serialNumber", + NameOID.SURNAME: "surname", + NameOID.GIVEN_NAME: "givenName", + NameOID.TITLE: "title", + NameOID.GENERATION_QUALIFIER: "generationQualifier", + NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", + NameOID.DN_QUALIFIER: "dnQualifier", + NameOID.PSEUDONYM: "pseudonym", + NameOID.USER_ID: "userID", + NameOID.DOMAIN_COMPONENT: "domainComponent", + NameOID.EMAIL_ADDRESS: "emailAddress", + NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", + NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( + "jurisdictionStateOrProvinceName" + ), + NameOID.BUSINESS_CATEGORY: "businessCategory", + NameOID.POSTAL_ADDRESS: "postalAddress", + NameOID.POSTAL_CODE: "postalCode", + NameOID.INN: "INN", + NameOID.OGRN: "OGRN", + NameOID.SNILS: "SNILS", + NameOID.UNSTRUCTURED_NAME: "unstructuredName", + SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", + SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS", + SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", + SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", + SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", + SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", + SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", + SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", + SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", + SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( + "GOST R 34.11-94 with GOST R 34.10-2001" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" + ), + ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", + ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", + ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", + ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", + ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", + ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", + ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", + ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", + ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", + ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", + ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", + ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.PRECERT_POISON: "ctPoison", + CRLEntryExtensionOID.CRL_REASON: "cRLReason", + CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", + CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", + ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", + ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", + ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", + ExtensionOID.POLICY_MAPPINGS: "policyMappings", + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", + ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", + ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", + ExtensionOID.FRESHEST_CRL: "freshestCRL", + ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", + ExtensionOID.ISSUING_DISTRIBUTION_POINT: ("issuingDistributionPoint"), + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", + ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", + ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", + ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", + ExtensionOID.TLS_FEATURE: "TLSFeature", + AuthorityInformationAccessOID.OCSP: "OCSP", + AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", + CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", + CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", + OCSPExtensionOID.NONCE: "OCSPNonce", + AttributeOID.CHALLENGE_PASSWORD: "challengePassword", +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3926f85f1d188eddafd9cf540dcd4d9209c3415b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from typing import Any + + +def default_backend() -> Any: + from cryptography.hazmat.backends.openssl.backend import backend + + return backend diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42070ead3797d80661ac60ff14cceeff682e2af2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..42c4539df3ed24ed99d5a5963e97ca78e3ffddcd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,8 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.hazmat.backends.openssl.backend import backend + +__all__ = ["backend"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..275ab6f94adad014e1d2811c24b158c7ae045f87 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40379f89f7d92fb7b9f897a776a497954f0bc183 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8ad3a346b23faea2824b10dcd4fed5789ce8bae Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66a9f7ea78cd18afed301a82fbfb1c50744b4e9b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed99b4623cddab6d0e985e2538c47b53ebb75a0f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b981dd64e6022322dc21127323a01d5e6004c1bc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a41d0490120d30169580d3ec9d443f1d618631ba Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25b4b94a5143a559e12337f5666bfc9948ef7225 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a32dd764e1719c042076f699c4bdc84b4e6fc4ff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbed5af74eca5fea7b55f31bdb546cfe9447fb13 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f111dacae41ebfc541b6b8e0270c12afedf9518e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9db095d93d4d456f1d9981cfb799dec3d9bf9aa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4bc4faabba5c184dc255ce35200421a2d79b15b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e10cf1d8762ae66cf928a2e96bf2b7413b28c59b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..301f204f0ea8e8a60f984605f92a65cf66050a5a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67f4b49c51abc3fe6bf07d4b73a0cc52469eb36f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d2e2e70085f523fbcb41739a41afe732b4100e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/aead.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/aead.py new file mode 100644 index 0000000000000000000000000000000000000000..d43deb432a16dd0d2764283dc566237b9249cf1c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/aead.py @@ -0,0 +1,310 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidTag + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, + AESGCM, + AESOCB3, + AESSIV, + ChaCha20Poly1305, + ) + + _AEADTypes = typing.Union[ + AESCCM, AESGCM, AESOCB3, AESSIV, ChaCha20Poly1305 + ] + +_ENCRYPT = 1 +_DECRYPT = 0 + + +def _aead_cipher_name(cipher: "_AEADTypes") -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, + AESGCM, + AESOCB3, + AESSIV, + ChaCha20Poly1305, + ) + + if isinstance(cipher, ChaCha20Poly1305): + return b"chacha20-poly1305" + elif isinstance(cipher, AESCCM): + return f"aes-{len(cipher._key) * 8}-ccm".encode("ascii") + elif isinstance(cipher, AESOCB3): + return f"aes-{len(cipher._key) * 8}-ocb".encode("ascii") + elif isinstance(cipher, AESSIV): + return f"aes-{len(cipher._key) * 8 // 2}-siv".encode("ascii") + else: + assert isinstance(cipher, AESGCM) + return f"aes-{len(cipher._key) * 8}-gcm".encode("ascii") + + +def _evp_cipher(cipher_name: bytes, backend: "Backend"): + if cipher_name.endswith(b"-siv"): + evp_cipher = backend._lib.EVP_CIPHER_fetch( + backend._ffi.NULL, + cipher_name, + backend._ffi.NULL, + ) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + evp_cipher = backend._ffi.gc(evp_cipher, backend._lib.EVP_CIPHER_free) + else: + evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + + return evp_cipher + + +def _aead_create_ctx( + backend: "Backend", + cipher: "_AEADTypes", + key: bytes, +): + ctx = backend._lib.EVP_CIPHER_CTX_new() + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) + cipher_name = _aead_cipher_name(cipher) + evp_cipher = _evp_cipher(cipher_name, backend) + key_ptr = backend._ffi.from_buffer(key) + res = backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + backend._ffi.NULL, + key_ptr, + backend._ffi.NULL, + 0, + ) + backend.openssl_assert(res != 0) + return ctx + + +def _aead_setup( + backend: "Backend", + cipher_name: bytes, + key: bytes, + nonce: bytes, + tag: typing.Optional[bytes], + tag_len: int, + operation: int, +): + evp_cipher = _evp_cipher(cipher_name, backend) + ctx = backend._lib.EVP_CIPHER_CTX_new() + ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) + res = backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + # CCM requires the IVLEN to be set before calling SET_TAG on decrypt + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(nonce), + backend._ffi.NULL, + ) + backend.openssl_assert(res != 0) + if operation == _DECRYPT: + assert tag is not None + _set_tag(backend, ctx, tag) + elif cipher_name.endswith(b"-ccm"): + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL + ) + backend.openssl_assert(res != 0) + + nonce_ptr = backend._ffi.from_buffer(nonce) + key_ptr = backend._ffi.from_buffer(key) + res = backend._lib.EVP_CipherInit_ex( + ctx, + backend._ffi.NULL, + backend._ffi.NULL, + key_ptr, + nonce_ptr, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + return ctx + + +def _set_tag(backend, ctx, tag: bytes) -> None: + tag_ptr = backend._ffi.from_buffer(tag) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag_ptr + ) + backend.openssl_assert(res != 0) + + +def _set_nonce_operation(backend, ctx, nonce: bytes, operation: int) -> None: + nonce_ptr = backend._ffi.from_buffer(nonce) + res = backend._lib.EVP_CipherInit_ex( + ctx, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + nonce_ptr, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + + +def _set_length(backend: "Backend", ctx, data_len: int) -> None: + intptr = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len + ) + backend.openssl_assert(res != 0) + + +def _process_aad(backend: "Backend", ctx, associated_data: bytes) -> None: + outlen = backend._ffi.new("int *") + a_data_ptr = backend._ffi.from_buffer(associated_data) + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, outlen, a_data_ptr, len(associated_data) + ) + backend.openssl_assert(res != 0) + + +def _process_data(backend: "Backend", ctx, data: bytes) -> bytes: + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + data_ptr = backend._ffi.from_buffer(data) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data_ptr, len(data)) + if res == 0: + # AES SIV can error here if the data is invalid on decrypt + backend._consume_errors() + raise InvalidTag + return backend._ffi.buffer(buf, outlen[0])[:] + + +def _encrypt( + backend: "Backend", + cipher: "_AEADTypes", + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any = None, +) -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESSIV + + if ctx is None: + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, + cipher_name, + cipher._key, + nonce, + None, + tag_length, + _ENCRYPT, + ) + else: + _set_nonce_operation(backend, ctx, nonce, _ENCRYPT) + + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + for ad in associated_data: + _process_aad(backend, ctx, ad) + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + # All AEADs we support besides OCB are streaming so they return nothing + # in finalization. OCB can return up to (16 byte block - 1) bytes so + # we need a buffer here too. + buf = backend._ffi.new("unsigned char[]", 16) + res = backend._lib.EVP_CipherFinal_ex(ctx, buf, outlen) + backend.openssl_assert(res != 0) + processed_data += backend._ffi.buffer(buf, outlen[0])[:] + tag_buf = backend._ffi.new("unsigned char[]", tag_length) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf + ) + backend.openssl_assert(res != 0) + tag = backend._ffi.buffer(tag_buf)[:] + + if isinstance(cipher, AESSIV): + # RFC 5297 defines the output as IV || C, where the tag we generate is + # the "IV" and C is the ciphertext. This is the opposite of our + # other AEADs, which are Ciphertext || Tag + backend.openssl_assert(len(tag) == 16) + return tag + processed_data + else: + return processed_data + tag + + +def _decrypt( + backend: "Backend", + cipher: "_AEADTypes", + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any = None, +) -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESSIV + + if len(data) < tag_length: + raise InvalidTag + + if isinstance(cipher, AESSIV): + # RFC 5297 defines the output as IV || C, where the tag we generate is + # the "IV" and C is the ciphertext. This is the opposite of our + # other AEADs, which are Ciphertext || Tag + tag = data[:tag_length] + data = data[tag_length:] + else: + tag = data[-tag_length:] + data = data[:-tag_length] + if ctx is None: + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT + ) + else: + _set_nonce_operation(backend, ctx, nonce, _DECRYPT) + _set_tag(backend, ctx, tag) + + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + for ad in associated_data: + _process_aad(backend, ctx, ad) + # CCM has a different error path if the tag doesn't match. Errors are + # raised in Update and Final is irrelevant. + if isinstance(cipher, AESCCM): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + d_ptr = backend._ffi.from_buffer(data) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, d_ptr, len(data)) + if res != 1: + backend._consume_errors() + raise InvalidTag + + processed_data = backend._ffi.buffer(buf, outlen[0])[:] + else: + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + # OCB can return up to 15 bytes (16 byte block - 1) in finalization + buf = backend._ffi.new("unsigned char[]", 16) + res = backend._lib.EVP_CipherFinal_ex(ctx, buf, outlen) + processed_data += backend._ffi.buffer(buf, outlen[0])[:] + if res == 0: + backend._consume_errors() + raise InvalidTag + + return processed_data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 0000000000000000000000000000000000000000..a3fe1bce47cead512fada863910ddd5d94a303a1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,2428 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import collections +import contextlib +import itertools +import typing +import warnings +from contextlib import contextmanager + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.ciphers import _CipherContext +from cryptography.hazmat.backends.openssl.cmac import _CMACContext +from cryptography.hazmat.backends.openssl.dh import ( + _dh_params_dup, + _DHParameters, + _DHPrivateKey, + _DHPublicKey, +) +from cryptography.hazmat.backends.openssl.dsa import ( + _DSAParameters, + _DSAPrivateKey, + _DSAPublicKey, +) +from cryptography.hazmat.backends.openssl.ec import ( + _EllipticCurvePrivateKey, + _EllipticCurvePublicKey, +) +from cryptography.hazmat.backends.openssl.ed448 import ( + _ED448_KEY_SIZE, + _Ed448PrivateKey, + _Ed448PublicKey, +) +from cryptography.hazmat.backends.openssl.ed25519 import ( + _Ed25519PrivateKey, + _Ed25519PublicKey, +) +from cryptography.hazmat.backends.openssl.hashes import _HashContext +from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.backends.openssl.poly1305 import ( + _POLY1305_KEY_SIZE, + _Poly1305Context, +) +from cryptography.hazmat.backends.openssl.rsa import ( + _RSAPrivateKey, + _RSAPublicKey, +) +from cryptography.hazmat.backends.openssl.x448 import ( + _X448PrivateKey, + _X448PublicKey, +) +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.bindings.openssl import binding +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives.asymmetric import ( + dh, + dsa, + ec, + ed448, + ed25519, + rsa, + x448, + x25519, +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, + OAEP, + PSS, + PKCS1v15, +) +from cryptography.hazmat.primitives.asymmetric.types import ( + PrivateKeyTypes, + PublicKeyTypes, +) +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, + AES128, + AES256, + ARC4, + SM4, + Camellia, + ChaCha20, + TripleDES, + _BlowfishInternal, + _CAST5Internal, + _IDEAInternal, + _SEEDInternal, +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, + CFB, + CFB8, + CTR, + ECB, + GCM, + OFB, + XTS, + Mode, +) +from cryptography.hazmat.primitives.kdf import scrypt +from cryptography.hazmat.primitives.serialization import ssh +from cryptography.hazmat.primitives.serialization.pkcs12 import ( + PBES, + PKCS12Certificate, + PKCS12KeyAndCertificates, + PKCS12PrivateKeyTypes, + _PKCS12CATypes, +) + +_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) + + +# Not actually supported, just used as a marker for some serialization tests. +class _RC2: + pass + + +class Backend: + """ + OpenSSL API binding interfaces. + """ + + name = "openssl" + + # FIPS has opinions about acceptable algorithms and key sizes, but the + # disallowed algorithms are still present in OpenSSL. They just error if + # you try to use them. To avoid that we allowlist the algorithms in + # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are. + _fips_aead = { + b"aes-128-ccm", + b"aes-192-ccm", + b"aes-256-ccm", + b"aes-128-gcm", + b"aes-192-gcm", + b"aes-256-gcm", + } + # TripleDES encryption is disallowed/deprecated throughout 2023 in + # FIPS 140-3. To keep it simple we denylist any use of TripleDES (TDEA). + _fips_ciphers = (AES,) + # Sometimes SHA1 is still permissible. That logic is contained + # within the various *_supported methods. + _fips_hashes = ( + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + hashes.SHAKE128, + hashes.SHAKE256, + ) + _fips_ecdh_curves = ( + ec.SECP224R1, + ec.SECP256R1, + ec.SECP384R1, + ec.SECP521R1, + ) + _fips_rsa_min_key_size = 2048 + _fips_rsa_min_public_exponent = 65537 + _fips_dsa_min_modulus = 1 << 2048 + _fips_dh_min_key_size = 2048 + _fips_dh_min_modulus = 1 << _fips_dh_min_key_size + + def __init__(self) -> None: + self._binding = binding.Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + self._fips_enabled = self._is_fips_enabled() + + self._cipher_registry: typing.Dict[ + typing.Tuple[typing.Type[CipherAlgorithm], typing.Type[Mode]], + typing.Callable, + ] = {} + self._register_default_ciphers() + if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + warnings.warn( + "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.", + UserWarning, + ) + else: + self.activate_osrandom_engine() + self._dh_types = [self._lib.EVP_PKEY_DH] + if self._lib.Cryptography_HAS_EVP_PKEY_DHX: + self._dh_types.append(self._lib.EVP_PKEY_DHX) + + def __repr__(self) -> str: + return "<OpenSSLBackend(version: {}, FIPS: {}, Legacy: {})>".format( + self.openssl_version_text(), + self._fips_enabled, + self._binding._legacy_provider_loaded, + ) + + def openssl_assert( + self, + ok: bool, + errors: typing.Optional[typing.List[rust_openssl.OpenSSLError]] = None, + ) -> None: + return binding._openssl_assert(self._lib, ok, errors=errors) + + def _is_fips_enabled(self) -> bool: + if self._lib.Cryptography_HAS_300_FIPS: + mode = self._lib.EVP_default_properties_is_fips_enabled( + self._ffi.NULL + ) + else: + mode = self._lib.FIPS_mode() + + if mode == 0: + # OpenSSL without FIPS pushes an error on the error stack + self._lib.ERR_clear_error() + return bool(mode) + + def _enable_fips(self) -> None: + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + self._binding._enable_fips() + assert self._is_fips_enabled() + self._fips_enabled = self._is_fips_enabled() + + def activate_builtin_random(self) -> None: + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Obtain a new structural reference. + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + self._lib.ENGINE_unregister_RAND(e) + # Reset the RNG to use the built-in. + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + # decrement the structural reference from get_default_RAND + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + @contextlib.contextmanager + def _get_osurandom_engine(self): + # Fetches an engine by id and returns it. This creates a structural + # reference. + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) + self.openssl_assert(e != self._ffi.NULL) + # Initialize the engine for use. This adds a functional reference. + res = self._lib.ENGINE_init(e) + self.openssl_assert(res == 1) + + try: + yield e + finally: + # Decrement the structural ref incremented by ENGINE_by_id. + res = self._lib.ENGINE_free(e) + self.openssl_assert(res == 1) + # Decrement the functional ref incremented by ENGINE_init. + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + def activate_osrandom_engine(self) -> None: + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Unregister and free the current engine. + self.activate_builtin_random() + with self._get_osurandom_engine() as e: + # Set the engine as the default RAND provider. + res = self._lib.ENGINE_set_default_RAND(e) + self.openssl_assert(res == 1) + # Reset the RNG to use the engine + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + + def osrandom_engine_implementation(self) -> str: + buf = self._ffi.new("char[]", 64) + with self._get_osurandom_engine() as e: + res = self._lib.ENGINE_ctrl_cmd( + e, b"get_implementation", len(buf), buf, self._ffi.NULL, 0 + ) + self.openssl_assert(res > 0) + return self._ffi.string(buf).decode("ascii") + + def openssl_version_text(self) -> str: + """ + Friendly string name of the loaded OpenSSL library. This is not + necessarily the same version as it was compiled against. + + Example: OpenSSL 1.1.1d 10 Sep 2019 + """ + return self._ffi.string( + self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) + ).decode("ascii") + + def openssl_version_number(self) -> int: + return self._lib.OpenSSL_version_num() + + def create_hmac_ctx( + self, key: bytes, algorithm: hashes.HashAlgorithm + ) -> _HMACContext: + return _HMACContext(self, key, algorithm) + + def _evp_md_from_algorithm(self, algorithm: hashes.HashAlgorithm): + if algorithm.name == "blake2b" or algorithm.name == "blake2s": + alg = "{}{}".format( + algorithm.name, algorithm.digest_size * 8 + ).encode("ascii") + else: + alg = algorithm.name.encode("ascii") + + evp_md = self._lib.EVP_get_digestbyname(alg) + return evp_md + + def _evp_md_non_null_from_algorithm(self, algorithm: hashes.HashAlgorithm): + evp_md = self._evp_md_from_algorithm(algorithm) + self.openssl_assert(evp_md != self._ffi.NULL) + return evp_md + + def hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): + return False + + evp_md = self._evp_md_from_algorithm(algorithm) + return evp_md != self._ffi.NULL + + def signature_hash_supported( + self, algorithm: hashes.HashAlgorithm + ) -> bool: + # Dedicated check for hashing algorithm use in message digest for + # signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption). + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return False + return self.hash_supported(algorithm) + + def scrypt_supported(self) -> bool: + if self._fips_enabled: + return False + else: + return self._lib.Cryptography_HAS_SCRYPT == 1 + + def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + # FIPS mode still allows SHA1 for HMAC + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return True + + return self.hash_supported(algorithm) + + def create_hash_ctx( + self, algorithm: hashes.HashAlgorithm + ) -> hashes.HashContext: + return _HashContext(self, algorithm) + + def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: + if self._fips_enabled: + # FIPS mode requires AES. TripleDES is disallowed/deprecated in + # FIPS 140-3. + if not isinstance(cipher, self._fips_ciphers): + return False + + try: + adapter = self._cipher_registry[type(cipher), type(mode)] + except KeyError: + return False + evp_cipher = adapter(self, cipher, mode) + return self._ffi.NULL != evp_cipher + + def register_cipher_adapter(self, cipher_cls, mode_cls, adapter) -> None: + if (cipher_cls, mode_cls) in self._cipher_registry: + raise ValueError( + "Duplicate registration for: {} {}.".format( + cipher_cls, mode_cls + ) + ) + self._cipher_registry[cipher_cls, mode_cls] = adapter + + def _register_default_ciphers(self) -> None: + for cipher_cls in [AES, AES128, AES256]: + for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]: + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName( + "{cipher.name}-{cipher.key_size}-{mode.name}" + ), + ) + for mode_cls in [CBC, CTR, ECB, OFB, CFB]: + self.register_cipher_adapter( + Camellia, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), + ) + for mode_cls in [CBC, CFB, CFB8, OFB]: + self.register_cipher_adapter( + TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}") + ) + self.register_cipher_adapter( + TripleDES, ECB, GetCipherByName("des-ede3") + ) + self.register_cipher_adapter( + ChaCha20, type(None), GetCipherByName("chacha20") + ) + self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + for mode_cls in [ECB, CBC, OFB, CFB, CTR]: + self.register_cipher_adapter( + SM4, mode_cls, GetCipherByName("sm4-{mode.name}") + ) + # Don't register legacy ciphers if they're unavailable. Hypothetically + # this wouldn't be necessary because we test availability by seeing if + # we get an EVP_CIPHER * in the _CipherContext __init__, but OpenSSL 3 + # will return a valid pointer even though the cipher is unavailable. + if ( + self._binding._legacy_provider_loaded + or not self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER + ): + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + _BlowfishInternal, + mode_cls, + GetCipherByName("bf-{mode.name}"), + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + _SEEDInternal, + mode_cls, + GetCipherByName("seed-{mode.name}"), + ) + for cipher_cls, mode_cls in itertools.product( + [_CAST5Internal, _IDEAInternal], + [CBC, OFB, CFB, ECB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{mode.name}"), + ) + self.register_cipher_adapter( + ARC4, type(None), GetCipherByName("rc4") + ) + # We don't actually support RC2, this is just used by some tests. + self.register_cipher_adapter( + _RC2, type(None), GetCipherByName("rc2") + ) + + def create_symmetric_encryption_ctx( + self, cipher: CipherAlgorithm, mode: Mode + ) -> _CipherContext: + return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) + + def create_symmetric_decryption_ctx( + self, cipher: CipherAlgorithm, mode: Mode + ) -> _CipherContext: + return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT) + + def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + return self.hmac_supported(algorithm) + + def derive_pbkdf2_hmac( + self, + algorithm: hashes.HashAlgorithm, + length: int, + salt: bytes, + iterations: int, + key_material: bytes, + ) -> bytes: + buf = self._ffi.new("unsigned char[]", length) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.PKCS5_PBKDF2_HMAC( + key_material_ptr, + len(key_material), + salt, + len(salt), + iterations, + evp_md, + length, + buf, + ) + self.openssl_assert(res == 1) + return self._ffi.buffer(buf)[:] + + def _consume_errors(self) -> typing.List[rust_openssl.OpenSSLError]: + return rust_openssl.capture_error_stack() + + def _bn_to_int(self, bn) -> int: + assert bn != self._ffi.NULL + self.openssl_assert(not self._lib.BN_is_negative(bn)) + + bn_num_bytes = self._lib.BN_num_bytes(bn) + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + # A zero length means the BN has value 0 + self.openssl_assert(bin_len >= 0) + val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + return val + + def _int_to_bn(self, num: int, bn=None): + """ + Converts a python integer to a BIGNUM. The returned BIGNUM will not + be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will + be discarded after use. + """ + assert bn is None or bn != self._ffi.NULL + + if bn is None: + bn = self._ffi.NULL + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn) + self.openssl_assert(bn_ptr != self._ffi.NULL) + return bn_ptr + + def generate_rsa_private_key( + self, public_exponent: int, key_size: int + ) -> rsa.RSAPrivateKey: + rsa._verify_rsa_parameters(public_exponent, key_size) + + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + + bn = self._int_to_bn(public_exponent) + bn = self._ffi.gc(bn, self._lib.BN_free) + + res = self._lib.RSA_generate_key_ex( + rsa_cdata, key_size, bn, self._ffi.NULL + ) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + # We can skip RSA key validation here since we just generated the key + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, unsafe_skip_rsa_key_validation=True + ) + + def generate_rsa_parameters_supported( + self, public_exponent: int, key_size: int + ) -> bool: + return ( + public_exponent >= 3 + and public_exponent & 1 != 0 + and key_size >= 512 + ) + + def load_rsa_private_numbers( + self, + numbers: rsa.RSAPrivateNumbers, + unsafe_skip_rsa_key_validation: bool, + ) -> rsa.RSAPrivateKey: + rsa._check_private_key_components( + numbers.p, + numbers.q, + numbers.d, + numbers.dmp1, + numbers.dmq1, + numbers.iqmp, + numbers.public_numbers.e, + numbers.public_numbers.n, + ) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + d = self._int_to_bn(numbers.d) + dmp1 = self._int_to_bn(numbers.dmp1) + dmq1 = self._int_to_bn(numbers.dmq1) + iqmp = self._int_to_bn(numbers.iqmp) + e = self._int_to_bn(numbers.public_numbers.e) + n = self._int_to_bn(numbers.public_numbers.n) + res = self._lib.RSA_set0_factors(rsa_cdata, p, q) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, d) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey( + self, + rsa_cdata, + evp_pkey, + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) + + def load_rsa_public_numbers( + self, numbers: rsa.RSAPublicNumbers + ) -> rsa.RSAPublicKey: + rsa._check_public_key_components(numbers.e, numbers.n) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + e = self._int_to_bn(numbers.e) + n = self._int_to_bn(numbers.n) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + + def _create_evp_pkey_gc(self): + evp_pkey = self._lib.EVP_PKEY_new() + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return evp_pkey + + def _rsa_cdata_to_evp_pkey(self, rsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _bytes_to_bio(self, data: bytes) -> _MemoryBIO: + """ + Return a _MemoryBIO namedtuple of (BIO, char*). + + The char* is the storage for the BIO and it must stay alive until the + BIO is finished with. + """ + data_ptr = self._ffi.from_buffer(data) + bio = self._lib.BIO_new_mem_buf(data_ptr, len(data)) + self.openssl_assert(bio != self._ffi.NULL) + + return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr) + + def _create_mem_bio_gc(self): + """ + Creates an empty memory BIO. + """ + bio_method = self._lib.BIO_s_mem() + self.openssl_assert(bio_method != self._ffi.NULL) + bio = self._lib.BIO_new(bio_method) + self.openssl_assert(bio != self._ffi.NULL) + bio = self._ffi.gc(bio, self._lib.BIO_free) + return bio + + def _read_mem_bio(self, bio) -> bytes: + """ + Reads a memory BIO. This only works on memory BIOs. + """ + buf = self._ffi.new("char **") + buf_len = self._lib.BIO_get_mem_data(bio, buf) + self.openssl_assert(buf_len > 0) + self.openssl_assert(buf[0] != self._ffi.NULL) + bio_data = self._ffi.buffer(buf[0], buf_len)[:] + return bio_data + + def _evp_pkey_to_private_key( + self, evp_pkey, unsafe_skip_rsa_key_validation: bool + ) -> PrivateKeyTypes: + """ + Return the appropriate type of PrivateKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPrivateKey( + self, + rsa_cdata, + evp_pkey, + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) + elif ( + key_type == self._lib.EVP_PKEY_RSA_PSS + and not self._lib.CRYPTOGRAPHY_IS_LIBRESSL + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + and not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E + ): + # At the moment the way we handle RSA PSS keys is to strip the + # PSS constraints from them and treat them as normal RSA keys + # Unfortunately the RSA * itself tracks this data so we need to + # extract, serialize, and reload it without the constraints. + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + bio = self._create_mem_bio_gc() + res = self._lib.i2d_RSAPrivateKey_bio(bio, rsa_cdata) + self.openssl_assert(res == 1) + return self.load_der_private_key( + self._read_mem_bio(bio), + password=None, + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPrivateKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _Ed25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _X448PrivateKey(self, evp_pkey) + elif key_type == self._lib.EVP_PKEY_X25519: + return rust_openssl.x25519.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _Ed448PrivateKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + elif ( + key_type == self._lib.EVP_PKEY_RSA_PSS + and not self._lib.CRYPTOGRAPHY_IS_LIBRESSL + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + and not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E + ): + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + bio = self._create_mem_bio_gc() + res = self._lib.i2d_RSAPublicKey_bio(bio, rsa_cdata) + self.openssl_assert(res == 1) + return self.load_der_public_key(self._read_mem_bio(bio)) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + if ec_cdata == self._ffi.NULL: + errors = self._consume_errors() + raise ValueError("Unable to load EC key", errors) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPublicKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _Ed25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _X448PublicKey(self, evp_pkey) + elif key_type == self._lib.EVP_PKEY_X25519: + return rust_openssl.x25519.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL + return _Ed448PublicKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return False + + return isinstance( + algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ) + + def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool: + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + # SHA1 is permissible in MGF1 in FIPS even when SHA1 is blocked + # as signature algorithm. + if self._fips_enabled and isinstance( + padding._mgf._algorithm, hashes.SHA1 + ): + return True + else: + return self.hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return self._oaep_hash_supported( + padding._mgf._algorithm + ) and self._oaep_hash_supported(padding._algorithm) + else: + return False + + def rsa_encryption_supported(self, padding: AsymmetricPadding) -> bool: + if self._fips_enabled and isinstance(padding, PKCS1v15): + return False + else: + return self.rsa_padding_supported(padding) + + def generate_dsa_parameters(self, key_size: int) -> dsa.DSAParameters: + if key_size not in (1024, 2048, 3072, 4096): + raise ValueError( + "Key size must be 1024, 2048, 3072, or 4096 bits." + ) + + ctx = self._lib.DSA_new() + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + + res = self._lib.DSA_generate_parameters_ex( + ctx, + key_size, + self._ffi.NULL, + 0, + self._ffi.NULL, + self._ffi.NULL, + self._ffi.NULL, + ) + + self.openssl_assert(res == 1) + + return _DSAParameters(self, ctx) + + def generate_dsa_private_key( + self, parameters: dsa.DSAParameters + ) -> dsa.DSAPrivateKey: + ctx = self._lib.DSAparams_dup( + parameters._dsa_cdata # type: ignore[attr-defined] + ) + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + self._lib.DSA_generate_key(ctx) + evp_pkey = self._dsa_cdata_to_evp_pkey(ctx) + + return _DSAPrivateKey(self, ctx, evp_pkey) + + def generate_dsa_private_key_and_parameters( + self, key_size: int + ) -> dsa.DSAPrivateKey: + parameters = self.generate_dsa_parameters(key_size) + return self.generate_dsa_private_key(parameters) + + def _dsa_cdata_set_values( + self, dsa_cdata, p, q, g, pub_key, priv_key + ) -> None: + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + def load_dsa_private_numbers( + self, numbers: dsa.DSAPrivateNumbers + ) -> dsa.DSAPrivateKey: + dsa._check_dsa_private_numbers(numbers) + parameter_numbers = numbers.public_numbers.parameter_numbers + + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(parameter_numbers.p) + q = self._int_to_bn(parameter_numbers.q) + g = self._int_to_bn(parameter_numbers.g) + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + + def load_dsa_public_numbers( + self, numbers: dsa.DSAPublicNumbers + ) -> dsa.DSAPublicKey: + dsa._check_dsa_parameters(numbers.parameter_numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.parameter_numbers.p) + q = self._int_to_bn(numbers.parameter_numbers.q) + g = self._int_to_bn(numbers.parameter_numbers.g) + pub_key = self._int_to_bn(numbers.y) + priv_key = self._ffi.NULL + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + + def load_dsa_parameter_numbers( + self, numbers: dsa.DSAParameterNumbers + ) -> dsa.DSAParameters: + dsa._check_dsa_parameters(numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + g = self._int_to_bn(numbers.g) + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DSAParameters(self, dsa_cdata) + + def _dsa_cdata_to_evp_pkey(self, dsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def dsa_supported(self) -> bool: + return not self._fips_enabled + + def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if not self.dsa_supported(): + return False + return self.signature_hash_supported(algorithm) + + def cmac_algorithm_supported(self, algorithm) -> bool: + return self.cipher_supported( + algorithm, CBC(b"\x00" * algorithm.block_size) + ) + + def create_cmac_ctx(self, algorithm: BlockCipherAlgorithm) -> _CMACContext: + return _CMACContext(self, algorithm) + + def load_pem_private_key( + self, + data: bytes, + password: typing.Optional[bytes], + unsafe_skip_rsa_key_validation: bool, + ) -> PrivateKeyTypes: + return self._load_key( + self._lib.PEM_read_bio_PrivateKey, + data, + password, + unsafe_skip_rsa_key_validation, + ) + + def load_pem_public_key(self, data: bytes) -> PublicKeyTypes: + mem_bio = self._bytes_to_bio(data) + # In OpenSSL 3.0.x the PEM_read_bio_PUBKEY function will invoke + # the default password callback if you pass an encrypted private + # key. This is very, very, very bad as the default callback can + # trigger an interactive console prompt, which will hang the + # Python process. We therefore provide our own callback to + # catch this and error out properly. + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + evp_pkey = self._lib.PEM_read_bio_PUBKEY( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_pem_parameters(self, data: bytes) -> dh.DHParameters: + mem_bio = self._bytes_to_bio(data) + # only DH is supported currently + dh_cdata = self._lib.PEM_read_bio_DHparams( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + else: + self._handle_key_loading_error() + + def load_der_private_key( + self, + data: bytes, + password: typing.Optional[bytes], + unsafe_skip_rsa_key_validation: bool, + ) -> PrivateKeyTypes: + # OpenSSL has a function called d2i_AutoPrivateKey that in theory + # handles this automatically, however it doesn't handle encrypted + # private keys. Instead we try to load the key two different ways. + # First we'll try to load it as a traditional key. + bio_data = self._bytes_to_bio(data) + key = self._evp_pkey_from_der_traditional_key(bio_data, password) + if key: + return self._evp_pkey_to_private_key( + key, unsafe_skip_rsa_key_validation + ) + else: + # Finally we try to load it with the method that handles encrypted + # PKCS8 properly. + return self._load_key( + self._lib.d2i_PKCS8PrivateKey_bio, + data, + password, + unsafe_skip_rsa_key_validation, + ) + + def _evp_pkey_from_der_traditional_key(self, bio_data, password): + key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL) + if key != self._ffi.NULL: + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + return key + else: + self._consume_errors() + return None + + def load_der_public_key(self, data: bytes) -> PublicKeyTypes: + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.d2i_RSAPublicKey_bio( + mem_bio.bio, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_der_parameters(self, data: bytes) -> dh.DHParameters: + mem_bio = self._bytes_to_bio(data) + dh_cdata = self._lib.d2i_DHparams_bio(mem_bio.bio, self._ffi.NULL) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + elif self._lib.Cryptography_HAS_EVP_PKEY_DHX: + # We check to see if the is dhx. + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + dh_cdata = self._lib.d2i_DHxparams_bio(mem_bio.bio, self._ffi.NULL) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + + self._handle_key_loading_error() + + def _cert2ossl(self, cert: x509.Certificate) -> typing.Any: + data = cert.public_bytes(serialization.Encoding.DER) + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) + self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) + return x509 + + def _ossl2cert(self, x509_ptr: typing.Any) -> x509.Certificate: + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_bio(bio, x509_ptr) + self.openssl_assert(res == 1) + return x509.load_der_x509_certificate(self._read_mem_bio(bio)) + + def _check_keys_correspond(self, key1, key2) -> None: + if self._lib.EVP_PKEY_cmp(key1._evp_pkey, key2._evp_pkey) != 1: + raise ValueError("Keys do not correspond") + + def _load_key( + self, openssl_read_func, data, password, unsafe_skip_rsa_key_validation + ) -> PrivateKeyTypes: + mem_bio = self._bytes_to_bio(data) + + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + if password is not None: + utils._check_byteslike("password", password) + password_ptr = self._ffi.from_buffer(password) + userdata.password = password_ptr + userdata.length = len(password) + + evp_pkey = openssl_read_func( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + + if evp_pkey == self._ffi.NULL: + if userdata.error != 0: + self._consume_errors() + if userdata.error == -1: + raise TypeError( + "Password was not given but private key is encrypted" + ) + else: + assert userdata.error == -2 + raise ValueError( + "Passwords longer than {} bytes are not supported " + "by this backend.".format(userdata.maxsize - 1) + ) + else: + self._handle_key_loading_error() + + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + if password is not None and userdata.called == 0: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + assert ( + password is not None and userdata.called == 1 + ) or password is None + + return self._evp_pkey_to_private_key( + evp_pkey, unsafe_skip_rsa_key_validation + ) + + def _handle_key_loading_error(self) -> typing.NoReturn: + errors = self._consume_errors() + + if not errors: + raise ValueError( + "Could not deserialize key data. The data may be in an " + "incorrect format or it may be encrypted with an unsupported " + "algorithm." + ) + + elif ( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) + or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, + ) + or ( + self._lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + self._lib.ERR_LIB_PROV, + self._lib.PROV_R_BAD_DECRYPT, + ) + ) + ): + raise ValueError("Bad decrypt. Incorrect password?") + + elif any( + error._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM, + ) + for error in errors + ): + raise ValueError("Unsupported public key algorithm.") + + else: + raise ValueError( + "Could not deserialize key data. The data may be in an " + "incorrect format, it may be encrypted with an unsupported " + "algorithm, or it may be an unsupported key type (e.g. EC " + "curves with explicit parameters).", + errors, + ) + + def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: + try: + curve_nid = self._elliptic_curve_to_nid(curve) + except UnsupportedAlgorithm: + curve_nid = self._lib.NID_undef + + group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) + + if group == self._ffi.NULL: + self._consume_errors() + return False + else: + self.openssl_assert(curve_nid != self._lib.NID_undef) + self._lib.EC_GROUP_free(group) + return True + + def elliptic_curve_signature_algorithm_supported( + self, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + curve: ec.EllipticCurve, + ) -> bool: + # We only support ECDSA right now. + if not isinstance(signature_algorithm, ec.ECDSA): + return False + + return self.elliptic_curve_supported(curve) + + def generate_elliptic_curve_private_key( + self, curve: ec.EllipticCurve + ) -> ec.EllipticCurvePrivateKey: + """ + Generate a new private key on the named curve. + """ + + if self.elliptic_curve_supported(curve): + ec_cdata = self._ec_key_new_by_curve(curve) + + res = self._lib.EC_KEY_generate_key(ec_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm( + f"Backend object does not support {curve.name}.", + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + def load_elliptic_curve_private_numbers( + self, numbers: ec.EllipticCurvePrivateNumbers + ) -> ec.EllipticCurvePrivateKey: + public = numbers.public_numbers + + ec_cdata = self._ec_key_new_by_curve(public.curve) + + private_value = self._ffi.gc( + self._int_to_bn(numbers.private_value), self._lib.BN_clear_free + ) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + + with self._tmp_bn_ctx() as bn_ctx: + self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y, bn_ctx + ) + # derive the expected public point and compare it to the one we + # just set based on the values we were given. If they don't match + # this isn't a valid key pair. + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + set_point = backend._lib.EC_KEY_get0_public_key(ec_cdata) + self.openssl_assert(set_point != self._ffi.NULL) + computed_point = self._lib.EC_POINT_new(group) + self.openssl_assert(computed_point != self._ffi.NULL) + computed_point = self._ffi.gc( + computed_point, self._lib.EC_POINT_free + ) + res = self._lib.EC_POINT_mul( + group, + computed_point, + private_value, + self._ffi.NULL, + self._ffi.NULL, + bn_ctx, + ) + self.openssl_assert(res == 1) + if ( + self._lib.EC_POINT_cmp( + group, set_point, computed_point, bn_ctx + ) + != 0 + ): + raise ValueError("Invalid EC key.") + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_numbers( + self, numbers: ec.EllipticCurvePublicNumbers + ) -> ec.EllipticCurvePublicKey: + ec_cdata = self._ec_key_new_by_curve(numbers.curve) + with self._tmp_bn_ctx() as bn_ctx: + self._ec_key_set_public_key_affine_coordinates( + ec_cdata, numbers.x, numbers.y, bn_ctx + ) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_bytes( + self, curve: ec.EllipticCurve, point_bytes: bytes + ) -> ec.EllipticCurvePublicKey: + ec_cdata = self._ec_key_new_by_curve(curve) + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_oct2point( + group, point, point_bytes, len(point_bytes), bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Invalid public bytes for the given curve") + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def derive_elliptic_curve_private_key( + self, private_value: int, curve: ec.EllipticCurve + ) -> ec.EllipticCurvePrivateKey: + ec_cdata = self._ec_key_new_by_curve(curve) + + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + + value = self._int_to_bn(private_value) + value = self._ffi.gc(value, self._lib.BN_clear_free) + + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_mul( + group, point, value, self._ffi.NULL, self._ffi.NULL, bn_ctx + ) + self.openssl_assert(res == 1) + + bn_x = self._lib.BN_CTX_get(bn_ctx) + bn_y = self._lib.BN_CTX_get(bn_ctx) + + res = self._lib.EC_POINT_get_affine_coordinates( + group, point, bn_x, bn_y, bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Unable to derive key from private_value") + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + private = self._int_to_bn(private_value) + private = self._ffi.gc(private, self._lib.BN_clear_free) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def _ec_key_new_by_curve(self, curve: ec.EllipticCurve): + curve_nid = self._elliptic_curve_to_nid(curve) + return self._ec_key_new_by_curve_nid(curve_nid) + + def _ec_key_new_by_curve_nid(self, curve_nid: int): + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + def elliptic_curve_exchange_algorithm_supported( + self, algorithm: ec.ECDH, curve: ec.EllipticCurve + ) -> bool: + if self._fips_enabled and not isinstance( + curve, self._fips_ecdh_curves + ): + return False + + return self.elliptic_curve_supported(curve) and isinstance( + algorithm, ec.ECDH + ) + + def _ec_cdata_to_evp_pkey(self, ec_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _elliptic_curve_to_nid(self, curve: ec.EllipticCurve) -> int: + """ + Get the NID for a curve name. + """ + + curve_aliases = {"secp192r1": "prime192v1", "secp256r1": "prime256v1"} + + curve_name = curve_aliases.get(curve.name, curve.name) + + curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) + if curve_nid == self._lib.NID_undef: + raise UnsupportedAlgorithm( + f"{curve.name} is not a supported elliptic curve", + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + return curve_nid + + @contextmanager + def _tmp_bn_ctx(self): + bn_ctx = self._lib.BN_CTX_new() + self.openssl_assert(bn_ctx != self._ffi.NULL) + bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free) + self._lib.BN_CTX_start(bn_ctx) + try: + yield bn_ctx + finally: + self._lib.BN_CTX_end(bn_ctx) + + def _ec_key_set_public_key_affine_coordinates( + self, + ec_cdata, + x: int, + y: int, + bn_ctx, + ) -> None: + """ + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + if x < 0 or y < 0: + raise ValueError( + "Invalid EC key. Both x and y must be non-negative." + ) + + x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free) + y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free) + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + res = self._lib.EC_POINT_set_affine_coordinates( + group, point, x, y, bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + + def _private_key_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + key, + evp_pkey, + cdata, + ) -> bytes: + # validate argument types + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PrivateFormat): + raise TypeError( + "format must be an item from the PrivateFormat enum" + ) + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Encryption algorithm must be a KeySerializationEncryption " + "instance" + ) + + # validate password + if isinstance(encryption_algorithm, serialization.NoEncryption): + password = b"" + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + password = encryption_algorithm.password + if len(password) > 1023: + raise ValueError( + "Passwords longer than 1023 bytes are not supported by " + "this backend" + ) + elif ( + isinstance( + encryption_algorithm, serialization._KeySerializationEncryption + ) + and encryption_algorithm._format + is format + is serialization.PrivateFormat.OpenSSH + ): + password = encryption_algorithm.password + else: + raise ValueError("Unsupported encryption type") + + # PKCS8 + PEM/DER + if format is serialization.PrivateFormat.PKCS8: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PKCS8PrivateKey_bio + else: + raise ValueError("Unsupported encoding for PKCS8") + return self._private_key_bytes_via_bio( + write_bio, evp_pkey, password + ) + + # TraditionalOpenSSL + PEM/DER + if format is serialization.PrivateFormat.TraditionalOpenSSL: + if self._fips_enabled and not isinstance( + encryption_algorithm, serialization.NoEncryption + ): + raise ValueError( + "Encrypted traditional OpenSSL format is not " + "supported in FIPS mode." + ) + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if encoding is serialization.Encoding.PEM: + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.PEM_write_bio_RSAPrivateKey + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.PEM_write_bio_DSAPrivateKey + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.PEM_write_bio_ECPrivateKey + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._private_key_bytes_via_bio( + write_bio, cdata, password + ) + + if encoding is serialization.Encoding.DER: + if password: + raise ValueError( + "Encryption is not supported for DER encoded " + "traditional OpenSSL keys" + ) + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.i2d_RSAPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.i2d_ECPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.i2d_DSAPrivateKey_bio + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._bio_func_output(write_bio, cdata) + + raise ValueError("Unsupported encoding for TraditionalOpenSSL") + + # OpenSSH + PEM + if format is serialization.PrivateFormat.OpenSSH: + if encoding is serialization.Encoding.PEM: + return ssh._serialize_ssh_private_key( + key, password, encryption_algorithm + ) + + raise ValueError( + "OpenSSH private key format can only be used" + " with PEM encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw. + raise ValueError("format is invalid with this key") + + def _private_key_bytes_via_bio( + self, write_bio, evp_pkey, password + ) -> bytes: + if not password: + evp_cipher = self._ffi.NULL + else: + # This is a curated value that we will update over time. + evp_cipher = self._lib.EVP_get_cipherbyname(b"aes-256-cbc") + + return self._bio_func_output( + write_bio, + evp_pkey, + evp_cipher, + password, + len(password), + self._ffi.NULL, + self._ffi.NULL, + ) + + def _bio_func_output(self, write_bio, *args) -> bytes: + bio = self._create_mem_bio_gc() + res = write_bio(bio, *args) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _public_key_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + key, + evp_pkey, + cdata, + ) -> bytes: + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PublicFormat): + raise TypeError( + "format must be an item from the PublicFormat enum" + ) + + # SubjectPublicKeyInfo + PEM/DER + if format is serialization.PublicFormat.SubjectPublicKeyInfo: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PUBKEY + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PUBKEY_bio + else: + raise ValueError( + "SubjectPublicKeyInfo works only with PEM or DER encoding" + ) + return self._bio_func_output(write_bio, evp_pkey) + + # PKCS1 + PEM/DER + if format is serialization.PublicFormat.PKCS1: + # Only RSA is supported here. + key_type = self._lib.EVP_PKEY_id(evp_pkey) + if key_type != self._lib.EVP_PKEY_RSA: + raise ValueError("PKCS1 format is supported only for RSA keys") + + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_RSAPublicKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_RSAPublicKey_bio + else: + raise ValueError("PKCS1 works only with PEM or DER encoding") + return self._bio_func_output(write_bio, cdata) + + # OpenSSH + OpenSSH + if format is serialization.PublicFormat.OpenSSH: + if encoding is serialization.Encoding.OpenSSH: + return ssh.serialize_ssh_public_key(key) + + raise ValueError( + "OpenSSH format must be used with OpenSSH encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw, CompressedPoint, UncompressedPoint + raise ValueError("format is invalid with this key") + + def dh_supported(self) -> bool: + return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + + def generate_dh_parameters( + self, generator: int, key_size: int + ) -> dh.DHParameters: + if key_size < dh._MIN_MODULUS_SIZE: + raise ValueError( + "DH key_size must be at least {} bits".format( + dh._MIN_MODULUS_SIZE + ) + ) + + if generator not in (2, 5): + raise ValueError("DH generator must be 2 or 5") + + dh_param_cdata = self._lib.DH_new() + self.openssl_assert(dh_param_cdata != self._ffi.NULL) + dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free) + + res = self._lib.DH_generate_parameters_ex( + dh_param_cdata, key_size, generator, self._ffi.NULL + ) + if res != 1: + errors = self._consume_errors() + raise ValueError("Unable to generate DH parameters", errors) + + return _DHParameters(self, dh_param_cdata) + + def _dh_cdata_to_evp_pkey(self, dh_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def generate_dh_private_key( + self, parameters: dh.DHParameters + ) -> dh.DHPrivateKey: + dh_key_cdata = _dh_params_dup( + parameters._dh_cdata, self # type: ignore[attr-defined] + ) + + res = self._lib.DH_generate_key(dh_key_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata) + + return _DHPrivateKey(self, dh_key_cdata, evp_pkey) + + def generate_dh_private_key_and_parameters( + self, generator: int, key_size: int + ) -> dh.DHPrivateKey: + return self.generate_dh_private_key( + self.generate_dh_parameters(generator, key_size) + ) + + def load_dh_private_numbers( + self, numbers: dh.DHPrivateNumbers + ) -> dh.DHPrivateKey: + parameter_numbers = numbers.public_numbers.parameter_numbers + + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not + # equal 11 when the generator is 2 (a quadratic nonresidue). + # We want to ignore that error because p % 24 == 23 is also fine. + # Specifically, g is then a quadratic residue. Within the context of + # Diffie-Hellman this means it can only generate half the possible + # values. That sounds bad, but quadratic nonresidues leak a bit of + # the key to the attacker in exchange for having the full key space + # available. See: https://crypto.stackexchange.com/questions/12961 + if codes[0] != 0 and not ( + parameter_numbers.g == 2 + and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 + ): + raise ValueError("DH private numbers did not pass safety checks.") + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPrivateKey(self, dh_cdata, evp_pkey) + + def load_dh_public_numbers( + self, numbers: dh.DHPublicNumbers + ) -> dh.DHPublicKey: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + parameter_numbers = numbers.parameter_numbers + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.y) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPublicKey(self, dh_cdata, evp_pkey) + + def load_dh_parameter_numbers( + self, numbers: dh.DHParameterNumbers + ) -> dh.DHParameters: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(numbers.p) + g = self._int_to_bn(numbers.g) + + if numbers.q is not None: + q = self._int_to_bn(numbers.q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_cdata) + + def dh_parameters_supported( + self, p: int, g: int, q: typing.Optional[int] = None + ) -> bool: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(p) + g = self._int_to_bn(g) + + if q is not None: + q = self._int_to_bn(q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + return codes[0] == 0 + + def dh_x942_serialization_supported(self) -> bool: + return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 + + def x25519_load_public_bytes(self, data: bytes) -> x25519.X25519PublicKey: + return rust_openssl.x25519.from_public_bytes(data) + + def x25519_load_private_bytes( + self, data: bytes + ) -> x25519.X25519PrivateKey: + return rust_openssl.x25519.from_private_bytes(data) + + def _evp_pkey_keygen_gc(self, nid): + evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL) + self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) + evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free) + res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) + self.openssl_assert(res == 1) + evp_ppkey = self._ffi.new("EVP_PKEY **") + res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey) + self.openssl_assert(res == 1) + self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) + return evp_pkey + + def x25519_generate_key(self) -> x25519.X25519PrivateKey: + return rust_openssl.x25519.generate_key() + + def x25519_supported(self) -> bool: + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 + + def x448_load_public_bytes(self, data: bytes) -> x448.X448PublicKey: + if len(data) != 56: + raise ValueError("An X448 public key is 56 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_X448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PublicKey(self, evp_pkey) + + def x448_load_private_bytes(self, data: bytes) -> x448.X448PrivateKey: + if len(data) != 56: + raise ValueError("An X448 private key is 56 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PrivateKey(self, evp_pkey) + + def x448_generate_key(self) -> x448.X448PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448) + return _X448PrivateKey(self, evp_pkey) + + def x448_supported(self) -> bool: + if self._fips_enabled: + return False + return ( + not self._lib.CRYPTOGRAPHY_IS_LIBRESSL + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ) + + def ed25519_supported(self) -> bool: + if self._fips_enabled: + return False + return self._lib.CRYPTOGRAPHY_HAS_WORKING_ED25519 + + def ed25519_load_public_bytes( + self, data: bytes + ) -> ed25519.Ed25519PublicKey: + utils._check_bytes("data", data) + + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 public key is 32 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED25519, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PublicKey(self, evp_pkey) + + def ed25519_load_private_bytes( + self, data: bytes + ) -> ed25519.Ed25519PrivateKey: + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 private key is 32 bytes long") + + utils._check_byteslike("data", data) + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PrivateKey(self, evp_pkey) + + def ed25519_generate_key(self) -> ed25519.Ed25519PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) + return _Ed25519PrivateKey(self, evp_pkey) + + def ed448_supported(self) -> bool: + if self._fips_enabled: + return False + return ( + not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ) + + def ed448_load_public_bytes(self, data: bytes) -> ed448.Ed448PublicKey: + utils._check_bytes("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 public key is 57 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PublicKey(self, evp_pkey) + + def ed448_load_private_bytes(self, data: bytes) -> ed448.Ed448PrivateKey: + utils._check_byteslike("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 private key is 57 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PrivateKey(self, evp_pkey) + + def ed448_generate_key(self) -> ed448.Ed448PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) + return _Ed448PrivateKey(self, evp_pkey) + + def derive_scrypt( + self, + key_material: bytes, + salt: bytes, + length: int, + n: int, + r: int, + p: int, + ) -> bytes: + buf = self._ffi.new("unsigned char[]", length) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.EVP_PBE_scrypt( + key_material_ptr, + len(key_material), + salt, + len(salt), + n, + r, + p, + scrypt._MEM_LIMIT, + buf, + length, + ) + if res != 1: + errors = self._consume_errors() + # memory required formula explained here: + # https://blog.filippo.io/the-scrypt-parameters/ + min_memory = 128 * n * r // (1024**2) + raise MemoryError( + "Not enough memory to derive key. These parameters require" + " {} MB of memory.".format(min_memory), + errors, + ) + return self._ffi.buffer(buf)[:] + + def aead_cipher_supported(self, cipher) -> bool: + cipher_name = aead._aead_cipher_name(cipher) + if self._fips_enabled and cipher_name not in self._fips_aead: + return False + # SIV isn't loaded through get_cipherbyname but instead a new fetch API + # only available in 3.0+. But if we know we're on 3.0+ then we know + # it's supported. + if cipher_name.endswith(b"-siv"): + return self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER == 1 + else: + return ( + self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL + ) + + def _zero_data(self, data, length: int) -> None: + # We clear things this way because at the moment we're not + # sure of a better way that can guarantee it overwrites the + # memory of a bytearray and doesn't just replace the underlying char *. + for i in range(length): + data[i] = 0 + + @contextlib.contextmanager + def _zeroed_null_terminated_buf(self, data): + """ + This method takes bytes, which can be a bytestring or a mutable + buffer like a bytearray, and yields a null-terminated version of that + data. This is required because PKCS12_parse doesn't take a length with + its password char * and ffi.from_buffer doesn't provide null + termination. So, to support zeroing the data via bytearray we + need to build this ridiculous construct that copies the memory, but + zeroes it after use. + """ + if data is None: + yield self._ffi.NULL + else: + data_len = len(data) + buf = self._ffi.new("char[]", data_len + 1) + self._ffi.memmove(buf, data, data_len) + try: + yield buf + finally: + # Cast to a uint8_t * so we can assign by integer + self._zero_data(self._ffi.cast("uint8_t *", buf), data_len) + + def load_key_and_certificates_from_pkcs12( + self, data: bytes, password: typing.Optional[bytes] + ) -> typing.Tuple[ + typing.Optional[PrivateKeyTypes], + typing.Optional[x509.Certificate], + typing.List[x509.Certificate], + ]: + pkcs12 = self.load_pkcs12(data, password) + return ( + pkcs12.key, + pkcs12.cert.certificate if pkcs12.cert else None, + [cert.certificate for cert in pkcs12.additional_certs], + ) + + def load_pkcs12( + self, data: bytes, password: typing.Optional[bytes] + ) -> PKCS12KeyAndCertificates: + if password is not None: + utils._check_byteslike("password", password) + + bio = self._bytes_to_bio(data) + p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL) + if p12 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Could not deserialize PKCS12 data") + + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + evp_pkey_ptr = self._ffi.new("EVP_PKEY **") + x509_ptr = self._ffi.new("X509 **") + sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **") + with self._zeroed_null_terminated_buf(password) as password_buf: + res = self._lib.PKCS12_parse( + p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr + ) + if res == 0: + self._consume_errors() + raise ValueError("Invalid password or PKCS12 data") + + cert = None + key = None + additional_certificates = [] + + if evp_pkey_ptr[0] != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free) + # We don't support turning off RSA key validation when loading + # PKCS12 keys + key = self._evp_pkey_to_private_key( + evp_pkey, unsafe_skip_rsa_key_validation=False + ) + + if x509_ptr[0] != self._ffi.NULL: + x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free) + cert_obj = self._ossl2cert(x509) + name = None + maybe_name = self._lib.X509_alias_get0(x509, self._ffi.NULL) + if maybe_name != self._ffi.NULL: + name = self._ffi.string(maybe_name) + cert = PKCS12Certificate(cert_obj, name) + + if sk_x509_ptr[0] != self._ffi.NULL: + sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free) + num = self._lib.sk_X509_num(sk_x509_ptr[0]) + + # In OpenSSL < 3.0.0 PKCS12 parsing reverses the order of the + # certificates. + indices: typing.Iterable[int] + if ( + self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER + or self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ): + indices = range(num) + else: + indices = reversed(range(num)) + + for i in indices: + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) + addl_cert = self._ossl2cert(x509) + addl_name = None + maybe_name = self._lib.X509_alias_get0(x509, self._ffi.NULL) + if maybe_name != self._ffi.NULL: + addl_name = self._ffi.string(maybe_name) + additional_certificates.append( + PKCS12Certificate(addl_cert, addl_name) + ) + + return PKCS12KeyAndCertificates(key, cert, additional_certificates) + + def serialize_key_and_certificates_to_pkcs12( + self, + name: typing.Optional[bytes], + key: typing.Optional[PKCS12PrivateKeyTypes], + cert: typing.Optional[x509.Certificate], + cas: typing.Optional[typing.List[_PKCS12CATypes]], + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + password = None + if name is not None: + utils._check_bytes("name", name) + + if isinstance(encryption_algorithm, serialization.NoEncryption): + nid_cert = -1 + nid_key = -1 + pkcs12_iter = 0 + mac_iter = 0 + mac_alg = self._ffi.NULL + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + # PKCS12 encryption is hopeless trash and can never be fixed. + # OpenSSL 3 supports PBESv2, but Libre and Boring do not, so + # we use PBESv1 with 3DES on the older paths. + if self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + nid_cert = self._lib.NID_aes_256_cbc + nid_key = self._lib.NID_aes_256_cbc + else: + nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + # At least we can set this higher than OpenSSL's default + pkcs12_iter = 20000 + # mac_iter chosen for compatibility reasons, see: + # https://www.openssl.org/docs/man1.1.1/man3/PKCS12_create.html + # Did we mention how lousy PKCS12 encryption is? + mac_iter = 1 + # MAC algorithm can only be set on OpenSSL 3.0.0+ + mac_alg = self._ffi.NULL + password = encryption_algorithm.password + elif ( + isinstance( + encryption_algorithm, serialization._KeySerializationEncryption + ) + and encryption_algorithm._format + is serialization.PrivateFormat.PKCS12 + ): + # Default to OpenSSL's defaults. Behavior will vary based on the + # version of OpenSSL cryptography is compiled against. + nid_cert = 0 + nid_key = 0 + # Use the default iters we use in best available + pkcs12_iter = 20000 + # See the Best Available comment for why this is 1 + mac_iter = 1 + password = encryption_algorithm.password + keycertalg = encryption_algorithm._key_cert_algorithm + if keycertalg is PBES.PBESv1SHA1And3KeyTripleDESCBC: + nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + elif keycertalg is PBES.PBESv2SHA256AndAES256CBC: + if not self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + raise UnsupportedAlgorithm( + "PBESv2 is not supported by this version of OpenSSL" + ) + nid_cert = self._lib.NID_aes_256_cbc + nid_key = self._lib.NID_aes_256_cbc + else: + assert keycertalg is None + # We use OpenSSL's defaults + + if encryption_algorithm._hmac_hash is not None: + if not self._lib.Cryptography_HAS_PKCS12_SET_MAC: + raise UnsupportedAlgorithm( + "Setting MAC algorithm is not supported by this " + "version of OpenSSL." + ) + mac_alg = self._evp_md_non_null_from_algorithm( + encryption_algorithm._hmac_hash + ) + self.openssl_assert(mac_alg != self._ffi.NULL) + else: + mac_alg = self._ffi.NULL + + if encryption_algorithm._kdf_rounds is not None: + pkcs12_iter = encryption_algorithm._kdf_rounds + + else: + raise ValueError("Unsupported key encryption type") + + if cas is None or len(cas) == 0: + sk_x509 = self._ffi.NULL + else: + sk_x509 = self._lib.sk_X509_new_null() + sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) + + # This list is to keep the x509 values alive until end of function + ossl_cas = [] + for ca in cas: + if isinstance(ca, PKCS12Certificate): + ca_alias = ca.friendly_name + ossl_ca = self._cert2ossl(ca.certificate) + if ca_alias is None: + res = self._lib.X509_alias_set1( + ossl_ca, self._ffi.NULL, -1 + ) + else: + res = self._lib.X509_alias_set1( + ossl_ca, ca_alias, len(ca_alias) + ) + self.openssl_assert(res == 1) + else: + ossl_ca = self._cert2ossl(ca) + ossl_cas.append(ossl_ca) + res = self._lib.sk_X509_push(sk_x509, ossl_ca) + backend.openssl_assert(res >= 1) + + with self._zeroed_null_terminated_buf(password) as password_buf: + with self._zeroed_null_terminated_buf(name) as name_buf: + ossl_cert = self._cert2ossl(cert) if cert else self._ffi.NULL + if key is not None: + evp_pkey = key._evp_pkey # type: ignore[union-attr] + else: + evp_pkey = self._ffi.NULL + + p12 = self._lib.PKCS12_create( + password_buf, + name_buf, + evp_pkey, + ossl_cert, + sk_x509, + nid_key, + nid_cert, + pkcs12_iter, + mac_iter, + 0, + ) + + if ( + self._lib.Cryptography_HAS_PKCS12_SET_MAC + and mac_alg != self._ffi.NULL + ): + self._lib.PKCS12_set_mac( + p12, + password_buf, + -1, + self._ffi.NULL, + 0, + mac_iter, + mac_alg, + ) + + self.openssl_assert(p12 != self._ffi.NULL) + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + + bio = self._create_mem_bio_gc() + res = self._lib.i2d_PKCS12_bio(bio, p12) + self.openssl_assert(res > 0) + return self._read_mem_bio(bio) + + def poly1305_supported(self) -> bool: + if self._fips_enabled: + return False + return self._lib.Cryptography_HAS_POLY1305 == 1 + + def create_poly1305_ctx(self, key: bytes) -> _Poly1305Context: + utils._check_byteslike("key", key) + if len(key) != _POLY1305_KEY_SIZE: + raise ValueError("A poly1305 key is 32 bytes long") + + return _Poly1305Context(self, key) + + def pkcs7_supported(self) -> bool: + return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + + def load_pem_pkcs7_certificates( + self, data: bytes + ) -> typing.List[x509.Certificate]: + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.PEM_read_bio_PKCS7( + bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def load_der_pkcs7_certificates( + self, data: bytes + ) -> typing.List[x509.Certificate]: + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.d2i_PKCS7_bio(bio.bio, self._ffi.NULL) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def _load_pkcs7_certificates(self, p7) -> typing.List[x509.Certificate]: + nid = self._lib.OBJ_obj2nid(p7.type) + self.openssl_assert(nid != self._lib.NID_undef) + if nid != self._lib.NID_pkcs7_signed: + raise UnsupportedAlgorithm( + "Only basic signed structures are currently supported. NID" + " for this data was {}".format(nid), + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + sk_x509 = p7.d.sign.cert + num = self._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + cert = self._ossl2cert(x509) + certs.append(cert) + + return certs + + +class GetCipherByName: + def __init__(self, fmt: str): + self._fmt = fmt + + def __call__(self, backend: Backend, cipher: CipherAlgorithm, mode: Mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + evp_cipher = backend._lib.EVP_get_cipherbyname( + cipher_name.encode("ascii") + ) + + # try EVP_CIPHER_fetch if present + if ( + evp_cipher == backend._ffi.NULL + and backend._lib.Cryptography_HAS_300_EVP_CIPHER + ): + evp_cipher = backend._lib.EVP_CIPHER_fetch( + backend._ffi.NULL, + cipher_name.encode("ascii"), + backend._ffi.NULL, + ) + + backend._consume_errors() + return evp_cipher + + +def _get_xts_cipher(backend: Backend, cipher: AES, mode): + cipher_name = f"aes-{cipher.key_size // 2}-xts" + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +backend = Backend() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ciphers.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ciphers.py new file mode 100644 index 0000000000000000000000000000000000000000..075d68fb905754d3a0ca3ba65d82841639d00f58 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ciphers.py @@ -0,0 +1,281 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import ciphers +from cryptography.hazmat.primitives.ciphers import algorithms, modes + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _CipherContext: + _ENCRYPT = 1 + _DECRYPT = 0 + _MAX_CHUNK_SIZE = 2**30 - 1 + + def __init__( + self, backend: "Backend", cipher, mode, operation: int + ) -> None: + self._backend = backend + self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag: typing.Optional[bytes] = None + + if isinstance(self._cipher, ciphers.BlockCipherAlgorithm): + self._block_size_bytes = self._cipher.block_size // 8 + else: + self._block_size_bytes = 1 + + ctx = self._backend._lib.EVP_CIPHER_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_CIPHER_CTX_free + ) + + registry = self._backend._cipher_registry + try: + adapter = registry[type(cipher), type(mode)] + except KeyError: + raise UnsupportedAlgorithm( + "cipher {} in {} mode is not supported " + "by this backend.".format( + cipher.name, mode.name if mode else mode + ), + _Reasons.UNSUPPORTED_CIPHER, + ) + + evp_cipher = adapter(self._backend, cipher, mode) + if evp_cipher == self._backend._ffi.NULL: + msg = f"cipher {cipher.name} " + if mode is not None: + msg += f"in {mode.name} mode " + msg += ( + "is not supported by this backend (Your version of OpenSSL " + "may be too old. Current version: {}.)" + ).format(self._backend.openssl_version_text()) + raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER) + + if isinstance(mode, modes.ModeWithInitializationVector): + iv_nonce = self._backend._ffi.from_buffer( + mode.initialization_vector + ) + elif isinstance(mode, modes.ModeWithTweak): + iv_nonce = self._backend._ffi.from_buffer(mode.tweak) + elif isinstance(mode, modes.ModeWithNonce): + iv_nonce = self._backend._ffi.from_buffer(mode.nonce) + elif isinstance(cipher, algorithms.ChaCha20): + iv_nonce = self._backend._ffi.from_buffer(cipher.nonce) + else: + iv_nonce = self._backend._ffi.NULL + # begin init with cipher and operation type + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + operation, + ) + self._backend.openssl_assert(res != 0) + # set the key length to handle variable key ciphers + res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( + ctx, len(cipher.key) + ) + self._backend.openssl_assert(res != 0) + if isinstance(mode, modes.GCM): + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(iv_nonce), + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res != 0) + if mode.tag is not None: + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(mode.tag), + mode.tag, + ) + self._backend.openssl_assert(res != 0) + self._tag = mode.tag + + # pass key/iv + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.from_buffer(cipher.key), + iv_nonce, + operation, + ) + + # Check for XTS mode duplicate keys error + errors = self._backend._consume_errors() + lib = self._backend._lib + if res == 0 and ( + ( + lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + and errors[0]._lib_reason_match( + lib.ERR_LIB_EVP, lib.EVP_R_XTS_DUPLICATED_KEYS + ) + ) + or ( + lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + lib.ERR_LIB_PROV, lib.PROV_R_XTS_DUPLICATED_KEYS + ) + ) + ): + raise ValueError("In XTS mode duplicated keys are not allowed") + + self._backend.openssl_assert(res != 0, errors=errors) + + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data: bytes) -> bytes: + buf = bytearray(len(data) + self._block_size_bytes - 1) + n = self.update_into(data, buf) + return bytes(buf[:n]) + + def update_into(self, data: bytes, buf: bytes) -> int: + total_data_len = len(data) + if len(buf) < (total_data_len + self._block_size_bytes - 1): + raise ValueError( + "buffer must be at least {} bytes for this " + "payload".format(len(data) + self._block_size_bytes - 1) + ) + + data_processed = 0 + total_out = 0 + outlen = self._backend._ffi.new("int *") + baseoutbuf = self._backend._ffi.from_buffer(buf, require_writable=True) + baseinbuf = self._backend._ffi.from_buffer(data) + + while data_processed != total_data_len: + outbuf = baseoutbuf + total_out + inbuf = baseinbuf + data_processed + inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed) + + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, outbuf, outlen, inbuf, inlen + ) + if res == 0 and isinstance(self._mode, modes.XTS): + self._backend._consume_errors() + raise ValueError( + "In XTS mode you must supply at least a full block in the " + "first update call. For AES this is 16 bytes." + ) + else: + self._backend.openssl_assert(res != 0) + data_processed += inlen + total_out += outlen[0] + + return total_out + + def finalize(self) -> bytes: + if ( + self._operation == self._DECRYPT + and isinstance(self._mode, modes.ModeWithAuthenticationTag) + and self.tag is None + ): + raise ValueError( + "Authentication tag must be provided when decrypting." + ) + + buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes) + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) + if res == 0: + errors = self._backend._consume_errors() + + if not errors and isinstance(self._mode, modes.GCM): + raise InvalidTag + + lib = self._backend._lib + self._backend.openssl_assert( + errors[0]._lib_reason_match( + lib.ERR_LIB_EVP, + lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + ) + or ( + lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + lib.ERR_LIB_PROV, + lib.PROV_R_WRONG_FINAL_BLOCK_LENGTH, + ) + ) + or ( + lib.CRYPTOGRAPHY_IS_BORINGSSL + and errors[0].reason + == lib.CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH + ), + errors=errors, + ) + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length." + ) + + if ( + isinstance(self._mode, modes.GCM) + and self._operation == self._ENCRYPT + ): + tag_buf = self._backend._ffi.new( + "unsigned char[]", self._block_size_bytes + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, + self._backend._lib.EVP_CTRL_AEAD_GET_TAG, + self._block_size_bytes, + tag_buf, + ) + self._backend.openssl_assert(res != 0) + self._tag = self._backend._ffi.buffer(tag_buf)[:] + + res = self._backend._lib.EVP_CIPHER_CTX_reset(self._ctx) + self._backend.openssl_assert(res == 1) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def finalize_with_tag(self, tag: bytes) -> bytes: + tag_len = len(tag) + if tag_len < self._mode._min_tag_length: + raise ValueError( + "Authentication tag must be {} bytes or longer.".format( + self._mode._min_tag_length + ) + ) + elif tag_len > self._block_size_bytes: + raise ValueError( + "Authentication tag cannot be more than {} bytes.".format( + self._block_size_bytes + ) + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + self._backend.openssl_assert(res != 0) + self._tag = tag + return self.finalize() + + def authenticate_additional_data(self, data: bytes) -> None: + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, + self._backend._ffi.NULL, + outlen, + self._backend._ffi.from_buffer(data), + len(data), + ) + self._backend.openssl_assert(res != 0) + + @property + def tag(self) -> typing.Optional[bytes]: + return self._tag diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/cmac.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/cmac.py new file mode 100644 index 0000000000000000000000000000000000000000..6f73632941797ddc73b1ed0d25cb290d4c3235a8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/cmac.py @@ -0,0 +1,87 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.ciphers.modes import CBC + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + from cryptography.hazmat.primitives import ciphers + + +class _CMACContext: + def __init__( + self, + backend: "Backend", + algorithm: "ciphers.BlockCipherAlgorithm", + ctx=None, + ) -> None: + if not backend.cmac_algorithm_supported(algorithm): + raise UnsupportedAlgorithm( + "This backend does not support CMAC.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + self._backend = backend + self._key = algorithm.key + self._algorithm = algorithm + self._output_length = algorithm.block_size // 8 + + if ctx is None: + registry = self._backend._cipher_registry + adapter = registry[type(algorithm), CBC] + + evp_cipher = adapter(self._backend, algorithm, CBC) + + ctx = self._backend._lib.CMAC_CTX_new() + + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) + + key_ptr = self._backend._ffi.from_buffer(self._key) + res = self._backend._lib.CMAC_Init( + ctx, + key_ptr, + len(self._key), + evp_cipher, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res == 1) + + self._ctx = ctx + + def update(self, data: bytes) -> None: + res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) + self._backend.openssl_assert(res == 1) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new("unsigned char[]", self._output_length) + length = self._backend._ffi.new("size_t *", self._output_length) + res = self._backend._lib.CMAC_Final(self._ctx, buf, length) + self._backend.openssl_assert(res == 1) + + self._ctx = None + + return self._backend._ffi.buffer(buf)[:] + + def copy(self) -> "_CMACContext": + copied_ctx = self._backend._lib.CMAC_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.CMAC_CTX_free + ) + res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res == 1) + return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx) + + def verify(self, signature: bytes) -> None: + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py new file mode 100644 index 0000000000000000000000000000000000000000..df91d6d8a73e9555001694f85c2662f4b8e9e25c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -0,0 +1,31 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography import x509 + +# CRLReason ::= ENUMERATED { +# unspecified (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# -- value 7 is not used +# removeFromCRL (8), +# privilegeWithdrawn (9), +# aACompromise (10) } +_CRL_ENTRY_REASON_ENUM_TO_CODE = { + x509.ReasonFlags.unspecified: 0, + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.remove_from_crl: 8, + x509.ReasonFlags.privilege_withdrawn: 9, + x509.ReasonFlags.aa_compromise: 10, +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dh.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dh.py new file mode 100644 index 0000000000000000000000000000000000000000..87d6fb8af69433090ce5a58ef4fe267cb4e087e7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dh.py @@ -0,0 +1,317 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import dh + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _dh_params_dup(dh_cdata, backend: "Backend"): + lib = backend._lib + ffi = backend._ffi + + param_cdata = lib.DHparams_dup(dh_cdata) + backend.openssl_assert(param_cdata != ffi.NULL) + param_cdata = ffi.gc(param_cdata, lib.DH_free) + if lib.CRYPTOGRAPHY_IS_LIBRESSL: + # In libressl DHparams_dup don't copy q + q = ffi.new("BIGNUM **") + lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) + q_dup = lib.BN_dup(q[0]) + res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL) + backend.openssl_assert(res == 1) + + return param_cdata + + +def _dh_cdata_to_parameters(dh_cdata, backend: "Backend") -> "_DHParameters": + param_cdata = _dh_params_dup(dh_cdata, backend) + return _DHParameters(backend, param_cdata) + + +class _DHParameters(dh.DHParameters): + def __init__(self, backend: "Backend", dh_cdata): + self._backend = backend + self._dh_cdata = dh_cdata + + def parameter_numbers(self) -> dh.DHParameterNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + q_val: typing.Optional[int] + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + return dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ) + + def generate_private_key(self) -> dh.DHPrivateKey: + return self._backend.generate_dh_private_key(self) + + def parameter_bytes( + self, + encoding: serialization.Encoding, + format: serialization.ParameterFormat, + ) -> bytes: + if encoding is serialization.Encoding.OpenSSH: + raise TypeError("OpenSSH encoding is not supported") + + if format is not serialization.ParameterFormat.PKCS3: + raise ValueError("Only PKCS3 serialization is supported") + + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, self._backend._ffi.NULL, q, self._backend._ffi.NULL + ) + if ( + q[0] != self._backend._ffi.NULL + and not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX + ): + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + if encoding is serialization.Encoding.PEM: + if q[0] != self._backend._ffi.NULL: + write_bio = self._backend._lib.PEM_write_bio_DHxparams + else: + write_bio = self._backend._lib.PEM_write_bio_DHparams + elif encoding is serialization.Encoding.DER: + if q[0] != self._backend._ffi.NULL: + write_bio = self._backend._lib.i2d_DHxparams_bio + else: + write_bio = self._backend._lib.i2d_DHparams_bio + else: + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._backend._create_mem_bio_gc() + res = write_bio(bio, self._dh_cdata) + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + +def _get_dh_num_bits(backend, dh_cdata) -> int: + p = backend._ffi.new("BIGNUM **") + backend._lib.DH_get0_pqg(dh_cdata, p, backend._ffi.NULL, backend._ffi.NULL) + backend.openssl_assert(p[0] != backend._ffi.NULL) + return backend._lib.BN_num_bits(p[0]) + + +class _DHPrivateKey(dh.DHPrivateKey): + def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bytes = self._backend._lib.DH_size(dh_cdata) + + @property + def key_size(self) -> int: + return _get_dh_num_bits(self._backend, self._dh_cdata) + + def private_numbers(self) -> dh.DHPrivateNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dh.DHPrivateNumbers( + public_numbers=dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def exchange(self, peer_public_key: dh.DHPublicKey) -> bytes: + if not isinstance(peer_public_key, _DHPublicKey): + raise TypeError("peer_public_key must be a DHPublicKey") + + ctx = self._backend._lib.EVP_PKEY_CTX_new( + self._evp_pkey, self._backend._ffi.NULL + ) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.EVP_PKEY_CTX_free) + res = self._backend._lib.EVP_PKEY_derive_init(ctx) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_PKEY_derive_set_peer( + ctx, peer_public_key._evp_pkey + ) + # Invalid kex errors here in OpenSSL 3.0 because checks were moved + # to EVP_PKEY_derive_set_peer + self._exchange_assert(res == 1) + keylen = self._backend._ffi.new("size_t *") + res = self._backend._lib.EVP_PKEY_derive( + ctx, self._backend._ffi.NULL, keylen + ) + # Invalid kex errors here in OpenSSL < 3 + self._exchange_assert(res == 1) + self._backend.openssl_assert(keylen[0] > 0) + buf = self._backend._ffi.new("unsigned char[]", keylen[0]) + res = self._backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + self._backend.openssl_assert(res == 1) + + key = self._backend._ffi.buffer(buf, keylen[0])[:] + pad = self._key_size_bytes - len(key) + + if pad > 0: + key = (b"\x00" * pad) + key + + return key + + def _exchange_assert(self, ok: bool) -> None: + if not ok: + errors = self._backend._consume_errors() + raise ValueError( + "Error computing shared key.", + errors, + ) + + def public_key(self) -> dh.DHPublicKey: + dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL) + + res = self._backend._lib.DH_set0_key( + dh_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata) + return _DHPublicKey(self._backend, dh_cdata, evp_pkey) + + def parameters(self) -> dh.DHParameters: + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if format is not serialization.PrivateFormat.PKCS8: + raise ValueError( + "DH private keys support only PKCS8 serialization" + ) + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dh_cdata, + ) + + +class _DHPublicKey(dh.DHPublicKey): + def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata) + + @property + def key_size(self) -> int: + return self._key_size_bits + + def public_numbers(self) -> dh.DHPublicNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self) -> dh.DHParameters: + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if format is not serialization.PublicFormat.SubjectPublicKeyInfo: + raise ValueError( + "DH public keys support only " + "SubjectPublicKeyInfo serialization" + ) + + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dsa.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dsa.py new file mode 100644 index 0000000000000000000000000000000000000000..15bd84a7b5a5150313ca03e7df74da4db15a8327 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/dsa.py @@ -0,0 +1,236 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import dsa +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _dsa_sig_sign( + backend: "Backend", private_key: "_DSAPrivateKey", data: bytes +) -> bytes: + sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) + sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) + buflen = backend._ffi.new("unsigned int *") + + # The first parameter passed to DSA_sign is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_sign( + 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(buflen[0]) + + return backend._ffi.buffer(sig_buf)[: buflen[0]] + + +def _dsa_sig_verify( + backend: "Backend", + public_key: "_DSAPublicKey", + signature: bytes, + data: bytes, +) -> None: + # The first parameter passed to DSA_verify is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_verify( + 0, data, len(data), signature, len(signature), public_key._dsa_cdata + ) + + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +class _DSAParameters(dsa.DSAParameters): + def __init__(self, backend: "Backend", dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + + def parameter_numbers(self) -> dsa.DSAParameterNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + return dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ) + + def generate_private_key(self) -> dsa.DSAPrivateKey: + return self._backend.generate_dsa_private_key(self) + + +class _DSAPrivateKey(dsa.DSAPrivateKey): + _key_size: int + + def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def private_numbers(self) -> dsa.DSAPrivateNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def public_key(self) -> dsa.DSAPublicKey: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + res = self._backend._lib.DSA_set0_key( + dsa_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata) + return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey) + + def parameters(self) -> dsa.DSAParameters: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dsa_cdata, + ) + + def sign( + self, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + data, _ = _calculate_digest_and_algorithm(data, algorithm) + return _dsa_sig_sign(self._backend, self, data) + + +class _DSAPublicKey(dsa.DSAPublicKey): + _key_size: int + + def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def public_numbers(self) -> dsa.DSAPublicNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self) -> dsa.DSAParameters: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify( + self, + signature: bytes, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + data, _ = _calculate_digest_and_algorithm(data, algorithm) + return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ec.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ec.py new file mode 100644 index 0000000000000000000000000000000000000000..969306bcb893c74cba1cde4881ed3454701bc53e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ec.py @@ -0,0 +1,317 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, + _evp_pkey_derive, +) +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _check_signature_algorithm( + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, +) -> None: + if not isinstance(signature_algorithm, ec.ECDSA): + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + +def _ec_key_curve_sn(backend: "Backend", ec_key) -> str: + group = backend._lib.EC_KEY_get0_group(ec_key) + backend.openssl_assert(group != backend._ffi.NULL) + + nid = backend._lib.EC_GROUP_get_curve_name(group) + # The following check is to find EC keys with unnamed curves and raise + # an error for now. + if nid == backend._lib.NID_undef: + raise ValueError( + "ECDSA keys with explicit parameters are unsupported at this time" + ) + + # This is like the above check, but it also catches the case where you + # explicitly encoded a curve with the same parameters as a named curve. + # Don't do that. + if ( + not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + and backend._lib.EC_GROUP_get_asn1_flag(group) == 0 + ): + raise ValueError( + "ECDSA keys with explicit parameters are unsupported at this time" + ) + + curve_name = backend._lib.OBJ_nid2sn(nid) + backend.openssl_assert(curve_name != backend._ffi.NULL) + + sn = backend._ffi.string(curve_name).decode("ascii") + return sn + + +def _mark_asn1_named_ec_curve(backend: "Backend", ec_cdata): + """ + Set the named curve flag on the EC_KEY. This causes OpenSSL to + serialize EC keys along with their curve OID which makes + deserialization easier. + """ + + backend._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) + + +def _check_key_infinity(backend: "Backend", ec_cdata) -> None: + point = backend._lib.EC_KEY_get0_public_key(ec_cdata) + backend.openssl_assert(point != backend._ffi.NULL) + group = backend._lib.EC_KEY_get0_group(ec_cdata) + backend.openssl_assert(group != backend._ffi.NULL) + if backend._lib.EC_POINT_is_at_infinity(group, point): + raise ValueError( + "Cannot load an EC public key where the point is at infinity" + ) + + +def _sn_to_elliptic_curve(backend: "Backend", sn: str) -> ec.EllipticCurve: + try: + return ec._CURVE_TYPES[sn]() + except KeyError: + raise UnsupportedAlgorithm( + f"{sn} is not a supported elliptic curve", + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + +def _ecdsa_sig_sign( + backend: "Backend", private_key: "_EllipticCurvePrivateKey", data: bytes +) -> bytes: + max_size = backend._lib.ECDSA_size(private_key._ec_key) + backend.openssl_assert(max_size > 0) + + sigbuf = backend._ffi.new("unsigned char[]", max_size) + siglen_ptr = backend._ffi.new("unsigned int[]", 1) + res = backend._lib.ECDSA_sign( + 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key + ) + backend.openssl_assert(res == 1) + return backend._ffi.buffer(sigbuf)[: siglen_ptr[0]] + + +def _ecdsa_sig_verify( + backend: "Backend", + public_key: "_EllipticCurvePublicKey", + signature: bytes, + data: bytes, +) -> None: + res = backend._lib.ECDSA_verify( + 0, data, len(data), signature, len(signature), public_key._ec_key + ) + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +class _EllipticCurvePrivateKey(ec.EllipticCurvePrivateKey): + def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + _check_key_infinity(backend, ec_key_cdata) + + @property + def curve(self) -> ec.EllipticCurve: + return self._curve + + @property + def key_size(self) -> int: + return self.curve.key_size + + def exchange( + self, algorithm: ec.ECDH, peer_public_key: ec.EllipticCurvePublicKey + ) -> bytes: + if not ( + self._backend.elliptic_curve_exchange_algorithm_supported( + algorithm, self.curve + ) + ): + raise UnsupportedAlgorithm( + "This backend does not support the ECDH algorithm.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + if peer_public_key.curve.name != self.curve.name: + raise ValueError( + "peer_public_key and self are not on the same curve" + ) + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def public_key(self) -> ec.EllipticCurvePublicKey: + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + + curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) + public_ec_key = self._backend._ec_key_new_by_curve_nid(curve_nid) + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point) + self._backend.openssl_assert(res == 1) + + evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key) + + return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey) + + def private_numbers(self) -> ec.EllipticCurvePrivateNumbers: + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers(), + ) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._ec_key, + ) + + def sign( + self, + data: bytes, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + ) -> bytes: + _check_signature_algorithm(signature_algorithm) + data, _ = _calculate_digest_and_algorithm( + data, + signature_algorithm.algorithm, + ) + return _ecdsa_sig_sign(self._backend, self, data) + + +class _EllipticCurvePublicKey(ec.EllipticCurvePublicKey): + def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + _check_key_infinity(backend, ec_key_cdata) + + @property + def curve(self) -> ec.EllipticCurve: + return self._curve + + @property + def key_size(self) -> int: + return self.curve.key_size + + def public_numbers(self) -> ec.EllipticCurvePublicNumbers: + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + with self._backend._tmp_bn_ctx() as bn_ctx: + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = self._backend._lib.EC_POINT_get_affine_coordinates( + group, point, bn_x, bn_y, bn_ctx + ) + self._backend.openssl_assert(res == 1) + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + + return ec.EllipticCurvePublicNumbers(x=x, y=y, curve=self._curve) + + def _encode_point(self, format: serialization.PublicFormat) -> bytes: + if format is serialization.PublicFormat.CompressedPoint: + conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED + else: + assert format is serialization.PublicFormat.UncompressedPoint + conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + with self._backend._tmp_bn_ctx() as bn_ctx: + buflen = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx + ) + self._backend.openssl_assert(buflen > 0) + buf = self._backend._ffi.new("char[]", buflen) + res = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, buf, buflen, bn_ctx + ) + self._backend.openssl_assert(buflen == res) + + return self._backend._ffi.buffer(buf)[:] + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.X962 + or format is serialization.PublicFormat.CompressedPoint + or format is serialization.PublicFormat.UncompressedPoint + ): + if encoding is not serialization.Encoding.X962 or format not in ( + serialization.PublicFormat.CompressedPoint, + serialization.PublicFormat.UncompressedPoint, + ): + raise ValueError( + "X962 encoding must be used with CompressedPoint or " + "UncompressedPoint format" + ) + + return self._encode_point(format) + else: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify( + self, + signature: bytes, + data: bytes, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + ) -> None: + _check_signature_algorithm(signature_algorithm) + data, _ = _calculate_digest_and_algorithm( + data, + signature_algorithm.algorithm, + ) + _ecdsa_sig_verify(self._backend, self, signature, data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed25519.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed25519.py new file mode 100644 index 0000000000000000000000000000000000000000..6f393e5b6aa917ad0b5b81c57056a48a30a4d33e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed25519.py @@ -0,0 +1,155 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import exceptions +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + _ED25519_KEY_SIZE, + _ED25519_SIG_SIZE, + Ed25519PrivateKey, + Ed25519PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _Ed25519PublicKey(Ed25519PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] + + def verify(self, signature: bytes, data: bytes) -> None: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +class _Ed25519PrivateKey(Ed25519PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> Ed25519PublicKey: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed25519_load_public_bytes(public_bytes) + + def sign(self, data: bytes) -> bytes: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PrivateFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed448.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed448.py new file mode 100644 index 0000000000000000000000000000000000000000..0d27ea638ad67be07aa575a567286cefebc41b3d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/ed448.py @@ -0,0 +1,156 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import exceptions +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + +_ED448_KEY_SIZE = 57 +_ED448_SIG_SIZE = 114 + + +class _Ed448PublicKey(Ed448PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] + + def verify(self, signature: bytes, data: bytes) -> None: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +class _Ed448PrivateKey(Ed448PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> Ed448PublicKey: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed448_load_public_bytes(public_bytes) + + def sign(self, data: bytes) -> bytes: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PrivateFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hashes.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hashes.py new file mode 100644 index 0000000000000000000000000000000000000000..52d4646a7ab0b00c797544df5662fb903d6c542f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hashes.py @@ -0,0 +1,86 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import hashes + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _HashContext(hashes.HashContext): + def __init__( + self, backend: "Backend", algorithm: hashes.HashAlgorithm, ctx=None + ) -> None: + self._algorithm = algorithm + + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.EVP_MD_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_MD_CTX_free + ) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = self._backend._lib.EVP_DigestInit_ex( + ctx, evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + def copy(self) -> "_HashContext": + copied_ctx = self._backend._lib.EVP_MD_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + if isinstance(self.algorithm, hashes.ExtendableOutputFunction): + # extendable output functions use a different finalize + return self._finalize_xof() + else: + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert( + outlen[0] == self.algorithm.digest_size + ) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def _finalize_xof(self) -> bytes: + buf = self._backend._ffi.new( + "unsigned char[]", self.algorithm.digest_size + ) + res = self._backend._lib.EVP_DigestFinalXOF( + self._ctx, buf, self.algorithm.digest_size + ) + self._backend.openssl_assert(res != 0) + return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hmac.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hmac.py new file mode 100644 index 0000000000000000000000000000000000000000..ba3dfb53f8b3b2e89fe36f9918cef64872246ce9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/hmac.py @@ -0,0 +1,84 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time, hashes + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _HMACContext(hashes.HashContext): + def __init__( + self, + backend: "Backend", + key: bytes, + algorithm: hashes.HashAlgorithm, + ctx=None, + ): + self._algorithm = algorithm + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.HMAC_CTX_free) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + key_ptr = self._backend._ffi.from_buffer(key) + res = self._backend._lib.HMAC_Init_ex( + ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + self._key = key + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + def copy(self) -> "_HMACContext": + copied_ctx = self._backend._lib.HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.HMAC_CTX_free + ) + res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HMACContext( + self._backend, self._key, self.algorithm, ctx=copied_ctx + ) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data)) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, signature: bytes) -> None: + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/poly1305.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/poly1305.py new file mode 100644 index 0000000000000000000000000000000000000000..d0d44f6fd96e5030c5831349fcc4177dd798efae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/poly1305.py @@ -0,0 +1,67 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import constant_time + +_POLY1305_TAG_SIZE = 16 +_POLY1305_KEY_SIZE = 32 + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _Poly1305Context: + def __init__(self, backend: "Backend", key: bytes) -> None: + self._backend = backend + + key_ptr = self._backend._ffi.from_buffer(key) + # This function copies the key into OpenSSL-owned memory so we don't + # need to retain it ourselves + evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key( + self._backend._lib.NID_poly1305, + self._backend._ffi.NULL, + key_ptr, + len(key), + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + self._evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + self._ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + self._ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestSignUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE) + outlen = self._backend._ffi.new("size_t *", _POLY1305_TAG_SIZE) + res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, tag: bytes) -> None: + mac = self.finalize() + if not constant_time.bytes_eq(mac, tag): + raise InvalidSignature("Value did not match computed tag.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/rsa.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/rsa.py new file mode 100644 index 0000000000000000000000000000000000000000..c960105e718eb4f9df61d4d771733668ad1713cc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/rsa.py @@ -0,0 +1,588 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import threading +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, + OAEP, + PSS, + AsymmetricPadding, + PKCS1v15, + _Auto, + _DigestLength, + _MaxLength, + calculate_max_pss_salt_length, +) +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKey, + RSAPrivateNumbers, + RSAPublicKey, + RSAPublicNumbers, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _get_rsa_pss_salt_length( + backend: "Backend", + pss: PSS, + key: typing.Union[RSAPrivateKey, RSAPublicKey], + hash_algorithm: hashes.HashAlgorithm, +) -> int: + salt = pss._salt_length + + if isinstance(salt, _MaxLength): + return calculate_max_pss_salt_length(key, hash_algorithm) + elif isinstance(salt, _DigestLength): + return hash_algorithm.digest_size + elif isinstance(salt, _Auto): + if isinstance(key, RSAPrivateKey): + raise ValueError( + "PSS salt length can only be set to AUTO when verifying" + ) + return backend._lib.RSA_PSS_SALTLEN_AUTO + else: + return salt + + +def _enc_dec_rsa( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + data: bytes, + padding: AsymmetricPadding, +) -> bytes: + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Padding must be an instance of AsymmetricPadding.") + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, OAEP): + padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING + + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + if not backend.rsa_padding_supported(padding): + raise UnsupportedAlgorithm( + "This combination of padding and hash algorithm is not " + "supported by this backend.", + _Reasons.UNSUPPORTED_PADDING, + ) + + else: + raise UnsupportedAlgorithm( + f"{padding.name} is not supported by this backend.", + _Reasons.UNSUPPORTED_PADDING, + ) + + return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) + + +def _enc_dec_rsa_pkey_ctx( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + data: bytes, + padding_enum: int, + padding: AsymmetricPadding, +) -> bytes: + init: typing.Callable[[typing.Any], int] + crypt: typing.Callable[[typing.Any, typing.Any, int, bytes, int], int] + if isinstance(key, _RSAPublicKey): + init = backend._lib.EVP_PKEY_encrypt_init + crypt = backend._lib.EVP_PKEY_encrypt + else: + init = backend._lib.EVP_PKEY_decrypt_init + crypt = backend._lib.EVP_PKEY_decrypt + + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(buf_size > 0) + if isinstance(padding, OAEP): + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm) + res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md) + backend.openssl_assert(res > 0) + + if ( + isinstance(padding, OAEP) + and padding._label is not None + and len(padding._label) > 0 + ): + # set0_rsa_oaep_label takes ownership of the char * so we need to + # copy it into some new memory + labelptr = backend._lib.OPENSSL_malloc(len(padding._label)) + backend.openssl_assert(labelptr != backend._ffi.NULL) + backend._ffi.memmove(labelptr, padding._label, len(padding._label)) + res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label( + pkey_ctx, labelptr, len(padding._label) + ) + backend.openssl_assert(res == 1) + + outlen = backend._ffi.new("size_t *", buf_size) + buf = backend._ffi.new("unsigned char[]", buf_size) + # Everything from this line onwards is written with the goal of being as + # constant-time as is practical given the constraints of Python and our + # API. See Bleichenbacher's '98 attack on RSA, and its many many variants. + # As such, you should not attempt to change this (particularly to "clean it + # up") without understanding why it was written this way (see + # Chesterton's Fence), and without measuring to verify you have not + # introduced observable time differences. + res = crypt(pkey_ctx, buf, outlen, data, len(data)) + resbuf = backend._ffi.buffer(buf)[: outlen[0]] + backend._lib.ERR_clear_error() + if res <= 0: + raise ValueError("Encryption/decryption failed.") + return resbuf + + +def _rsa_sig_determine_padding( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], +) -> int: + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Expected provider of AsymmetricPadding.") + + pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(pkey_size > 0) + + if isinstance(padding, PKCS1v15): + # Hash algorithm is ignored for PKCS1v15-padding, may be None. + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, PSS): + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + # PSS padding requires a hash algorithm + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + # Size of key in bytes - 2 is the maximum + # PSS signature length (salt length is checked later) + if pkey_size - algorithm.digest_size - 2 < 0: + raise ValueError( + "Digest too large for key size. Use a larger " + "key or different digest." + ) + + padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING + else: + raise UnsupportedAlgorithm( + f"{padding.name} is not supported by this backend.", + _Reasons.UNSUPPORTED_PADDING, + ) + + return padding_enum + + +# Hash algorithm can be absent (None) to initialize the context without setting +# any message digest algorithm. This is currently only valid for the PKCS1v15 +# padding type, where it means that the signature data is encoded/decoded +# as provided, without being wrapped in a DigestInfo structure. +def _rsa_sig_setup( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + key: typing.Union["_RSAPublicKey", "_RSAPrivateKey"], + init_func: typing.Callable[[typing.Any], int], +): + padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init_func(pkey_ctx) + if res != 1: + errors = backend._consume_errors() + raise ValueError("Unable to sign/verify with this key", errors) + + if algorithm is not None: + evp_md = backend._evp_md_non_null_from_algorithm(algorithm) + res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md) + if res <= 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported by this backend for RSA signing.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + if res <= 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported for the RSA signature operation.".format( + padding.name + ), + _Reasons.UNSUPPORTED_PADDING, + ) + if isinstance(padding, PSS): + assert isinstance(algorithm, hashes.HashAlgorithm) + res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, + _get_rsa_pss_salt_length(backend, padding, key, algorithm), + ) + backend.openssl_assert(res > 0) + + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + + return pkey_ctx + + +def _rsa_sig_sign( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: hashes.HashAlgorithm, + private_key: "_RSAPrivateKey", + data: bytes, +) -> bytes: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + private_key, + backend._lib.EVP_PKEY_sign_init, + ) + buflen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_sign( + pkey_ctx, backend._ffi.NULL, buflen, data, len(data) + ) + backend.openssl_assert(res == 1) + buf = backend._ffi.new("unsigned char[]", buflen[0]) + res = backend._lib.EVP_PKEY_sign(pkey_ctx, buf, buflen, data, len(data)) + if res != 1: + errors = backend._consume_errors() + raise ValueError( + "Digest or salt length too long for key size. Use a larger key " + "or shorter salt length if you are specifying a PSS salt", + errors, + ) + + return backend._ffi.buffer(buf)[:] + + +def _rsa_sig_verify( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: hashes.HashAlgorithm, + public_key: "_RSAPublicKey", + signature: bytes, + data: bytes, +) -> None: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + public_key, + backend._lib.EVP_PKEY_verify_init, + ) + res = backend._lib.EVP_PKEY_verify( + pkey_ctx, signature, len(signature), data, len(data) + ) + # The previous call can return negative numbers in the event of an + # error. This is not a signature failure but we need to fail if it + # occurs. + backend.openssl_assert(res >= 0) + if res == 0: + backend._consume_errors() + raise InvalidSignature + + +def _rsa_sig_recover( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + public_key: "_RSAPublicKey", + signature: bytes, +) -> bytes: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + public_key, + backend._lib.EVP_PKEY_verify_recover_init, + ) + + # Attempt to keep the rest of the code in this function as constant/time + # as possible. See the comment in _enc_dec_rsa_pkey_ctx. Note that the + # buflen parameter is used even though its value may be undefined in the + # error case. Due to the tolerant nature of Python slicing this does not + # trigger any exceptions. + maxlen = backend._lib.EVP_PKEY_size(public_key._evp_pkey) + backend.openssl_assert(maxlen > 0) + buf = backend._ffi.new("unsigned char[]", maxlen) + buflen = backend._ffi.new("size_t *", maxlen) + res = backend._lib.EVP_PKEY_verify_recover( + pkey_ctx, buf, buflen, signature, len(signature) + ) + resbuf = backend._ffi.buffer(buf)[: buflen[0]] + backend._lib.ERR_clear_error() + # Assume that all parameter errors are handled during the setup phase and + # any error here is due to invalid signature. + if res != 1: + raise InvalidSignature + return resbuf + + +class _RSAPrivateKey(RSAPrivateKey): + _evp_pkey: object + _rsa_cdata: object + _key_size: int + + def __init__( + self, + backend: "Backend", + rsa_cdata, + evp_pkey, + *, + unsafe_skip_rsa_key_validation: bool, + ): + res: int + # RSA_check_key is slower in OpenSSL 3.0.0 due to improved + # primality checking. In normal use this is unlikely to be a problem + # since users don't load new keys constantly, but for TESTING we've + # added an init arg that allows skipping the checks. You should not + # use this in production code unless you understand the consequences. + if not unsafe_skip_rsa_key_validation: + res = backend._lib.RSA_check_key(rsa_cdata) + if res != 1: + errors = backend._consume_errors() + raise ValueError("Invalid private key", errors) + # 2 is prime and passes an RSA key check, so we also check + # if p and q are odd just to be safe. + p = backend._ffi.new("BIGNUM **") + q = backend._ffi.new("BIGNUM **") + backend._lib.RSA_get0_factors(rsa_cdata, p, q) + backend.openssl_assert(p[0] != backend._ffi.NULL) + backend.openssl_assert(q[0] != backend._ffi.NULL) + p_odd = backend._lib.BN_is_odd(p[0]) + q_odd = backend._lib.BN_is_odd(q[0]) + if p_odd != 1 or q_odd != 1: + errors = backend._consume_errors() + raise ValueError("Invalid private key", errors) + + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + # Used for lazy blinding + self._blinded = False + self._blinding_lock = threading.Lock() + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + def _enable_blinding(self) -> None: + # If you call blind on an already blinded RSA key OpenSSL will turn + # it off and back on, which is a performance hit we want to avoid. + if not self._blinded: + with self._blinding_lock: + self._non_threadsafe_enable_blinding() + + def _non_threadsafe_enable_blinding(self) -> None: + # This is only a separate function to allow for testing to cover both + # branches. It should never be invoked except through _enable_blinding. + # Check if it's not True again in case another thread raced past the + # first non-locked check. + if not self._blinded: + res = self._backend._lib.RSA_blinding_on( + self._rsa_cdata, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + self._blinded = True + + @property + def key_size(self) -> int: + return self._key_size + + def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: + self._enable_blinding() + key_size_bytes = (self.key_size + 7) // 8 + if key_size_bytes != len(ciphertext): + raise ValueError("Ciphertext length must be equal to key size.") + + return _enc_dec_rsa(self._backend, self, ciphertext, padding) + + def public_key(self) -> RSAPublicKey: + ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) + evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx) + return _RSAPublicKey(self._backend, ctx, evp_pkey) + + def private_numbers(self) -> RSAPrivateNumbers: + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + d = self._backend._ffi.new("BIGNUM **") + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + dmp1 = self._backend._ffi.new("BIGNUM **") + dmq1 = self._backend._ffi.new("BIGNUM **") + iqmp = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(d[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_crt_params( + self._rsa_cdata, dmp1, dmq1, iqmp + ) + self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL) + return RSAPrivateNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + d=self._backend._bn_to_int(d[0]), + dmp1=self._backend._bn_to_int(dmp1[0]), + dmq1=self._backend._bn_to_int(dmq1[0]), + iqmp=self._backend._bn_to_int(iqmp[0]), + public_numbers=RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ), + ) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._rsa_cdata, + ) + + def sign( + self, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + self._enable_blinding() + data, algorithm = _calculate_digest_and_algorithm(data, algorithm) + return _rsa_sig_sign(self._backend, padding, algorithm, self, data) + + +class _RSAPublicKey(RSAPublicKey): + _evp_pkey: object + _rsa_cdata: object + _key_size: int + + def __init__(self, backend: "Backend", rsa_cdata, evp_pkey): + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: + return _enc_dec_rsa(self._backend, self, plaintext, padding) + + def public_numbers(self) -> RSAPublicNumbers: + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, e, self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + return RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, self._rsa_cdata + ) + + def verify( + self, + signature: bytes, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + data, algorithm = _calculate_digest_and_algorithm(data, algorithm) + _rsa_sig_verify( + self._backend, padding, algorithm, self, signature, data + ) + + def recover_data_from_signature( + self, + signature: bytes, + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> bytes: + if isinstance(algorithm, asym_utils.Prehashed): + raise TypeError( + "Prehashed is only supported in the sign and verify methods. " + "It cannot be used with recover_data_from_signature." + ) + return _rsa_sig_recover( + self._backend, padding, algorithm, self, signature + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..64b4a8334b51c663970377aefaf121f60df67c5a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/utils.py @@ -0,0 +1,61 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.utils import Prehashed + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _evp_pkey_derive(backend: "Backend", evp_pkey, peer_public_key) -> bytes: + ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL) + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) + res = backend._lib.EVP_PKEY_derive_init(ctx) + backend.openssl_assert(res == 1) + + if backend._lib.Cryptography_HAS_EVP_PKEY_SET_PEER_EX: + res = backend._lib.EVP_PKEY_derive_set_peer_ex( + ctx, peer_public_key._evp_pkey, 0 + ) + else: + res = backend._lib.EVP_PKEY_derive_set_peer( + ctx, peer_public_key._evp_pkey + ) + backend.openssl_assert(res == 1) + + keylen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen) + backend.openssl_assert(res == 1) + backend.openssl_assert(keylen[0] > 0) + buf = backend._ffi.new("unsigned char[]", keylen[0]) + res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + if res != 1: + errors = backend._consume_errors() + raise ValueError("Error computing shared key.", errors) + + return backend._ffi.buffer(buf, keylen[0])[:] + + +def _calculate_digest_and_algorithm( + data: bytes, + algorithm: typing.Union[Prehashed, hashes.HashAlgorithm], +) -> typing.Tuple[bytes, hashes.HashAlgorithm]: + if not isinstance(algorithm, Prehashed): + hash_ctx = hashes.Hash(algorithm) + hash_ctx.update(data) + data = hash_ctx.finalize() + else: + algorithm = algorithm._algorithm + + if len(data) != algorithm.digest_size: + raise ValueError( + "The provided data must be the same length as the hash " + "algorithm's digest size." + ) + + return (data, algorithm) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/x448.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/x448.py new file mode 100644 index 0000000000000000000000000000000000000000..d738188c71f71a3dabea54cb5f7093d588024964 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/backends/openssl/x448.py @@ -0,0 +1,117 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PrivateKey, + X448PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + +_X448_KEY_SIZE = 56 + + +class _X448PublicKey(X448PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] + + +class _X448PrivateKey(X448PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> X448PublicKey: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.x448_load_public_bytes(public_bytes) + + def exchange(self, peer_public_key: X448PublicKey) -> bytes: + if not isinstance(peer_public_key, X448PublicKey): + raise TypeError("peer_public_key must be X448PublicKey.") + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PrivateFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b509336233c2fafe4185a49da5909c8bbb38dfd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__init__.py @@ -0,0 +1,3 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0017d4720b92d9937553aac27e746350744fe18 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd new file mode 100644 index 0000000000000000000000000000000000000000..f5c57163822a867f44756c73040ed9a527583a87 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi new file mode 100644 index 0000000000000000000000000000000000000000..94a37a20aa962dccf5d403dcad17c69ffd57c455 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi @@ -0,0 +1,34 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import types +import typing + +def check_pkcs7_padding(data: bytes) -> bool: ... +def check_ansix923_padding(data: bytes) -> bool: ... + +class ObjectIdentifier: + def __init__(self, val: str) -> None: ... + @property + def dotted_string(self) -> str: ... + @property + def _name(self) -> str: ... + +T = typing.TypeVar("T") + +class FixedPool(typing.Generic[T]): + def __init__( + self, + create: typing.Callable[[], T], + ) -> None: ... + def acquire(self) -> PoolAcquisition[T]: ... + +class PoolAcquisition(typing.Generic[T]): + def __enter__(self) -> T: ... + def __exit__( + self, + exc_type: typing.Optional[typing.Type[BaseException]], + exc_value: typing.Optional[BaseException], + exc_tb: typing.Optional[types.TracebackType], + ) -> None: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi new file mode 100644 index 0000000000000000000000000000000000000000..80100082acd30b6bc69e5b8ab0972d77a33dc11a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi @@ -0,0 +1,8 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +lib = typing.Any +ffi = typing.Any diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi new file mode 100644 index 0000000000000000000000000000000000000000..a8369ba8383e639c2b1173008051ecc72450bf8a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +class TestCertificate: + not_after_tag: int + not_before_tag: int + issuer_value_tags: typing.List[int] + subject_value_tags: typing.List[int] + +def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: ... +def encode_dss_signature(r: int, s: int) -> bytes: ... +def parse_spki_for_data(data: bytes) -> bytes: ... +def test_parse_certificate(data: bytes) -> TestCertificate: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi new file mode 100644 index 0000000000000000000000000000000000000000..4671eb9ba34df990a5e95c2aad354f67b500ba0c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -0,0 +1,25 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes +from cryptography.x509.ocsp import ( + OCSPRequest, + OCSPRequestBuilder, + OCSPResponse, + OCSPResponseBuilder, + OCSPResponseStatus, +) + +def load_der_ocsp_request(data: bytes) -> OCSPRequest: ... +def load_der_ocsp_response(data: bytes) -> OCSPResponse: ... +def create_ocsp_request(builder: OCSPRequestBuilder) -> OCSPRequest: ... +def create_ocsp_response( + status: OCSPResponseStatus, + builder: typing.Optional[OCSPResponseBuilder], + private_key: typing.Optional[PrivateKeyTypes], + hash_algorithm: typing.Optional[hashes.HashAlgorithm], +) -> OCSPResponse: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi new file mode 100644 index 0000000000000000000000000000000000000000..c19b6a9bcbebb68e2dec2994eee5bb42e9e87698 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -0,0 +1,22 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.bindings._rust.openssl import x25519 + +__all__ = ["openssl_version", "raise_openssl_error", "x25519"] + +def openssl_version() -> int: ... +def raise_openssl_error() -> typing.NoReturn: ... +def capture_error_stack() -> typing.List[OpenSSLError]: ... + +class OpenSSLError: + @property + def lib(self) -> int: ... + @property + def reason(self) -> int: ... + @property + def reason_text(self) -> bytes: ... + def _lib_reason_match(self, lib: int, reason: int) -> bool: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi new file mode 100644 index 0000000000000000000000000000000000000000..90f7cbdda950b10e2fc160353e15fdb30f7250cf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import x25519 + +class X25519PrivateKey: ... +class X25519PublicKey: ... + +def generate_key() -> x25519.X25519PrivateKey: ... +def private_key_from_ptr(ptr: int) -> x25519.X25519PrivateKey: ... +def public_key_from_ptr(ptr: int) -> x25519.X25519PublicKey: ... +def from_private_bytes(data: bytes) -> x25519.X25519PrivateKey: ... +def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi new file mode 100644 index 0000000000000000000000000000000000000000..66bd850981a6fa06eb7c7ecdec0e443c22b82c08 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi @@ -0,0 +1,15 @@ +import typing + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.serialization import pkcs7 + +def serialize_certificates( + certs: typing.List[x509.Certificate], + encoding: serialization.Encoding, +) -> bytes: ... +def sign_and_serialize( + builder: pkcs7.PKCS7SignatureBuilder, + encoding: serialization.Encoding, + options: typing.Iterable[pkcs7.PKCS7Options], +) -> bytes: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi new file mode 100644 index 0000000000000000000000000000000000000000..71c8d5c22c3ec9965ea740dbf67abf16c6f3942c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi @@ -0,0 +1,42 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes + +def load_pem_x509_certificate(data: bytes) -> x509.Certificate: ... +def load_pem_x509_certificates( + data: bytes, +) -> typing.List[x509.Certificate]: ... +def load_der_x509_certificate(data: bytes) -> x509.Certificate: ... +def load_pem_x509_crl(data: bytes) -> x509.CertificateRevocationList: ... +def load_der_x509_crl(data: bytes) -> x509.CertificateRevocationList: ... +def load_pem_x509_csr(data: bytes) -> x509.CertificateSigningRequest: ... +def load_der_x509_csr(data: bytes) -> x509.CertificateSigningRequest: ... +def encode_name_bytes(name: x509.Name) -> bytes: ... +def encode_extension_value(extension: x509.ExtensionType) -> bytes: ... +def create_x509_certificate( + builder: x509.CertificateBuilder, + private_key: PrivateKeyTypes, + hash_algorithm: typing.Optional[hashes.HashAlgorithm], +) -> x509.Certificate: ... +def create_x509_csr( + builder: x509.CertificateSigningRequestBuilder, + private_key: PrivateKeyTypes, + hash_algorithm: typing.Optional[hashes.HashAlgorithm], +) -> x509.CertificateSigningRequest: ... +def create_x509_crl( + builder: x509.CertificateRevocationListBuilder, + private_key: PrivateKeyTypes, + hash_algorithm: typing.Optional[hashes.HashAlgorithm], +) -> x509.CertificateRevocationList: ... + +class Sct: ... +class Certificate: ... +class RevokedCertificate: ... +class CertificateRevocationList: ... +class CertificateSigningRequest: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b509336233c2fafe4185a49da5909c8bbb38dfd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__init__.py @@ -0,0 +1,3 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c12c301aa782c6c647843470631a7a63e2da602 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e358660e1c6141bc53e6805f5a650abe57fcc13 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..446412f2221c6f2bd99b241600f35275cc22027e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py new file mode 100644 index 0000000000000000000000000000000000000000..c34fc3ae69603a29e20fd0c09690deb630b50758 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py @@ -0,0 +1,332 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + + +def cryptography_has_set_cert_cb() -> typing.List[str]: + return [ + "SSL_CTX_set_cert_cb", + "SSL_set_cert_cb", + ] + + +def cryptography_has_ssl_st() -> typing.List[str]: + return [ + "SSL_ST_BEFORE", + "SSL_ST_OK", + "SSL_ST_INIT", + "SSL_ST_RENEGOTIATE", + ] + + +def cryptography_has_tls_st() -> typing.List[str]: + return [ + "TLS_ST_BEFORE", + "TLS_ST_OK", + ] + + +def cryptography_has_scrypt() -> typing.List[str]: + return [ + "EVP_PBE_scrypt", + ] + + +def cryptography_has_evp_pkey_dhx() -> typing.List[str]: + return [ + "EVP_PKEY_DHX", + "d2i_DHxparams_bio", + "i2d_DHxparams_bio", + ] + + +def cryptography_has_mem_functions() -> typing.List[str]: + return [ + "Cryptography_CRYPTO_set_mem_functions", + ] + + +def cryptography_has_x509_store_ctx_get_issuer() -> typing.List[str]: + return [ + "X509_STORE_set_get_issuer", + ] + + +def cryptography_has_ed448() -> typing.List[str]: + return [ + "EVP_PKEY_ED448", + "NID_ED448", + ] + + +def cryptography_has_ed25519() -> typing.List[str]: + return [ + "NID_ED25519", + "EVP_PKEY_ED25519", + ] + + +def cryptography_has_poly1305() -> typing.List[str]: + return [ + "NID_poly1305", + "EVP_PKEY_POLY1305", + ] + + +def cryptography_has_evp_digestfinal_xof() -> typing.List[str]: + return [ + "EVP_DigestFinalXOF", + ] + + +def cryptography_has_fips() -> typing.List[str]: + return [ + "FIPS_mode_set", + "FIPS_mode", + ] + + +def cryptography_has_ssl_sigalgs() -> typing.List[str]: + return [ + "SSL_CTX_set1_sigalgs_list", + ] + + +def cryptography_has_psk() -> typing.List[str]: + return [ + "SSL_CTX_use_psk_identity_hint", + "SSL_CTX_set_psk_server_callback", + "SSL_CTX_set_psk_client_callback", + ] + + +def cryptography_has_psk_tlsv13() -> typing.List[str]: + return [ + "SSL_CTX_set_psk_find_session_callback", + "SSL_CTX_set_psk_use_session_callback", + "Cryptography_SSL_SESSION_new", + "SSL_CIPHER_find", + "SSL_SESSION_set1_master_key", + "SSL_SESSION_set_cipher", + "SSL_SESSION_set_protocol_version", + ] + + +def cryptography_has_custom_ext() -> typing.List[str]: + return [ + "SSL_CTX_add_client_custom_ext", + "SSL_CTX_add_server_custom_ext", + "SSL_extension_supported", + ] + + +def cryptography_has_openssl_cleanup() -> typing.List[str]: + return [ + "OPENSSL_cleanup", + ] + + +def cryptography_has_tlsv13_functions() -> typing.List[str]: + return [ + "SSL_VERIFY_POST_HANDSHAKE", + "SSL_CTX_set_ciphersuites", + "SSL_verify_client_post_handshake", + "SSL_CTX_set_post_handshake_auth", + "SSL_set_post_handshake_auth", + "SSL_SESSION_get_max_early_data", + "SSL_write_early_data", + "SSL_read_early_data", + "SSL_CTX_set_max_early_data", + ] + + +def cryptography_has_raw_key() -> typing.List[str]: + return [ + "EVP_PKEY_new_raw_private_key", + "EVP_PKEY_new_raw_public_key", + "EVP_PKEY_get_raw_private_key", + "EVP_PKEY_get_raw_public_key", + ] + + +def cryptography_has_engine() -> typing.List[str]: + return [ + "ENGINE_by_id", + "ENGINE_init", + "ENGINE_finish", + "ENGINE_get_default_RAND", + "ENGINE_set_default_RAND", + "ENGINE_unregister_RAND", + "ENGINE_ctrl_cmd", + "ENGINE_free", + "ENGINE_get_name", + "Cryptography_add_osrandom_engine", + "ENGINE_ctrl_cmd_string", + "ENGINE_load_builtin_engines", + "ENGINE_load_private_key", + "ENGINE_load_public_key", + "SSL_CTX_set_client_cert_engine", + ] + + +def cryptography_has_verified_chain() -> typing.List[str]: + return [ + "SSL_get0_verified_chain", + ] + + +def cryptography_has_srtp() -> typing.List[str]: + return [ + "SSL_CTX_set_tlsext_use_srtp", + "SSL_set_tlsext_use_srtp", + "SSL_get_selected_srtp_profile", + ] + + +def cryptography_has_providers() -> typing.List[str]: + return [ + "OSSL_PROVIDER_load", + "OSSL_PROVIDER_unload", + "ERR_LIB_PROV", + "PROV_R_WRONG_FINAL_BLOCK_LENGTH", + "PROV_R_BAD_DECRYPT", + ] + + +def cryptography_has_op_no_renegotiation() -> typing.List[str]: + return [ + "SSL_OP_NO_RENEGOTIATION", + ] + + +def cryptography_has_dtls_get_data_mtu() -> typing.List[str]: + return [ + "DTLS_get_data_mtu", + ] + + +def cryptography_has_300_fips() -> typing.List[str]: + return [ + "EVP_default_properties_is_fips_enabled", + "EVP_default_properties_enable_fips", + ] + + +def cryptography_has_ssl_cookie() -> typing.List[str]: + return [ + "SSL_OP_COOKIE_EXCHANGE", + "DTLSv1_listen", + "SSL_CTX_set_cookie_generate_cb", + "SSL_CTX_set_cookie_verify_cb", + ] + + +def cryptography_has_pkcs7_funcs() -> typing.List[str]: + return [ + "SMIME_write_PKCS7", + "PEM_write_bio_PKCS7_stream", + "PKCS7_sign_add_signer", + "PKCS7_final", + "PKCS7_verify", + "SMIME_read_PKCS7", + "PKCS7_get0_signers", + ] + + +def cryptography_has_bn_flags() -> typing.List[str]: + return [ + "BN_FLG_CONSTTIME", + "BN_set_flags", + "BN_prime_checks_for_size", + ] + + +def cryptography_has_evp_pkey_dh() -> typing.List[str]: + return [ + "EVP_PKEY_set1_DH", + ] + + +def cryptography_has_300_evp_cipher() -> typing.List[str]: + return ["EVP_CIPHER_fetch", "EVP_CIPHER_free"] + + +def cryptography_has_unexpected_eof_while_reading() -> typing.List[str]: + return ["SSL_R_UNEXPECTED_EOF_WHILE_READING"] + + +def cryptography_has_pkcs12_set_mac() -> typing.List[str]: + return ["PKCS12_set_mac"] + + +def cryptography_has_ssl_op_ignore_unexpected_eof() -> typing.List[str]: + return [ + "SSL_OP_IGNORE_UNEXPECTED_EOF", + ] + + +def cryptography_has_get_extms_support() -> typing.List[str]: + return ["SSL_get_extms_support"] + + +def cryptography_has_evp_pkey_set_peer_ex() -> typing.List[str]: + return ["EVP_PKEY_derive_set_peer_ex"] + + +# This is a mapping of +# {condition: function-returning-names-dependent-on-that-condition} so we can +# loop over them and delete unsupported names at runtime. It will be removed +# when cffi supports #if in cdef. We use functions instead of just a dict of +# lists so we can use coverage to measure which are used. +CONDITIONAL_NAMES = { + "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, + "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, + "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, + "Cryptography_HAS_SCRYPT": cryptography_has_scrypt, + "Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx, + "Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions, + "Cryptography_HAS_X509_STORE_CTX_GET_ISSUER": ( + cryptography_has_x509_store_ctx_get_issuer + ), + "Cryptography_HAS_ED448": cryptography_has_ed448, + "Cryptography_HAS_ED25519": cryptography_has_ed25519, + "Cryptography_HAS_POLY1305": cryptography_has_poly1305, + "Cryptography_HAS_FIPS": cryptography_has_fips, + "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, + "Cryptography_HAS_PSK": cryptography_has_psk, + "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, + "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, + "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup, + "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, + "Cryptography_HAS_RAW_KEY": cryptography_has_raw_key, + "Cryptography_HAS_EVP_DIGESTFINAL_XOF": ( + cryptography_has_evp_digestfinal_xof + ), + "Cryptography_HAS_ENGINE": cryptography_has_engine, + "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, + "Cryptography_HAS_SRTP": cryptography_has_srtp, + "Cryptography_HAS_PROVIDERS": cryptography_has_providers, + "Cryptography_HAS_OP_NO_RENEGOTIATION": ( + cryptography_has_op_no_renegotiation + ), + "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, + "Cryptography_HAS_300_FIPS": cryptography_has_300_fips, + "Cryptography_HAS_SSL_COOKIE": cryptography_has_ssl_cookie, + "Cryptography_HAS_PKCS7_FUNCS": cryptography_has_pkcs7_funcs, + "Cryptography_HAS_BN_FLAGS": cryptography_has_bn_flags, + "Cryptography_HAS_EVP_PKEY_DH": cryptography_has_evp_pkey_dh, + "Cryptography_HAS_300_EVP_CIPHER": cryptography_has_300_evp_cipher, + "Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING": ( + cryptography_has_unexpected_eof_while_reading + ), + "Cryptography_HAS_PKCS12_SET_MAC": cryptography_has_pkcs12_set_mac, + "Cryptography_HAS_SSL_OP_IGNORE_UNEXPECTED_EOF": ( + cryptography_has_ssl_op_ignore_unexpected_eof + ), + "Cryptography_HAS_GET_EXTMS_SUPPORT": cryptography_has_get_extms_support, + "Cryptography_HAS_EVP_PKEY_SET_PEER_EX": ( + cryptography_has_evp_pkey_set_peer_ex + ), +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py new file mode 100644 index 0000000000000000000000000000000000000000..7327157fd8d5923dc49bf2236acefb844846f872 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py @@ -0,0 +1,208 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import os +import sys +import threading +import types +import typing +import warnings + +import cryptography +from cryptography import utils +from cryptography.exceptions import InternalError +from cryptography.hazmat.bindings._rust import _openssl, openssl +from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES + + +def _openssl_assert( + lib, + ok: bool, + errors: typing.Optional[typing.List[openssl.OpenSSLError]] = None, +) -> None: + if not ok: + if errors is None: + errors = openssl.capture_error_stack() + + raise InternalError( + "Unknown OpenSSL error. This error is commonly encountered when " + "another library is not cleaning up the OpenSSL error stack. If " + "you are using cryptography with another library that uses " + "OpenSSL try disabling it before reporting a bug. Otherwise " + "please file an issue at https://github.com/pyca/cryptography/" + "issues with information on how to reproduce " + "this. ({!r})".format(errors), + errors, + ) + + +def _legacy_provider_error(loaded: bool) -> None: + if not loaded: + raise RuntimeError( + "OpenSSL 3.0's legacy provider failed to load. This is a fatal " + "error by default, but cryptography supports running without " + "legacy algorithms by setting the environment variable " + "CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error," + " you have likely made a mistake with your OpenSSL configuration." + ) + + +def build_conditional_library( + lib: typing.Any, + conditional_names: typing.Dict[str, typing.Callable[[], typing.List[str]]], +) -> typing.Any: + conditional_lib = types.ModuleType("lib") + conditional_lib._original_lib = lib # type: ignore[attr-defined] + excluded_names = set() + for condition, names_cb in conditional_names.items(): + if not getattr(lib, condition): + excluded_names.update(names_cb()) + + for attr in dir(lib): + if attr not in excluded_names: + setattr(conditional_lib, attr, getattr(lib, attr)) + + return conditional_lib + + +class Binding: + """ + OpenSSL API wrapper. + """ + + lib: typing.ClassVar = None + ffi = _openssl.ffi + _lib_loaded = False + _init_lock = threading.Lock() + _legacy_provider: typing.Any = ffi.NULL + _legacy_provider_loaded = False + _default_provider: typing.Any = ffi.NULL + + def __init__(self) -> None: + self._ensure_ffi_initialized() + + def _enable_fips(self) -> None: + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + _openssl_assert(self.lib, self.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER) + self._base_provider = self.lib.OSSL_PROVIDER_load( + self.ffi.NULL, b"base" + ) + _openssl_assert(self.lib, self._base_provider != self.ffi.NULL) + self.lib._fips_provider = self.lib.OSSL_PROVIDER_load( + self.ffi.NULL, b"fips" + ) + _openssl_assert(self.lib, self.lib._fips_provider != self.ffi.NULL) + + res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1) + _openssl_assert(self.lib, res == 1) + + @classmethod + def _register_osrandom_engine(cls) -> None: + # Clear any errors extant in the queue before we start. In many + # scenarios other things may be interacting with OpenSSL in the same + # process space and it has proven untenable to assume that they will + # reliably clear the error queue. Once we clear it here we will + # error on any subsequent unexpected item in the stack. + cls.lib.ERR_clear_error() + if cls.lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + result = cls.lib.Cryptography_add_osrandom_engine() + _openssl_assert(cls.lib, result in (1, 2)) + + @classmethod + def _ensure_ffi_initialized(cls) -> None: + with cls._init_lock: + if not cls._lib_loaded: + cls.lib = build_conditional_library( + _openssl.lib, CONDITIONAL_NAMES + ) + cls._lib_loaded = True + cls._register_osrandom_engine() + # As of OpenSSL 3.0.0 we must register a legacy cipher provider + # to get RC2 (needed for junk asymmetric private key + # serialization), RC4, Blowfish, IDEA, SEED, etc. These things + # are ugly legacy, but we aren't going to get rid of them + # any time soon. + if cls.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + if not os.environ.get("CRYPTOGRAPHY_OPENSSL_NO_LEGACY"): + cls._legacy_provider = cls.lib.OSSL_PROVIDER_load( + cls.ffi.NULL, b"legacy" + ) + cls._legacy_provider_loaded = ( + cls._legacy_provider != cls.ffi.NULL + ) + _legacy_provider_error(cls._legacy_provider_loaded) + + cls._default_provider = cls.lib.OSSL_PROVIDER_load( + cls.ffi.NULL, b"default" + ) + _openssl_assert( + cls.lib, cls._default_provider != cls.ffi.NULL + ) + + @classmethod + def init_static_locks(cls) -> None: + cls._ensure_ffi_initialized() + + +def _verify_package_version(version: str) -> None: + # Occasionally we run into situations where the version of the Python + # package does not match the version of the shared object that is loaded. + # This may occur in environments where multiple versions of cryptography + # are installed and available in the python path. To avoid errors cropping + # up later this code checks that the currently imported package and the + # shared object that were loaded have the same version and raise an + # ImportError if they do not + so_package_version = _openssl.ffi.string( + _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION + ) + if version.encode("ascii") != so_package_version: + raise ImportError( + "The version of cryptography does not match the loaded " + "shared object. This can happen if you have multiple copies of " + "cryptography installed in your Python path. Please try creating " + "a new virtual environment to resolve this issue. " + "Loaded python version: {}, shared object version: {}".format( + version, so_package_version + ) + ) + + _openssl_assert( + _openssl.lib, + _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(), + ) + + +_verify_package_version(cryptography.__version__) + +Binding.init_static_locks() + +if ( + sys.platform == "win32" + and os.environ.get("PROCESSOR_ARCHITEW6432") is not None +): + warnings.warn( + "You are using cryptography on a 32-bit Python on a 64-bit Windows " + "Operating System. Cryptography will be significantly faster if you " + "switch to using a 64-bit Python.", + UserWarning, + stacklevel=2, + ) + + +def _verify_openssl_version(lib): + if ( + not lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + and not lib.CRYPTOGRAPHY_IS_LIBRESSL + and not lib.CRYPTOGRAPHY_IS_BORINGSSL + ): + warnings.warn( + "Support for OpenSSL less than version 1.1.1d is deprecated and " + "the next release of cryptography will drop support. Please " + "upgrade your OpenSSL to version 1.1.1d or newer.", + utils.DeprecatedIn40, + ) + + +_verify_openssl_version(Binding.lib) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b509336233c2fafe4185a49da5909c8bbb38dfd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__init__.py @@ -0,0 +1,3 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fd7f24c680e54bb4542519d8ce089acaa7c1962 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32b35e9ada8f2f0181a272af1bf5c897c9c2b715 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..628c73045bbb8cb05c9d544a829bbab01f262b74 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5777db12dee3c5f202ba711b6c5e364ad08e892 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a74131fd6ffb24a3f694bfcde6d75260cd182fb9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a40c219cfb0e2a497c18df0fde8a3c1849ecea02 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ad98b868c92fc7bbf8c00f1b0e5f6395740cc79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..902349bf1f83b64dfd7a7db033e0af1c60d36143 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a1774654edf338032d0a1729aa40e0fe0801c59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0289a1cfa2387082a3191d4473646d51c6ea3fc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..209ef197d642ebbc220bd9bcbc76703a78d99d96 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_asymmetric.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_asymmetric.py new file mode 100644 index 0000000000000000000000000000000000000000..fb815a0e9154d163157f76c9ea94576b95f1279d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_asymmetric.py @@ -0,0 +1,17 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import abc + +# This exists to break an import cycle. It is normally accessible from the +# asymmetric padding module. + + +class AsymmetricPadding(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this padding (e.g. "PSS", "PKCS1"). + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py new file mode 100644 index 0000000000000000000000000000000000000000..b36dccfb3427024381c2c612062e265769ff791e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py @@ -0,0 +1,43 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import abc +import typing + +# This exists to break an import cycle. It is normally accessible from the +# ciphers module. + + +class CipherAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this mode (e.g. "AES", "Camellia"). + """ + + @property + @abc.abstractmethod + def key_sizes(self) -> typing.FrozenSet[int]: + """ + Valid key sizes for this algorithm in bits + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The size of the key being used as an integer in bits (e.g. 128, 256). + """ + + +class BlockCipherAlgorithm(CipherAlgorithm): + key: bytes + + @property + @abc.abstractmethod + def block_size(self) -> int: + """ + The size of a block as an integer in bits (e.g. 64, 128). + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py new file mode 100644 index 0000000000000000000000000000000000000000..aa41f30d2586b45513168403c3dbb31bf046d1f7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py @@ -0,0 +1,168 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import abc +import typing + +from cryptography import utils +from cryptography.hazmat.primitives.hashes import HashAlgorithm + +# This exists to break an import cycle. These classes are normally accessible +# from the serialization module. + + +class PBES(utils.Enum): + PBESv1SHA1And3KeyTripleDESCBC = "PBESv1 using SHA1 and 3-Key TripleDES" + PBESv2SHA256AndAES256CBC = "PBESv2 using SHA256 PBKDF2 and AES256 CBC" + + +class Encoding(utils.Enum): + PEM = "PEM" + DER = "DER" + OpenSSH = "OpenSSH" + Raw = "Raw" + X962 = "ANSI X9.62" + SMIME = "S/MIME" + + +class PrivateFormat(utils.Enum): + PKCS8 = "PKCS8" + TraditionalOpenSSL = "TraditionalOpenSSL" + Raw = "Raw" + OpenSSH = "OpenSSH" + PKCS12 = "PKCS12" + + def encryption_builder(self) -> "KeySerializationEncryptionBuilder": + if self not in (PrivateFormat.OpenSSH, PrivateFormat.PKCS12): + raise ValueError( + "encryption_builder only supported with PrivateFormat.OpenSSH" + " and PrivateFormat.PKCS12" + ) + return KeySerializationEncryptionBuilder(self) + + +class PublicFormat(utils.Enum): + SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" + PKCS1 = "Raw PKCS#1" + OpenSSH = "OpenSSH" + Raw = "Raw" + CompressedPoint = "X9.62 Compressed Point" + UncompressedPoint = "X9.62 Uncompressed Point" + + +class ParameterFormat(utils.Enum): + PKCS3 = "PKCS3" + + +class KeySerializationEncryption(metaclass=abc.ABCMeta): + pass + + +class BestAvailableEncryption(KeySerializationEncryption): + def __init__(self, password: bytes): + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + self.password = password + + +class NoEncryption(KeySerializationEncryption): + pass + + +class KeySerializationEncryptionBuilder: + def __init__( + self, + format: PrivateFormat, + *, + _kdf_rounds: typing.Optional[int] = None, + _hmac_hash: typing.Optional[HashAlgorithm] = None, + _key_cert_algorithm: typing.Optional[PBES] = None, + ) -> None: + self._format = format + + self._kdf_rounds = _kdf_rounds + self._hmac_hash = _hmac_hash + self._key_cert_algorithm = _key_cert_algorithm + + def kdf_rounds(self, rounds: int) -> "KeySerializationEncryptionBuilder": + if self._kdf_rounds is not None: + raise ValueError("kdf_rounds already set") + + if not isinstance(rounds, int): + raise TypeError("kdf_rounds must be an integer") + + if rounds < 1: + raise ValueError("kdf_rounds must be a positive integer") + + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=rounds, + _hmac_hash=self._hmac_hash, + _key_cert_algorithm=self._key_cert_algorithm, + ) + + def hmac_hash( + self, algorithm: HashAlgorithm + ) -> "KeySerializationEncryptionBuilder": + if self._format is not PrivateFormat.PKCS12: + raise TypeError( + "hmac_hash only supported with PrivateFormat.PKCS12" + ) + + if self._hmac_hash is not None: + raise ValueError("hmac_hash already set") + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=self._kdf_rounds, + _hmac_hash=algorithm, + _key_cert_algorithm=self._key_cert_algorithm, + ) + + def key_cert_algorithm( + self, algorithm: PBES + ) -> "KeySerializationEncryptionBuilder": + if self._format is not PrivateFormat.PKCS12: + raise TypeError( + "key_cert_algorithm only supported with " + "PrivateFormat.PKCS12" + ) + if self._key_cert_algorithm is not None: + raise ValueError("key_cert_algorithm already set") + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=self._kdf_rounds, + _hmac_hash=self._hmac_hash, + _key_cert_algorithm=algorithm, + ) + + def build(self, password: bytes) -> KeySerializationEncryption: + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + return _KeySerializationEncryption( + self._format, + password, + kdf_rounds=self._kdf_rounds, + hmac_hash=self._hmac_hash, + key_cert_algorithm=self._key_cert_algorithm, + ) + + +class _KeySerializationEncryption(KeySerializationEncryption): + def __init__( + self, + format: PrivateFormat, + password: bytes, + *, + kdf_rounds: typing.Optional[int], + hmac_hash: typing.Optional[HashAlgorithm], + key_cert_algorithm: typing.Optional[PBES], + ): + self._format = format + self.password = password + + self._kdf_rounds = kdf_rounds + self._hmac_hash = hmac_hash + self._key_cert_algorithm = key_cert_algorithm diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b509336233c2fafe4185a49da5909c8bbb38dfd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py @@ -0,0 +1,3 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2563d8f7727e6dbc05abf4ecedb336d5849cdd08 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8398d2a7f7863f6254c4a2f352437e7acaac0216 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad6c557c594c1f0bbbfb561baea94659c05ff80e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31cc38313c597a68269c6da6a315fe83f8c0a18a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33345e04e005e50448b50c03f0f076d30d4af3e5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95561d5603adb086444e02fe0cb3a236871c2113 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..467ccebd03120de312ea4a3a5bf8fe368382b764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8cf5604a21b997332bac7c6274f859b53b97796 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88d6a2ad587f15808cadeb526c1addd03290792b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec80000ad1d17c805f86fa4dc033d7467e6f2bd0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e42235f2c3ab560396b629ebba7b88b08e84dc1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ead6d1ada8a2b5827991b27f909d24e845b5c13 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py new file mode 100644 index 0000000000000000000000000000000000000000..debf01e134fa4a59bac7ab7854e1b166ef2fc5dd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py @@ -0,0 +1,251 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography.hazmat.primitives import _serialization + +_MIN_MODULUS_SIZE = 512 + + +def generate_parameters( + generator: int, key_size: int, backend: typing.Any = None +) -> "DHParameters": + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.generate_dh_parameters(generator, key_size) + + +class DHParameterNumbers: + def __init__(self, p: int, g: int, q: typing.Optional[int] = None) -> None: + if not isinstance(p, int) or not isinstance(g, int): + raise TypeError("p and g must be integers") + if q is not None and not isinstance(q, int): + raise TypeError("q must be integer or None") + + if g < 2: + raise ValueError("DH generator must be 2 or greater") + + if p.bit_length() < _MIN_MODULUS_SIZE: + raise ValueError( + f"p (modulus) must be at least {_MIN_MODULUS_SIZE}-bit" + ) + + self._p = p + self._g = g + self._q = q + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DHParameterNumbers): + return NotImplemented + + return ( + self._p == other._p and self._g == other._g and self._q == other._q + ) + + def parameters(self, backend: typing.Any = None) -> "DHParameters": + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dh_parameter_numbers(self) + + @property + def p(self) -> int: + return self._p + + @property + def g(self) -> int: + return self._g + + @property + def q(self) -> typing.Optional[int]: + return self._q + + +class DHPublicNumbers: + def __init__(self, y: int, parameter_numbers: DHParameterNumbers) -> None: + if not isinstance(y, int): + raise TypeError("y must be an integer.") + + if not isinstance(parameter_numbers, DHParameterNumbers): + raise TypeError( + "parameters must be an instance of DHParameterNumbers." + ) + + self._y = y + self._parameter_numbers = parameter_numbers + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DHPublicNumbers): + return NotImplemented + + return ( + self._y == other._y + and self._parameter_numbers == other._parameter_numbers + ) + + def public_key(self, backend: typing.Any = None) -> "DHPublicKey": + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dh_public_numbers(self) + + @property + def y(self) -> int: + return self._y + + @property + def parameter_numbers(self) -> DHParameterNumbers: + return self._parameter_numbers + + +class DHPrivateNumbers: + def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None: + if not isinstance(x, int): + raise TypeError("x must be an integer.") + + if not isinstance(public_numbers, DHPublicNumbers): + raise TypeError( + "public_numbers must be an instance of " "DHPublicNumbers." + ) + + self._x = x + self._public_numbers = public_numbers + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DHPrivateNumbers): + return NotImplemented + + return ( + self._x == other._x + and self._public_numbers == other._public_numbers + ) + + def private_key(self, backend: typing.Any = None) -> "DHPrivateKey": + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dh_private_numbers(self) + + @property + def public_numbers(self) -> DHPublicNumbers: + return self._public_numbers + + @property + def x(self) -> int: + return self._x + + +class DHParameters(metaclass=abc.ABCMeta): + @abc.abstractmethod + def generate_private_key(self) -> "DHPrivateKey": + """ + Generates and returns a DHPrivateKey. + """ + + @abc.abstractmethod + def parameter_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.ParameterFormat, + ) -> bytes: + """ + Returns the parameters serialized as bytes. + """ + + @abc.abstractmethod + def parameter_numbers(self) -> DHParameterNumbers: + """ + Returns a DHParameterNumbers. + """ + + +DHParametersWithSerialization = DHParameters + + +class DHPublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self) -> DHParameters: + """ + The DHParameters object associated with this public key. + """ + + @abc.abstractmethod + def public_numbers(self) -> DHPublicNumbers: + """ + Returns a DHPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + +DHPublicKeyWithSerialization = DHPublicKey + + +class DHPrivateKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self) -> DHPublicKey: + """ + The DHPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self) -> DHParameters: + """ + The DHParameters object associated with this private key. + """ + + @abc.abstractmethod + def exchange(self, peer_public_key: DHPublicKey) -> bytes: + """ + Given peer's DHPublicKey, carry out the key exchange and + return shared key as bytes. + """ + + @abc.abstractmethod + def private_numbers(self) -> DHPrivateNumbers: + """ + Returns a DHPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + +DHPrivateKeyWithSerialization = DHPrivateKey diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py new file mode 100644 index 0000000000000000000000000000000000000000..6103d809355fac3eaa143e922fe150c9a2152935 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -0,0 +1,288 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + + +class DSAParameters(metaclass=abc.ABCMeta): + @abc.abstractmethod + def generate_private_key(self) -> "DSAPrivateKey": + """ + Generates and returns a DSAPrivateKey. + """ + + @abc.abstractmethod + def parameter_numbers(self) -> "DSAParameterNumbers": + """ + Returns a DSAParameterNumbers. + """ + + +DSAParametersWithNumbers = DSAParameters + + +class DSAPrivateKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self) -> "DSAPublicKey": + """ + The DSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self) -> DSAParameters: + """ + The DSAParameters object associated with this private key. + """ + + @abc.abstractmethod + def sign( + self, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + """ + Signs the data + """ + + @abc.abstractmethod + def private_numbers(self) -> "DSAPrivateNumbers": + """ + Returns a DSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + +DSAPrivateKeyWithSerialization = DSAPrivateKey + + +class DSAPublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self) -> DSAParameters: + """ + The DSAParameters object associated with this public key. + """ + + @abc.abstractmethod + def public_numbers(self) -> "DSAPublicNumbers": + """ + Returns a DSAPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: bytes, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + """ + Verifies the signature of the data. + """ + + +DSAPublicKeyWithSerialization = DSAPublicKey + + +class DSAParameterNumbers: + def __init__(self, p: int, q: int, g: int): + if ( + not isinstance(p, int) + or not isinstance(q, int) + or not isinstance(g, int) + ): + raise TypeError( + "DSAParameterNumbers p, q, and g arguments must be integers." + ) + + self._p = p + self._q = q + self._g = g + + @property + def p(self) -> int: + return self._p + + @property + def q(self) -> int: + return self._q + + @property + def g(self) -> int: + return self._g + + def parameters(self, backend: typing.Any = None) -> DSAParameters: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dsa_parameter_numbers(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DSAParameterNumbers): + return NotImplemented + + return self.p == other.p and self.q == other.q and self.g == other.g + + def __repr__(self) -> str: + return ( + "<DSAParameterNumbers(p={self.p}, q={self.q}, " + "g={self.g})>".format(self=self) + ) + + +class DSAPublicNumbers: + def __init__(self, y: int, parameter_numbers: DSAParameterNumbers): + if not isinstance(y, int): + raise TypeError("DSAPublicNumbers y argument must be an integer.") + + if not isinstance(parameter_numbers, DSAParameterNumbers): + raise TypeError( + "parameter_numbers must be a DSAParameterNumbers instance." + ) + + self._y = y + self._parameter_numbers = parameter_numbers + + @property + def y(self) -> int: + return self._y + + @property + def parameter_numbers(self) -> DSAParameterNumbers: + return self._parameter_numbers + + def public_key(self, backend: typing.Any = None) -> DSAPublicKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dsa_public_numbers(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DSAPublicNumbers): + return NotImplemented + + return ( + self.y == other.y + and self.parameter_numbers == other.parameter_numbers + ) + + def __repr__(self) -> str: + return ( + "<DSAPublicNumbers(y={self.y}, " + "parameter_numbers={self.parameter_numbers})>".format(self=self) + ) + + +class DSAPrivateNumbers: + def __init__(self, x: int, public_numbers: DSAPublicNumbers): + if not isinstance(x, int): + raise TypeError("DSAPrivateNumbers x argument must be an integer.") + + if not isinstance(public_numbers, DSAPublicNumbers): + raise TypeError( + "public_numbers must be a DSAPublicNumbers instance." + ) + self._public_numbers = public_numbers + self._x = x + + @property + def x(self) -> int: + return self._x + + @property + def public_numbers(self) -> DSAPublicNumbers: + return self._public_numbers + + def private_key(self, backend: typing.Any = None) -> DSAPrivateKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_dsa_private_numbers(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DSAPrivateNumbers): + return NotImplemented + + return ( + self.x == other.x and self.public_numbers == other.public_numbers + ) + + +def generate_parameters( + key_size: int, backend: typing.Any = None +) -> DSAParameters: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.generate_dsa_parameters(key_size) + + +def generate_private_key( + key_size: int, backend: typing.Any = None +) -> DSAPrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.generate_dsa_private_key_and_parameters(key_size) + + +def _check_dsa_parameters(parameters: DSAParameterNumbers) -> None: + if parameters.p.bit_length() not in [1024, 2048, 3072, 4096]: + raise ValueError( + "p must be exactly 1024, 2048, 3072, or 4096 bits long" + ) + if parameters.q.bit_length() not in [160, 224, 256]: + raise ValueError("q must be exactly 160, 224, or 256 bits long") + + if not (1 < parameters.g < parameters.p): + raise ValueError("g, p don't satisfy 1 < g < p.") + + +def _check_dsa_private_numbers(numbers: DSAPrivateNumbers) -> None: + parameters = numbers.public_numbers.parameter_numbers + _check_dsa_parameters(parameters) + if numbers.x <= 0 or numbers.x >= parameters.q: + raise ValueError("x must be > 0 and < q.") + + if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p): + raise ValueError("y must be equal to (g ** x % p).") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py new file mode 100644 index 0000000000000000000000000000000000000000..c5df2c27a6e8ff8ef2f5cbb28089cf02d0489a37 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py @@ -0,0 +1,483 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography import utils +from cryptography.hazmat._oid import ObjectIdentifier +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + + +class EllipticCurveOID: + SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") + SECP224R1 = ObjectIdentifier("1.3.132.0.33") + SECP256K1 = ObjectIdentifier("1.3.132.0.10") + SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") + SECP384R1 = ObjectIdentifier("1.3.132.0.34") + SECP521R1 = ObjectIdentifier("1.3.132.0.35") + BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") + BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") + BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") + SECT163K1 = ObjectIdentifier("1.3.132.0.1") + SECT163R2 = ObjectIdentifier("1.3.132.0.15") + SECT233K1 = ObjectIdentifier("1.3.132.0.26") + SECT233R1 = ObjectIdentifier("1.3.132.0.27") + SECT283K1 = ObjectIdentifier("1.3.132.0.16") + SECT283R1 = ObjectIdentifier("1.3.132.0.17") + SECT409K1 = ObjectIdentifier("1.3.132.0.36") + SECT409R1 = ObjectIdentifier("1.3.132.0.37") + SECT571K1 = ObjectIdentifier("1.3.132.0.38") + SECT571R1 = ObjectIdentifier("1.3.132.0.39") + + +class EllipticCurve(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + The name of the curve. e.g. secp256r1. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + +class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def algorithm( + self, + ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]: + """ + The digest algorithm used with this signature. + """ + + +class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def exchange( + self, algorithm: "ECDH", peer_public_key: "EllipticCurvePublicKey" + ) -> bytes: + """ + Performs a key exchange operation using the provided algorithm with the + provided peer's public key. + """ + + @abc.abstractmethod + def public_key(self) -> "EllipticCurvePublicKey": + """ + The EllipticCurvePublicKey for this private key. + """ + + @property + @abc.abstractmethod + def curve(self) -> EllipticCurve: + """ + The EllipticCurve that this key is on. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractmethod + def sign( + self, + data: bytes, + signature_algorithm: EllipticCurveSignatureAlgorithm, + ) -> bytes: + """ + Signs the data + """ + + @abc.abstractmethod + def private_numbers(self) -> "EllipticCurvePrivateNumbers": + """ + Returns an EllipticCurvePrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + +EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey + + +class EllipticCurvePublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def curve(self) -> EllipticCurve: + """ + The EllipticCurve that this key is on. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractmethod + def public_numbers(self) -> "EllipticCurvePublicNumbers": + """ + Returns an EllipticCurvePublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: bytes, + data: bytes, + signature_algorithm: EllipticCurveSignatureAlgorithm, + ) -> None: + """ + Verifies the signature of the data. + """ + + @classmethod + def from_encoded_point( + cls, curve: EllipticCurve, data: bytes + ) -> "EllipticCurvePublicKey": + utils._check_bytes("data", data) + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must be an EllipticCurve instance") + + if len(data) == 0: + raise ValueError("data must not be an empty byte string") + + if data[0] not in [0x02, 0x03, 0x04]: + raise ValueError("Unsupported elliptic curve point type") + + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.load_elliptic_curve_public_bytes(curve, data) + + +EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey + + +class SECT571R1(EllipticCurve): + name = "sect571r1" + key_size = 570 + + +class SECT409R1(EllipticCurve): + name = "sect409r1" + key_size = 409 + + +class SECT283R1(EllipticCurve): + name = "sect283r1" + key_size = 283 + + +class SECT233R1(EllipticCurve): + name = "sect233r1" + key_size = 233 + + +class SECT163R2(EllipticCurve): + name = "sect163r2" + key_size = 163 + + +class SECT571K1(EllipticCurve): + name = "sect571k1" + key_size = 571 + + +class SECT409K1(EllipticCurve): + name = "sect409k1" + key_size = 409 + + +class SECT283K1(EllipticCurve): + name = "sect283k1" + key_size = 283 + + +class SECT233K1(EllipticCurve): + name = "sect233k1" + key_size = 233 + + +class SECT163K1(EllipticCurve): + name = "sect163k1" + key_size = 163 + + +class SECP521R1(EllipticCurve): + name = "secp521r1" + key_size = 521 + + +class SECP384R1(EllipticCurve): + name = "secp384r1" + key_size = 384 + + +class SECP256R1(EllipticCurve): + name = "secp256r1" + key_size = 256 + + +class SECP256K1(EllipticCurve): + name = "secp256k1" + key_size = 256 + + +class SECP224R1(EllipticCurve): + name = "secp224r1" + key_size = 224 + + +class SECP192R1(EllipticCurve): + name = "secp192r1" + key_size = 192 + + +class BrainpoolP256R1(EllipticCurve): + name = "brainpoolP256r1" + key_size = 256 + + +class BrainpoolP384R1(EllipticCurve): + name = "brainpoolP384r1" + key_size = 384 + + +class BrainpoolP512R1(EllipticCurve): + name = "brainpoolP512r1" + key_size = 512 + + +_CURVE_TYPES: typing.Dict[str, typing.Type[EllipticCurve]] = { + "prime192v1": SECP192R1, + "prime256v1": SECP256R1, + "secp192r1": SECP192R1, + "secp224r1": SECP224R1, + "secp256r1": SECP256R1, + "secp384r1": SECP384R1, + "secp521r1": SECP521R1, + "secp256k1": SECP256K1, + "sect163k1": SECT163K1, + "sect233k1": SECT233K1, + "sect283k1": SECT283K1, + "sect409k1": SECT409K1, + "sect571k1": SECT571K1, + "sect163r2": SECT163R2, + "sect233r1": SECT233R1, + "sect283r1": SECT283R1, + "sect409r1": SECT409R1, + "sect571r1": SECT571R1, + "brainpoolP256r1": BrainpoolP256R1, + "brainpoolP384r1": BrainpoolP384R1, + "brainpoolP512r1": BrainpoolP512R1, +} + + +class ECDSA(EllipticCurveSignatureAlgorithm): + def __init__( + self, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ): + self._algorithm = algorithm + + @property + def algorithm( + self, + ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]: + return self._algorithm + + +def generate_private_key( + curve: EllipticCurve, backend: typing.Any = None +) -> EllipticCurvePrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.generate_elliptic_curve_private_key(curve) + + +def derive_private_key( + private_value: int, + curve: EllipticCurve, + backend: typing.Any = None, +) -> EllipticCurvePrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + if not isinstance(private_value, int): + raise TypeError("private_value must be an integer type.") + + if private_value <= 0: + raise ValueError("private_value must be a positive integer.") + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must provide the EllipticCurve interface.") + + return ossl.derive_elliptic_curve_private_key(private_value, curve) + + +class EllipticCurvePublicNumbers: + def __init__(self, x: int, y: int, curve: EllipticCurve): + if not isinstance(x, int) or not isinstance(y, int): + raise TypeError("x and y must be integers.") + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must provide the EllipticCurve interface.") + + self._y = y + self._x = x + self._curve = curve + + def public_key(self, backend: typing.Any = None) -> EllipticCurvePublicKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_elliptic_curve_public_numbers(self) + + @property + def curve(self) -> EllipticCurve: + return self._curve + + @property + def x(self) -> int: + return self._x + + @property + def y(self) -> int: + return self._y + + def __eq__(self, other: object) -> bool: + if not isinstance(other, EllipticCurvePublicNumbers): + return NotImplemented + + return ( + self.x == other.x + and self.y == other.y + and self.curve.name == other.curve.name + and self.curve.key_size == other.curve.key_size + ) + + def __hash__(self) -> int: + return hash((self.x, self.y, self.curve.name, self.curve.key_size)) + + def __repr__(self) -> str: + return ( + "<EllipticCurvePublicNumbers(curve={0.curve.name}, x={0.x}, " + "y={0.y}>".format(self) + ) + + +class EllipticCurvePrivateNumbers: + def __init__( + self, private_value: int, public_numbers: EllipticCurvePublicNumbers + ): + if not isinstance(private_value, int): + raise TypeError("private_value must be an integer.") + + if not isinstance(public_numbers, EllipticCurvePublicNumbers): + raise TypeError( + "public_numbers must be an EllipticCurvePublicNumbers " + "instance." + ) + + self._private_value = private_value + self._public_numbers = public_numbers + + def private_key( + self, backend: typing.Any = None + ) -> EllipticCurvePrivateKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_elliptic_curve_private_numbers(self) + + @property + def private_value(self) -> int: + return self._private_value + + @property + def public_numbers(self) -> EllipticCurvePublicNumbers: + return self._public_numbers + + def __eq__(self, other: object) -> bool: + if not isinstance(other, EllipticCurvePrivateNumbers): + return NotImplemented + + return ( + self.private_value == other.private_value + and self.public_numbers == other.public_numbers + ) + + def __hash__(self) -> int: + return hash((self.private_value, self.public_numbers)) + + +class ECDH: + pass + + +_OID_TO_CURVE = { + EllipticCurveOID.SECP192R1: SECP192R1, + EllipticCurveOID.SECP224R1: SECP224R1, + EllipticCurveOID.SECP256K1: SECP256K1, + EllipticCurveOID.SECP256R1: SECP256R1, + EllipticCurveOID.SECP384R1: SECP384R1, + EllipticCurveOID.SECP521R1: SECP521R1, + EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, + EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, + EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, + EllipticCurveOID.SECT163K1: SECT163K1, + EllipticCurveOID.SECT163R2: SECT163R2, + EllipticCurveOID.SECT233K1: SECT233K1, + EllipticCurveOID.SECT233R1: SECT233R1, + EllipticCurveOID.SECT283K1: SECT283K1, + EllipticCurveOID.SECT283R1: SECT283R1, + EllipticCurveOID.SECT409K1: SECT409K1, + EllipticCurveOID.SECT409R1: SECT409R1, + EllipticCurveOID.SECT571K1: SECT571K1, + EllipticCurveOID.SECT571R1: SECT571R1, +} + + +def get_curve_for_oid(oid: ObjectIdentifier) -> typing.Type[EllipticCurve]: + try: + return _OID_TO_CURVE[oid] + except KeyError: + raise LookupError( + "The provided object identifier has no matching elliptic " + "curve class" + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py new file mode 100644 index 0000000000000000000000000000000000000000..df34159ec7e02c7bb6d8611a18865151cd718b1c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -0,0 +1,111 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import _serialization + +_ED25519_KEY_SIZE = 32 +_ED25519_SIG_SIZE = 64 + + +class Ed25519PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> "Ed25519PublicKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + return self.public_bytes( + _serialization.Encoding.Raw, _serialization.PublicFormat.Raw + ) + + @abc.abstractmethod + def verify(self, signature: bytes, data: bytes) -> None: + """ + Verify the signature. + """ + + +class Ed25519PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> "Ed25519PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_generate_key() + + @classmethod + def from_private_bytes(cls, data: bytes) -> "Ed25519PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> Ed25519PublicKey: + """ + The Ed25519PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + return self.private_bytes( + _serialization.Encoding.Raw, + _serialization.PrivateFormat.Raw, + _serialization.NoEncryption(), + ) + + @abc.abstractmethod + def sign(self, data: bytes) -> bytes: + """ + Signs the data. + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py new file mode 100644 index 0000000000000000000000000000000000000000..8b0ac1fd87a32031e3a3e71e8c591dcc532bf854 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -0,0 +1,107 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import _serialization + + +class Ed448PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> "Ed448PublicKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed448_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + return self.public_bytes( + _serialization.Encoding.Raw, _serialization.PublicFormat.Raw + ) + + @abc.abstractmethod + def verify(self, signature: bytes, data: bytes) -> None: + """ + Verify the signature. + """ + + +class Ed448PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> "Ed448PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + return backend.ed448_generate_key() + + @classmethod + def from_private_bytes(cls, data: bytes) -> "Ed448PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed448_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> Ed448PublicKey: + """ + The Ed448PublicKey derived from the private key. + """ + + @abc.abstractmethod + def sign(self, data: bytes) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + return self.private_bytes( + _serialization.Encoding.Raw, + _serialization.PrivateFormat.Raw, + _serialization.NoEncryption(), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py new file mode 100644 index 0000000000000000000000000000000000000000..dd3c648f165e3f50d8c98f199b31b20b33084ed8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py @@ -0,0 +1,101 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives._asymmetric import ( + AsymmetricPadding as AsymmetricPadding, +) +from cryptography.hazmat.primitives.asymmetric import rsa + + +class PKCS1v15(AsymmetricPadding): + name = "EMSA-PKCS1-v1_5" + + +class _MaxLength: + "Sentinel value for `MAX_LENGTH`." + + +class _Auto: + "Sentinel value for `AUTO`." + + +class _DigestLength: + "Sentinel value for `DIGEST_LENGTH`." + + +class PSS(AsymmetricPadding): + MAX_LENGTH = _MaxLength() + AUTO = _Auto() + DIGEST_LENGTH = _DigestLength() + name = "EMSA-PSS" + _salt_length: typing.Union[int, _MaxLength, _Auto, _DigestLength] + + def __init__( + self, + mgf: "MGF", + salt_length: typing.Union[int, _MaxLength, _Auto, _DigestLength], + ) -> None: + self._mgf = mgf + + if not isinstance( + salt_length, (int, _MaxLength, _Auto, _DigestLength) + ): + raise TypeError( + "salt_length must be an integer, MAX_LENGTH, " + "DIGEST_LENGTH, or AUTO" + ) + + if isinstance(salt_length, int) and salt_length < 0: + raise ValueError("salt_length must be zero or greater.") + + self._salt_length = salt_length + + +class OAEP(AsymmetricPadding): + name = "EME-OAEP" + + def __init__( + self, + mgf: "MGF", + algorithm: hashes.HashAlgorithm, + label: typing.Optional[bytes], + ): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._mgf = mgf + self._algorithm = algorithm + self._label = label + + +class MGF(metaclass=abc.ABCMeta): + _algorithm: hashes.HashAlgorithm + + +class MGF1(MGF): + MAX_LENGTH = _MaxLength() + + def __init__(self, algorithm: hashes.HashAlgorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._algorithm = algorithm + + +def calculate_max_pss_salt_length( + key: typing.Union["rsa.RSAPrivateKey", "rsa.RSAPublicKey"], + hash_algorithm: hashes.HashAlgorithm, +) -> int: + if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): + raise TypeError("key must be an RSA public or private key") + # bit length - 1 per RFC 3447 + emlen = (key.key_size + 6) // 8 + salt_length = emlen - hash_algorithm.digest_size - 2 + assert salt_length >= 0 + return salt_length diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py new file mode 100644 index 0000000000000000000000000000000000000000..81f5a0ec639fd4c557840cada35360804639fe1f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -0,0 +1,432 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing +from math import gcd + +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + + +class RSAPrivateKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: + """ + Decrypts the provided ciphertext. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_key(self) -> "RSAPublicKey": + """ + The RSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def sign( + self, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def private_numbers(self) -> "RSAPrivateNumbers": + """ + Returns an RSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + +RSAPrivateKeyWithSerialization = RSAPrivateKey + + +class RSAPublicKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: + """ + Encrypts the given plaintext. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_numbers(self) -> "RSAPublicNumbers": + """ + Returns an RSAPublicNumbers + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: bytes, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + """ + Verifies the signature of the data. + """ + + @abc.abstractmethod + def recover_data_from_signature( + self, + signature: bytes, + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> bytes: + """ + Recovers the original data from the signature. + """ + + +RSAPublicKeyWithSerialization = RSAPublicKey + + +def generate_private_key( + public_exponent: int, + key_size: int, + backend: typing.Any = None, +) -> RSAPrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + _verify_rsa_parameters(public_exponent, key_size) + return ossl.generate_rsa_private_key(public_exponent, key_size) + + +def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None: + if public_exponent not in (3, 65537): + raise ValueError( + "public_exponent must be either 3 (for legacy compatibility) or " + "65537. Almost everyone should choose 65537 here!" + ) + + if key_size < 512: + raise ValueError("key_size must be at least 512-bits.") + + +def _check_private_key_components( + p: int, + q: int, + private_exponent: int, + dmp1: int, + dmq1: int, + iqmp: int, + public_exponent: int, + modulus: int, +) -> None: + if modulus < 3: + raise ValueError("modulus must be >= 3.") + + if p >= modulus: + raise ValueError("p must be < modulus.") + + if q >= modulus: + raise ValueError("q must be < modulus.") + + if dmp1 >= modulus: + raise ValueError("dmp1 must be < modulus.") + + if dmq1 >= modulus: + raise ValueError("dmq1 must be < modulus.") + + if iqmp >= modulus: + raise ValueError("iqmp must be < modulus.") + + if private_exponent >= modulus: + raise ValueError("private_exponent must be < modulus.") + + if public_exponent < 3 or public_exponent >= modulus: + raise ValueError("public_exponent must be >= 3 and < modulus.") + + if public_exponent & 1 == 0: + raise ValueError("public_exponent must be odd.") + + if dmp1 & 1 == 0: + raise ValueError("dmp1 must be odd.") + + if dmq1 & 1 == 0: + raise ValueError("dmq1 must be odd.") + + if p * q != modulus: + raise ValueError("p*q must equal modulus.") + + +def _check_public_key_components(e: int, n: int) -> None: + if n < 3: + raise ValueError("n must be >= 3.") + + if e < 3 or e >= n: + raise ValueError("e must be >= 3 and < n.") + + if e & 1 == 0: + raise ValueError("e must be odd.") + + +def _modinv(e: int, m: int) -> int: + """ + Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 + """ + x1, x2 = 1, 0 + a, b = e, m + while b > 0: + q, r = divmod(a, b) + xn = x1 - q * x2 + a, b, x1, x2 = b, r, x2, xn + return x1 % m + + +def rsa_crt_iqmp(p: int, q: int) -> int: + """ + Compute the CRT (q ** -1) % p value from RSA primes p and q. + """ + return _modinv(q, p) + + +def rsa_crt_dmp1(private_exponent: int, p: int) -> int: + """ + Compute the CRT private_exponent % (p - 1) value from the RSA + private_exponent (d) and p. + """ + return private_exponent % (p - 1) + + +def rsa_crt_dmq1(private_exponent: int, q: int) -> int: + """ + Compute the CRT private_exponent % (q - 1) value from the RSA + private_exponent (d) and q. + """ + return private_exponent % (q - 1) + + +# Controls the number of iterations rsa_recover_prime_factors will perform +# to obtain the prime factors. Each iteration increments by 2 so the actual +# maximum attempts is half this number. +_MAX_RECOVERY_ATTEMPTS = 1000 + + +def rsa_recover_prime_factors( + n: int, e: int, d: int +) -> typing.Tuple[int, int]: + """ + Compute factors p and q from the private exponent d. We assume that n has + no more than two factors. This function is adapted from code in PyCrypto. + """ + # See 8.2.2(i) in Handbook of Applied Cryptography. + ktot = d * e - 1 + # The quantity d*e-1 is a multiple of phi(n), even, + # and can be represented as t*2^s. + t = ktot + while t % 2 == 0: + t = t // 2 + # Cycle through all multiplicative inverses in Zn. + # The algorithm is non-deterministic, but there is a 50% chance + # any candidate a leads to successful factoring. + # See "Digitalized Signatures and Public Key Functions as Intractable + # as Factorization", M. Rabin, 1979 + spotted = False + a = 2 + while not spotted and a < _MAX_RECOVERY_ATTEMPTS: + k = t + # Cycle through all values a^{t*2^i}=a^k + while k < ktot: + cand = pow(a, k, n) + # Check if a^k is a non-trivial root of unity (mod n) + if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: + # We have found a number such that (cand-1)(cand+1)=0 (mod n). + # Either of the terms divides n. + p = gcd(cand + 1, n) + spotted = True + break + k *= 2 + # This value was not any good... let's try another! + a += 2 + if not spotted: + raise ValueError("Unable to compute factors p and q from exponent d.") + # Found ! + q, r = divmod(n, p) + assert r == 0 + p, q = sorted((p, q), reverse=True) + return (p, q) + + +class RSAPrivateNumbers: + def __init__( + self, + p: int, + q: int, + d: int, + dmp1: int, + dmq1: int, + iqmp: int, + public_numbers: "RSAPublicNumbers", + ): + if ( + not isinstance(p, int) + or not isinstance(q, int) + or not isinstance(d, int) + or not isinstance(dmp1, int) + or not isinstance(dmq1, int) + or not isinstance(iqmp, int) + ): + raise TypeError( + "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must" + " all be an integers." + ) + + if not isinstance(public_numbers, RSAPublicNumbers): + raise TypeError( + "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers" + " instance." + ) + + self._p = p + self._q = q + self._d = d + self._dmp1 = dmp1 + self._dmq1 = dmq1 + self._iqmp = iqmp + self._public_numbers = public_numbers + + @property + def p(self) -> int: + return self._p + + @property + def q(self) -> int: + return self._q + + @property + def d(self) -> int: + return self._d + + @property + def dmp1(self) -> int: + return self._dmp1 + + @property + def dmq1(self) -> int: + return self._dmq1 + + @property + def iqmp(self) -> int: + return self._iqmp + + @property + def public_numbers(self) -> "RSAPublicNumbers": + return self._public_numbers + + def private_key( + self, + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, + ) -> RSAPrivateKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_rsa_private_numbers( + self, unsafe_skip_rsa_key_validation + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RSAPrivateNumbers): + return NotImplemented + + return ( + self.p == other.p + and self.q == other.q + and self.d == other.d + and self.dmp1 == other.dmp1 + and self.dmq1 == other.dmq1 + and self.iqmp == other.iqmp + and self.public_numbers == other.public_numbers + ) + + def __hash__(self) -> int: + return hash( + ( + self.p, + self.q, + self.d, + self.dmp1, + self.dmq1, + self.iqmp, + self.public_numbers, + ) + ) + + +class RSAPublicNumbers: + def __init__(self, e: int, n: int): + if not isinstance(e, int) or not isinstance(n, int): + raise TypeError("RSAPublicNumbers arguments must be integers.") + + self._e = e + self._n = n + + @property + def e(self) -> int: + return self._e + + @property + def n(self) -> int: + return self._n + + def public_key(self, backend: typing.Any = None) -> RSAPublicKey: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + return ossl.load_rsa_public_numbers(self) + + def __repr__(self) -> str: + return "<RSAPublicNumbers(e={0.e}, n={0.n})>".format(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RSAPublicNumbers): + return NotImplemented + + return self.e == other.e and self.n == other.n + + def __hash__(self) -> int: + return hash((self.e, self.n)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/types.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/types.py new file mode 100644 index 0000000000000000000000000000000000000000..e911a9f602c26ce383e1b3388a2cfc0f6b040f4e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/types.py @@ -0,0 +1,109 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import utils +from cryptography.hazmat.primitives.asymmetric import ( + dh, + dsa, + ec, + ed448, + ed25519, + rsa, + x448, + x25519, +) + +# Every asymmetric key type +PublicKeyTypes = typing.Union[ + dh.DHPublicKey, + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, +] +PUBLIC_KEY_TYPES = PublicKeyTypes +utils.deprecated( + PUBLIC_KEY_TYPES, + __name__, + "Use PublicKeyTypes instead", + utils.DeprecatedIn40, + name="PUBLIC_KEY_TYPES", +) +# Every asymmetric key type +PrivateKeyTypes = typing.Union[ + dh.DHPrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + x25519.X25519PrivateKey, + x448.X448PrivateKey, +] +PRIVATE_KEY_TYPES = PrivateKeyTypes +utils.deprecated( + PRIVATE_KEY_TYPES, + __name__, + "Use PrivateKeyTypes instead", + utils.DeprecatedIn40, + name="PRIVATE_KEY_TYPES", +) +# Just the key types we allow to be used for x509 signing. This mirrors +# the certificate public key types +CertificateIssuerPrivateKeyTypes = typing.Union[ + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, +] +CERTIFICATE_PRIVATE_KEY_TYPES = CertificateIssuerPrivateKeyTypes +utils.deprecated( + CERTIFICATE_PRIVATE_KEY_TYPES, + __name__, + "Use CertificateIssuerPrivateKeyTypes instead", + utils.DeprecatedIn40, + name="CERTIFICATE_PRIVATE_KEY_TYPES", +) +# Just the key types we allow to be used for x509 signing. This mirrors +# the certificate private key types +CertificateIssuerPublicKeyTypes = typing.Union[ + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, +] +CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES = CertificateIssuerPublicKeyTypes +utils.deprecated( + CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, + __name__, + "Use CertificateIssuerPublicKeyTypes instead", + utils.DeprecatedIn40, + name="CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES", +) +# This type removes DHPublicKey. x448/x25519 can be a public key +# but cannot be used in signing so they are allowed here. +CertificatePublicKeyTypes = typing.Union[ + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, +] +CERTIFICATE_PUBLIC_KEY_TYPES = CertificatePublicKeyTypes +utils.deprecated( + CERTIFICATE_PUBLIC_KEY_TYPES, + __name__, + "Use CertificatePublicKeyTypes instead", + utils.DeprecatedIn40, + name="CERTIFICATE_PUBLIC_KEY_TYPES", +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..140ca1960d9f783f805fad47fdfcbd8ee017aa7e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py @@ -0,0 +1,23 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.hazmat.bindings._rust import asn1 +from cryptography.hazmat.primitives import hashes + +decode_dss_signature = asn1.decode_dss_signature +encode_dss_signature = asn1.encode_dss_signature + + +class Prehashed: + def __init__(self, algorithm: hashes.HashAlgorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of HashAlgorithm.") + + self._algorithm = algorithm + self._digest_size = algorithm.digest_size + + @property + def digest_size(self) -> int: + return self._digest_size diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py new file mode 100644 index 0000000000000000000000000000000000000000..fb21fe1749a58076a73c8eecbf847f829ddbcadf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -0,0 +1,106 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization + + +class X25519PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> "X25519PublicKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return backend.x25519_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + + +# For LibreSSL +if hasattr(rust_openssl, "x25519"): + X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey) + + +class X25519PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> "X25519PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + return backend.x25519_generate_key() + + @classmethod + def from_private_bytes(cls, data: bytes) -> "X25519PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return backend.x25519_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> X25519PublicKey: + """ + Returns the public key assosciated with this private key + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def exchange(self, peer_public_key: X25519PublicKey) -> bytes: + """ + Performs a key exchange operation using the provided peer's public key. + """ + + +# For LibreSSL +if hasattr(rust_openssl, "x25519"): + X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py new file mode 100644 index 0000000000000000000000000000000000000000..dcab0445a4f73105dde8e52f5a1aa9c6d5a2627a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py @@ -0,0 +1,101 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import _serialization + + +class X448PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> "X448PublicKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return backend.x448_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + return self.public_bytes( + _serialization.Encoding.Raw, _serialization.PublicFormat.Raw + ) + + +class X448PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> "X448PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + return backend.x448_generate_key() + + @classmethod + def from_private_bytes(cls, data: bytes) -> "X448PrivateKey": + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return backend.x448_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> X448PublicKey: + """ + Returns the public key associated with this private key + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + return self.private_bytes( + _serialization.Encoding.Raw, + _serialization.PrivateFormat.Raw, + _serialization.NoEncryption(), + ) + + @abc.abstractmethod + def exchange(self, peer_public_key: X448PublicKey) -> bytes: + """ + Performs a key exchange operation using the provided peer's public key. + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..95f02842ad1a1f9d04035c68a82f6e7a90beaef1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers.base import ( + AEADCipherContext, + AEADDecryptionContext, + AEADEncryptionContext, + Cipher, + CipherContext, +) + +__all__ = [ + "Cipher", + "CipherAlgorithm", + "BlockCipherAlgorithm", + "CipherContext", + "AEADCipherContext", + "AEADDecryptionContext", + "AEADEncryptionContext", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08e3a4b9d51d663f41187425ac65899038bffcd1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..979fdec5901b382dd1ba9a94bf9b57c5f42bd9bc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27d3428b91ac933b03a29056f486b9242e83cb26 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dccb2843a5fa451bc462993f7d6fa5656f30c26f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30d6ec809e288e75d1cd2a34259d454b5d0e7a84 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/aead.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/aead.py new file mode 100644 index 0000000000000000000000000000000000000000..f2e206bbfa5dad1d39d94f9c45aa3fd391108d1f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/aead.py @@ -0,0 +1,377 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import os +import typing + +from cryptography import exceptions, utils +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.backend import backend +from cryptography.hazmat.bindings._rust import FixedPool + + +class ChaCha20Poly1305: + _MAX_SIZE = 2**31 - 1 + + def __init__(self, key: bytes): + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "ChaCha20Poly1305 is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER, + ) + utils._check_byteslike("key", key) + + if len(key) != 32: + raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") + + self._key = key + self._pool = FixedPool(self._create_fn) + + @classmethod + def generate_key(cls) -> bytes: + return os.urandom(32) + + def _create_fn(self): + return aead._aead_create_ctx(backend, self, self._key) + + def encrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**31 - 1 bytes" + ) + + self._check_params(nonce, data, associated_data) + with self._pool.acquire() as ctx: + return aead._encrypt( + backend, self, nonce, data, [associated_data], 16, ctx + ) + + def decrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + with self._pool.acquire() as ctx: + return aead._decrypt( + backend, self, nonce, data, [associated_data], 16, ctx + ) + + def _check_params( + self, + nonce: bytes, + data: bytes, + associated_data: bytes, + ) -> None: + utils._check_byteslike("nonce", nonce) + utils._check_byteslike("data", data) + utils._check_byteslike("associated_data", associated_data) + if len(nonce) != 12: + raise ValueError("Nonce must be 12 bytes") + + +class AESCCM: + _MAX_SIZE = 2**31 - 1 + + def __init__(self, key: bytes, tag_length: int = 16): + utils._check_byteslike("key", key) + if len(key) not in (16, 24, 32): + raise ValueError("AESCCM key must be 128, 192, or 256 bits.") + + self._key = key + if not isinstance(tag_length, int): + raise TypeError("tag_length must be an integer") + + if tag_length not in (4, 6, 8, 10, 12, 14, 16): + raise ValueError("Invalid tag_length") + + self._tag_length = tag_length + + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "AESCCM is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER, + ) + + @classmethod + def generate_key(cls, bit_length: int) -> bytes: + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (128, 192, 256): + raise ValueError("bit_length must be 128, 192, or 256") + + return os.urandom(bit_length // 8) + + def encrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**31 - 1 bytes" + ) + + self._check_params(nonce, data, associated_data) + self._validate_lengths(nonce, len(data)) + return aead._encrypt( + backend, self, nonce, data, [associated_data], self._tag_length + ) + + def decrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt( + backend, self, nonce, data, [associated_data], self._tag_length + ) + + def _validate_lengths(self, nonce: bytes, data_len: int) -> None: + # For information about computing this, see + # https://tools.ietf.org/html/rfc3610#section-2.1 + l_val = 15 - len(nonce) + if 2 ** (8 * l_val) < data_len: + raise ValueError("Data too long for nonce") + + def _check_params( + self, nonce: bytes, data: bytes, associated_data: bytes + ) -> None: + utils._check_byteslike("nonce", nonce) + utils._check_byteslike("data", data) + utils._check_byteslike("associated_data", associated_data) + if not 7 <= len(nonce) <= 13: + raise ValueError("Nonce must be between 7 and 13 bytes") + + +class AESGCM: + _MAX_SIZE = 2**31 - 1 + + def __init__(self, key: bytes): + utils._check_byteslike("key", key) + if len(key) not in (16, 24, 32): + raise ValueError("AESGCM key must be 128, 192, or 256 bits.") + + self._key = key + + @classmethod + def generate_key(cls, bit_length: int) -> bytes: + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (128, 192, 256): + raise ValueError("bit_length must be 128, 192, or 256") + + return os.urandom(bit_length // 8) + + def encrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**31 - 1 bytes" + ) + + self._check_params(nonce, data, associated_data) + return aead._encrypt(backend, self, nonce, data, [associated_data], 16) + + def decrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt(backend, self, nonce, data, [associated_data], 16) + + def _check_params( + self, + nonce: bytes, + data: bytes, + associated_data: bytes, + ) -> None: + utils._check_byteslike("nonce", nonce) + utils._check_byteslike("data", data) + utils._check_byteslike("associated_data", associated_data) + if len(nonce) < 8 or len(nonce) > 128: + raise ValueError("Nonce must be between 8 and 128 bytes") + + +class AESOCB3: + _MAX_SIZE = 2**31 - 1 + + def __init__(self, key: bytes): + utils._check_byteslike("key", key) + if len(key) not in (16, 24, 32): + raise ValueError("AESOCB3 key must be 128, 192, or 256 bits.") + + self._key = key + + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "OCB3 is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER, + ) + + @classmethod + def generate_key(cls, bit_length: int) -> bytes: + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (128, 192, 256): + raise ValueError("bit_length must be 128, 192, or 256") + + return os.urandom(bit_length // 8) + + def encrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**31 - 1 bytes" + ) + + self._check_params(nonce, data, associated_data) + return aead._encrypt(backend, self, nonce, data, [associated_data], 16) + + def decrypt( + self, + nonce: bytes, + data: bytes, + associated_data: typing.Optional[bytes], + ) -> bytes: + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt(backend, self, nonce, data, [associated_data], 16) + + def _check_params( + self, + nonce: bytes, + data: bytes, + associated_data: bytes, + ) -> None: + utils._check_byteslike("nonce", nonce) + utils._check_byteslike("data", data) + utils._check_byteslike("associated_data", associated_data) + if len(nonce) < 12 or len(nonce) > 15: + raise ValueError("Nonce must be between 12 and 15 bytes") + + +class AESSIV: + _MAX_SIZE = 2**31 - 1 + + def __init__(self, key: bytes): + utils._check_byteslike("key", key) + if len(key) not in (32, 48, 64): + raise ValueError("AESSIV key must be 256, 384, or 512 bits.") + + self._key = key + + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "AES-SIV is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER, + ) + + @classmethod + def generate_key(cls, bit_length: int) -> bytes: + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (256, 384, 512): + raise ValueError("bit_length must be 256, 384, or 512") + + return os.urandom(bit_length // 8) + + def encrypt( + self, + data: bytes, + associated_data: typing.Optional[typing.List[bytes]], + ) -> bytes: + if associated_data is None: + associated_data = [] + + self._check_params(data, associated_data) + + if len(data) > self._MAX_SIZE or any( + len(ad) > self._MAX_SIZE for ad in associated_data + ): + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**31 - 1 bytes" + ) + + return aead._encrypt(backend, self, b"", data, associated_data, 16) + + def decrypt( + self, + data: bytes, + associated_data: typing.Optional[typing.List[bytes]], + ) -> bytes: + if associated_data is None: + associated_data = [] + + self._check_params(data, associated_data) + + return aead._decrypt(backend, self, b"", data, associated_data, 16) + + def _check_params( + self, + data: bytes, + associated_data: typing.List[bytes], + ) -> None: + utils._check_byteslike("data", data) + if len(data) == 0: + raise ValueError("data must not be zero length") + + if not isinstance(associated_data, list): + raise TypeError( + "associated_data must be a list of bytes-like objects or None" + ) + for x in associated_data: + utils._check_byteslike("associated_data elements", x) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py new file mode 100644 index 0000000000000000000000000000000000000000..4357c17acab03f9ec9d1603bbe17324c05d11572 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -0,0 +1,227 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography import utils +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) + + +def _verify_key_size(algorithm: CipherAlgorithm, key: bytes) -> bytes: + # Verify that the key is instance of bytes + utils._check_byteslike("key", key) + + # Verify that the key size matches the expected key size + if len(key) * 8 not in algorithm.key_sizes: + raise ValueError( + "Invalid key size ({}) for {}.".format( + len(key) * 8, algorithm.name + ) + ) + return key + + +class AES(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + # 512 added to support AES-256-XTS, which uses 512-bit keys + key_sizes = frozenset([128, 192, 256, 512]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class AES128(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + key_sizes = frozenset([128]) + key_size = 128 + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + +class AES256(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + key_sizes = frozenset([256]) + key_size = 256 + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + +class Camellia(BlockCipherAlgorithm): + name = "camellia" + block_size = 128 + key_sizes = frozenset([128, 192, 256]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class TripleDES(BlockCipherAlgorithm): + name = "3DES" + block_size = 64 + key_sizes = frozenset([64, 128, 192]) + + def __init__(self, key: bytes): + if len(key) == 8: + key += key + key + elif len(key) == 16: + key += key[:8] + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class Blowfish(BlockCipherAlgorithm): + name = "Blowfish" + block_size = 64 + key_sizes = frozenset(range(32, 449, 8)) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +_BlowfishInternal = Blowfish +utils.deprecated( + Blowfish, + __name__, + "Blowfish has been deprecated", + utils.DeprecatedIn37, + name="Blowfish", +) + + +class CAST5(BlockCipherAlgorithm): + name = "CAST5" + block_size = 64 + key_sizes = frozenset(range(40, 129, 8)) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +_CAST5Internal = CAST5 +utils.deprecated( + CAST5, + __name__, + "CAST5 has been deprecated", + utils.DeprecatedIn37, + name="CAST5", +) + + +class ARC4(CipherAlgorithm): + name = "RC4" + key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class IDEA(BlockCipherAlgorithm): + name = "IDEA" + block_size = 64 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +_IDEAInternal = IDEA +utils.deprecated( + IDEA, + __name__, + "IDEA has been deprecated", + utils.DeprecatedIn37, + name="IDEA", +) + + +class SEED(BlockCipherAlgorithm): + name = "SEED" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +_SEEDInternal = SEED +utils.deprecated( + SEED, + __name__, + "SEED has been deprecated", + utils.DeprecatedIn37, + name="SEED", +) + + +class ChaCha20(CipherAlgorithm): + name = "ChaCha20" + key_sizes = frozenset([256]) + + def __init__(self, key: bytes, nonce: bytes): + self.key = _verify_key_size(self, key) + utils._check_byteslike("nonce", nonce) + + if len(nonce) != 16: + raise ValueError("nonce must be 128-bits (16 bytes)") + + self._nonce = nonce + + @property + def nonce(self) -> bytes: + return self._nonce + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class SM4(BlockCipherAlgorithm): + name = "SM4" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py new file mode 100644 index 0000000000000000000000000000000000000000..d80ef3f15d34c4c5c68d3eb02aac2536a5d173a4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py @@ -0,0 +1,268 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography.exceptions import ( + AlreadyFinalized, + AlreadyUpdated, + NotYetFinalized, +) +from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm +from cryptography.hazmat.primitives.ciphers import modes + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.ciphers import ( + _CipherContext as _BackendCipherContext, + ) + + +class CipherContext(metaclass=abc.ABCMeta): + @abc.abstractmethod + def update(self, data: bytes) -> bytes: + """ + Processes the provided bytes through the cipher and returns the results + as bytes. + """ + + @abc.abstractmethod + def update_into(self, data: bytes, buf: bytes) -> int: + """ + Processes the provided bytes and writes the resulting data into the + provided buffer. Returns the number of bytes written. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Returns the results of processing the final block as bytes. + """ + + +class AEADCipherContext(CipherContext, metaclass=abc.ABCMeta): + @abc.abstractmethod + def authenticate_additional_data(self, data: bytes) -> None: + """ + Authenticates the provided bytes. + """ + + +class AEADDecryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): + @abc.abstractmethod + def finalize_with_tag(self, tag: bytes) -> bytes: + """ + Returns the results of processing the final block as bytes and allows + delayed passing of the authentication tag. + """ + + +class AEADEncryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tag(self) -> bytes: + """ + Returns tag bytes. This is only available after encryption is + finalized. + """ + + +Mode = typing.TypeVar( + "Mode", bound=typing.Optional[modes.Mode], covariant=True +) + + +class Cipher(typing.Generic[Mode]): + def __init__( + self, + algorithm: CipherAlgorithm, + mode: Mode, + backend: typing.Any = None, + ) -> None: + if not isinstance(algorithm, CipherAlgorithm): + raise TypeError("Expected interface of CipherAlgorithm.") + + if mode is not None: + # mypy needs this assert to narrow the type from our generic + # type. Maybe it won't some time in the future. + assert isinstance(mode, modes.Mode) + mode.validate_for_algorithm(algorithm) + + self.algorithm = algorithm + self.mode = mode + + @typing.overload + def encryptor( + self: "Cipher[modes.ModeWithAuthenticationTag]", + ) -> AEADEncryptionContext: + ... + + @typing.overload + def encryptor( + self: "_CIPHER_TYPE", + ) -> CipherContext: + ... + + def encryptor(self): + if isinstance(self.mode, modes.ModeWithAuthenticationTag): + if self.mode.tag is not None: + raise ValueError( + "Authentication tag must be None when encrypting." + ) + from cryptography.hazmat.backends.openssl.backend import backend + + ctx = backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx, encrypt=True) + + @typing.overload + def decryptor( + self: "Cipher[modes.ModeWithAuthenticationTag]", + ) -> AEADDecryptionContext: + ... + + @typing.overload + def decryptor( + self: "_CIPHER_TYPE", + ) -> CipherContext: + ... + + def decryptor(self): + from cryptography.hazmat.backends.openssl.backend import backend + + ctx = backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx, encrypt=False) + + def _wrap_ctx( + self, ctx: "_BackendCipherContext", encrypt: bool + ) -> typing.Union[ + AEADEncryptionContext, AEADDecryptionContext, CipherContext + ]: + if isinstance(self.mode, modes.ModeWithAuthenticationTag): + if encrypt: + return _AEADEncryptionContext(ctx) + else: + return _AEADDecryptionContext(ctx) + else: + return _CipherContext(ctx) + + +_CIPHER_TYPE = Cipher[ + typing.Union[ + modes.ModeWithNonce, + modes.ModeWithTweak, + None, + modes.ECB, + modes.ModeWithInitializationVector, + ] +] + + +class _CipherContext(CipherContext): + _ctx: typing.Optional["_BackendCipherContext"] + + def __init__(self, ctx: "_BackendCipherContext") -> None: + self._ctx = ctx + + def update(self, data: bytes) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return self._ctx.update(data) + + def update_into(self, data: bytes, buf: bytes) -> int: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return self._ctx.update_into(data, buf) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize() + self._ctx = None + return data + + +class _AEADCipherContext(AEADCipherContext): + _ctx: typing.Optional["_BackendCipherContext"] + _tag: typing.Optional[bytes] + + def __init__(self, ctx: "_BackendCipherContext") -> None: + self._ctx = ctx + self._bytes_processed = 0 + self._aad_bytes_processed = 0 + self._tag = None + self._updated = False + + def _check_limit(self, data_size: int) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + self._updated = True + self._bytes_processed += data_size + if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES: + raise ValueError( + "{} has a maximum encrypted byte limit of {}".format( + self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES + ) + ) + + def update(self, data: bytes) -> bytes: + self._check_limit(len(data)) + # mypy needs this assert even though _check_limit already checked + assert self._ctx is not None + return self._ctx.update(data) + + def update_into(self, data: bytes, buf: bytes) -> int: + self._check_limit(len(data)) + # mypy needs this assert even though _check_limit already checked + assert self._ctx is not None + return self._ctx.update_into(data, buf) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize() + self._tag = self._ctx.tag + self._ctx = None + return data + + def authenticate_additional_data(self, data: bytes) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + if self._updated: + raise AlreadyUpdated("Update has been called on this context.") + + self._aad_bytes_processed += len(data) + if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES: + raise ValueError( + "{} has a maximum AAD byte limit of {}".format( + self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES + ) + ) + + self._ctx.authenticate_additional_data(data) + + +class _AEADDecryptionContext(_AEADCipherContext, AEADDecryptionContext): + def finalize_with_tag(self, tag: bytes) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize_with_tag(tag) + self._tag = self._ctx.tag + self._ctx = None + return data + + +class _AEADEncryptionContext(_AEADCipherContext, AEADEncryptionContext): + @property + def tag(self) -> bytes: + if self._ctx is not None: + raise NotYetFinalized( + "You must finalize encryption before " "getting the tag." + ) + assert self._tag is not None + return self._tag diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py new file mode 100644 index 0000000000000000000000000000000000000000..1fba397feb7a6486549128c01f8a1e721d03846e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py @@ -0,0 +1,273 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers import algorithms + + +class Mode(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this mode (e.g. "ECB", "CBC"). + """ + + @abc.abstractmethod + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + """ + Checks that all the necessary invariants of this (mode, algorithm) + combination are met. + """ + + +class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def initialization_vector(self) -> bytes: + """ + The value of the initialization vector for this mode as bytes. + """ + + +class ModeWithTweak(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tweak(self) -> bytes: + """ + The value of the tweak for this mode as bytes. + """ + + +class ModeWithNonce(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def nonce(self) -> bytes: + """ + The value of the nonce for this mode as bytes. + """ + + +class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tag(self) -> typing.Optional[bytes]: + """ + The value of the tag supplied to the constructor of this mode. + """ + + +def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None: + if algorithm.key_size > 256 and algorithm.name == "AES": + raise ValueError( + "Only 128, 192, and 256 bit keys are allowed for this AES mode" + ) + + +def _check_iv_length( + self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm +) -> None: + if len(self.initialization_vector) * 8 != algorithm.block_size: + raise ValueError( + "Invalid IV size ({}) for {}.".format( + len(self.initialization_vector), self.name + ) + ) + + +def _check_nonce_length( + nonce: bytes, name: str, algorithm: CipherAlgorithm +) -> None: + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + f"{name} requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + if len(nonce) * 8 != algorithm.block_size: + raise ValueError(f"Invalid nonce size ({len(nonce)}) for {name}.") + + +def _check_iv_and_key_length( + self: ModeWithInitializationVector, algorithm: CipherAlgorithm +) -> None: + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + f"{self} requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + _check_aes_key_length(self, algorithm) + _check_iv_length(self, algorithm) + + +class CBC(ModeWithInitializationVector): + name = "CBC" + + def __init__(self, initialization_vector: bytes): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class XTS(ModeWithTweak): + name = "XTS" + + def __init__(self, tweak: bytes): + utils._check_byteslike("tweak", tweak) + + if len(tweak) != 16: + raise ValueError("tweak must be 128-bits (16 bytes)") + + self._tweak = tweak + + @property + def tweak(self) -> bytes: + return self._tweak + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + if isinstance(algorithm, (algorithms.AES128, algorithms.AES256)): + raise TypeError( + "The AES128 and AES256 classes do not support XTS, please use " + "the standard AES class instead." + ) + + if algorithm.key_size not in (256, 512): + raise ValueError( + "The XTS specification requires a 256-bit key for AES-128-XTS" + " and 512-bit key for AES-256-XTS" + ) + + +class ECB(Mode): + name = "ECB" + + validate_for_algorithm = _check_aes_key_length + + +class OFB(ModeWithInitializationVector): + name = "OFB" + + def __init__(self, initialization_vector: bytes): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class CFB(ModeWithInitializationVector): + name = "CFB" + + def __init__(self, initialization_vector: bytes): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class CFB8(ModeWithInitializationVector): + name = "CFB8" + + def __init__(self, initialization_vector: bytes): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class CTR(ModeWithNonce): + name = "CTR" + + def __init__(self, nonce: bytes): + utils._check_byteslike("nonce", nonce) + self._nonce = nonce + + @property + def nonce(self) -> bytes: + return self._nonce + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + _check_aes_key_length(self, algorithm) + _check_nonce_length(self.nonce, self.name, algorithm) + + +class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): + name = "GCM" + _MAX_ENCRYPTED_BYTES = (2**39 - 256) // 8 + _MAX_AAD_BYTES = (2**64) // 8 + + def __init__( + self, + initialization_vector: bytes, + tag: typing.Optional[bytes] = None, + min_tag_length: int = 16, + ): + # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive + # This is a sane limit anyway so we'll enforce it here. + utils._check_byteslike("initialization_vector", initialization_vector) + if len(initialization_vector) < 8 or len(initialization_vector) > 128: + raise ValueError( + "initialization_vector must be between 8 and 128 bytes (64 " + "and 1024 bits)." + ) + self._initialization_vector = initialization_vector + if tag is not None: + utils._check_bytes("tag", tag) + if min_tag_length < 4: + raise ValueError("min_tag_length must be >= 4") + if len(tag) < min_tag_length: + raise ValueError( + "Authentication tag must be {} bytes or longer.".format( + min_tag_length + ) + ) + self._tag = tag + self._min_tag_length = min_tag_length + + @property + def tag(self) -> typing.Optional[bytes]: + return self._tag + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + _check_aes_key_length(self, algorithm) + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + "GCM requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + block_size_bytes = algorithm.block_size // 8 + if self._tag is not None and len(self._tag) > block_size_bytes: + raise ValueError( + "Authentication tag cannot be more than {} bytes.".format( + block_size_bytes + ) + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/cmac.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/cmac.py new file mode 100644 index 0000000000000000000000000000000000000000..00c4bd11d8774088e9b14f47a8d9b8986dff3a3c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/cmac.py @@ -0,0 +1,64 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized +from cryptography.hazmat.primitives import ciphers + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.cmac import _CMACContext + + +class CMAC: + _ctx: typing.Optional["_CMACContext"] + _algorithm: ciphers.BlockCipherAlgorithm + + def __init__( + self, + algorithm: ciphers.BlockCipherAlgorithm, + backend: typing.Any = None, + ctx: typing.Optional["_CMACContext"] = None, + ) -> None: + if not isinstance(algorithm, ciphers.BlockCipherAlgorithm): + raise TypeError("Expected instance of BlockCipherAlgorithm.") + self._algorithm = algorithm + + if ctx is None: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + self._ctx = ossl.create_cmac_ctx(self._algorithm) + else: + self._ctx = ctx + + def update(self, data: bytes) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + utils._check_bytes("data", data) + self._ctx.update(data) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + def verify(self, signature: bytes) -> None: + utils._check_bytes("signature", signature) + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + ctx, self._ctx = self._ctx, None + ctx.verify(signature) + + def copy(self) -> "CMAC": + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return CMAC(self._algorithm, ctx=self._ctx.copy()) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/constant_time.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/constant_time.py new file mode 100644 index 0000000000000000000000000000000000000000..a02fa9c4534544e046cca53be3baca8b4a3992f3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/constant_time.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import hmac + + +def bytes_eq(a: bytes, b: bytes) -> bool: + if not isinstance(a, bytes) or not isinstance(b, bytes): + raise TypeError("a and b must be bytes.") + + return hmac.compare_digest(a, b) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py new file mode 100644 index 0000000000000000000000000000000000000000..6bbab4c0b92aa6512b311d585cab057bcb5bda89 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py @@ -0,0 +1,259 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import abc +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized + + +class HashAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this algorithm (e.g. "sha256", "md5"). + """ + + @property + @abc.abstractmethod + def digest_size(self) -> int: + """ + The size of the resulting digest in bytes. + """ + + @property + @abc.abstractmethod + def block_size(self) -> typing.Optional[int]: + """ + The internal block size of the hash function, or None if the hash + function does not use blocks internally (e.g. SHA3). + """ + + +class HashContext(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def algorithm(self) -> HashAlgorithm: + """ + A HashAlgorithm that will be used by this context. + """ + + @abc.abstractmethod + def update(self, data: bytes) -> None: + """ + Processes the provided bytes through the hash. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Finalizes the hash context and returns the hash digest as bytes. + """ + + @abc.abstractmethod + def copy(self) -> "HashContext": + """ + Return a HashContext that is a copy of the current context. + """ + + +class ExtendableOutputFunction(metaclass=abc.ABCMeta): + """ + An interface for extendable output functions. + """ + + +class Hash(HashContext): + _ctx: typing.Optional[HashContext] + + def __init__( + self, + algorithm: HashAlgorithm, + backend: typing.Any = None, + ctx: typing.Optional["HashContext"] = None, + ) -> None: + if not isinstance(algorithm, HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + self._algorithm = algorithm + + if ctx is None: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + self._ctx = ossl.create_hash_ctx(self.algorithm) + else: + self._ctx = ctx + + @property + def algorithm(self) -> HashAlgorithm: + return self._algorithm + + def update(self, data: bytes) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + utils._check_byteslike("data", data) + self._ctx.update(data) + + def copy(self) -> "Hash": + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return Hash(self.algorithm, ctx=self._ctx.copy()) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + +class SHA1(HashAlgorithm): + name = "sha1" + digest_size = 20 + block_size = 64 + + +class SHA512_224(HashAlgorithm): # noqa: N801 + name = "sha512-224" + digest_size = 28 + block_size = 128 + + +class SHA512_256(HashAlgorithm): # noqa: N801 + name = "sha512-256" + digest_size = 32 + block_size = 128 + + +class SHA224(HashAlgorithm): + name = "sha224" + digest_size = 28 + block_size = 64 + + +class SHA256(HashAlgorithm): + name = "sha256" + digest_size = 32 + block_size = 64 + + +class SHA384(HashAlgorithm): + name = "sha384" + digest_size = 48 + block_size = 128 + + +class SHA512(HashAlgorithm): + name = "sha512" + digest_size = 64 + block_size = 128 + + +class SHA3_224(HashAlgorithm): # noqa: N801 + name = "sha3-224" + digest_size = 28 + block_size = None + + +class SHA3_256(HashAlgorithm): # noqa: N801 + name = "sha3-256" + digest_size = 32 + block_size = None + + +class SHA3_384(HashAlgorithm): # noqa: N801 + name = "sha3-384" + digest_size = 48 + block_size = None + + +class SHA3_512(HashAlgorithm): # noqa: N801 + name = "sha3-512" + digest_size = 64 + block_size = None + + +class SHAKE128(HashAlgorithm, ExtendableOutputFunction): + name = "shake128" + block_size = None + + def __init__(self, digest_size: int): + if not isinstance(digest_size, int): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class SHAKE256(HashAlgorithm, ExtendableOutputFunction): + name = "shake256" + block_size = None + + def __init__(self, digest_size: int): + if not isinstance(digest_size, int): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class MD5(HashAlgorithm): + name = "md5" + digest_size = 16 + block_size = 64 + + +class BLAKE2b(HashAlgorithm): + name = "blake2b" + _max_digest_size = 64 + _min_digest_size = 1 + block_size = 128 + + def __init__(self, digest_size: int): + if digest_size != 64: + raise ValueError("Digest size must be 64") + + self._digest_size = digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class BLAKE2s(HashAlgorithm): + name = "blake2s" + block_size = 64 + _max_digest_size = 32 + _min_digest_size = 1 + + def __init__(self, digest_size: int): + if digest_size != 32: + raise ValueError("Digest size must be 32") + + self._digest_size = digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class SM3(HashAlgorithm): + name = "sm3" + digest_size = 32 + block_size = 64 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hmac.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hmac.py new file mode 100644 index 0000000000000000000000000000000000000000..8f1c0eae6e1f7918dbe8ebe54d41614973cd8cbc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/hmac.py @@ -0,0 +1,70 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized +from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.primitives import hashes + + +class HMAC(hashes.HashContext): + _ctx: typing.Optional[_HMACContext] + + def __init__( + self, + key: bytes, + algorithm: hashes.HashAlgorithm, + backend: typing.Any = None, + ctx=None, + ): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + self._algorithm = algorithm + + self._key = key + if ctx is None: + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + self._ctx = ossl.create_hmac_ctx(key, self.algorithm) + else: + self._ctx = ctx + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + def update(self, data: bytes) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + utils._check_byteslike("data", data) + self._ctx.update(data) + + def copy(self) -> "HMAC": + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return HMAC( + self._key, + self.algorithm, + ctx=self._ctx.copy(), + ) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + def verify(self, signature: bytes) -> None: + utils._check_bytes("signature", signature) + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + ctx, self._ctx = self._ctx, None + ctx.verify(signature) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..38e2f8bc4d66ea4226daff5380e21fd3a5d7c8bf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__init__.py @@ -0,0 +1,22 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc + + +class KeyDerivationFunction(metaclass=abc.ABCMeta): + @abc.abstractmethod + def derive(self, key_material: bytes) -> bytes: + """ + Deterministically generates and returns a new key based on the existing + key material. + """ + + @abc.abstractmethod + def verify(self, key_material: bytes, expected_key: bytes) -> None: + """ + Checks whether the key generated by the key material matches the + expected derived key. Raises an exception if they do not match. + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1775247d1700a37ee8f2c0d2e19162988bbe3a0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80115ef529d84b6596b80061a5336ac50bf2afe7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbd296617a8a555d8804dd49e96490b90e7b69ac Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8245d4395dbef90260c6154b624ff7b7e5a1630f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..deff654789b4f91f9016eb247c7853d5a221b3d6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61fe95abdb21700a1962bc35f88e974cf2d88f5c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0a58038890a3e84bdaa19fc052037bd7a4e357e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py new file mode 100644 index 0000000000000000000000000000000000000000..7bbce4ffcdbc5c5eee2adf126ef71d46ba3a4727 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -0,0 +1,123 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized, InvalidKey +from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +def _int_to_u32be(n: int) -> bytes: + return n.to_bytes(length=4, byteorder="big") + + +def _common_args_checks( + algorithm: hashes.HashAlgorithm, + length: int, + otherinfo: typing.Optional[bytes], +) -> None: + max_length = algorithm.digest_size * (2**32 - 1) + if length > max_length: + raise ValueError(f"Cannot derive keys larger than {max_length} bits.") + if otherinfo is not None: + utils._check_bytes("otherinfo", otherinfo) + + +def _concatkdf_derive( + key_material: bytes, + length: int, + auxfn: typing.Callable[[], hashes.HashContext], + otherinfo: bytes, +) -> bytes: + utils._check_byteslike("key_material", key_material) + output = [b""] + outlen = 0 + counter = 1 + + while length > outlen: + h = auxfn() + h.update(_int_to_u32be(counter)) + h.update(key_material) + h.update(otherinfo) + output.append(h.finalize()) + outlen += len(output[-1]) + counter += 1 + + return b"".join(output)[:length] + + +class ConcatKDFHash(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + otherinfo: typing.Optional[bytes], + backend: typing.Any = None, + ): + _common_args_checks(algorithm, length, otherinfo) + self._algorithm = algorithm + self._length = length + self._otherinfo: bytes = otherinfo if otherinfo is not None else b"" + + self._used = False + + def _hash(self) -> hashes.Hash: + return hashes.Hash(self._algorithm) + + def derive(self, key_material: bytes) -> bytes: + if self._used: + raise AlreadyFinalized + self._used = True + return _concatkdf_derive( + key_material, self._length, self._hash, self._otherinfo + ) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +class ConcatKDFHMAC(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + salt: typing.Optional[bytes], + otherinfo: typing.Optional[bytes], + backend: typing.Any = None, + ): + _common_args_checks(algorithm, length, otherinfo) + self._algorithm = algorithm + self._length = length + self._otherinfo: bytes = otherinfo if otherinfo is not None else b"" + + if algorithm.block_size is None: + raise TypeError(f"{algorithm.name} is unsupported for ConcatKDF") + + if salt is None: + salt = b"\x00" * algorithm.block_size + else: + utils._check_bytes("salt", salt) + + self._salt = salt + + self._used = False + + def _hmac(self) -> hmac.HMAC: + return hmac.HMAC(self._salt, self._algorithm) + + def derive(self, key_material: bytes) -> bytes: + if self._used: + raise AlreadyFinalized + self._used = True + return _concatkdf_derive( + key_material, self._length, self._hmac, self._otherinfo + ) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py new file mode 100644 index 0000000000000000000000000000000000000000..7d59a7ef77b9e6a88b530023a2690b9061dcb6cf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py @@ -0,0 +1,100 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized, InvalidKey +from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +class HKDF(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + salt: typing.Optional[bytes], + info: typing.Optional[bytes], + backend: typing.Any = None, + ): + self._algorithm = algorithm + + if salt is None: + salt = b"\x00" * self._algorithm.digest_size + else: + utils._check_bytes("salt", salt) + + self._salt = salt + + self._hkdf_expand = HKDFExpand(self._algorithm, length, info) + + def _extract(self, key_material: bytes) -> bytes: + h = hmac.HMAC(self._salt, self._algorithm) + h.update(key_material) + return h.finalize() + + def derive(self, key_material: bytes) -> bytes: + utils._check_byteslike("key_material", key_material) + return self._hkdf_expand.derive(self._extract(key_material)) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +class HKDFExpand(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + info: typing.Optional[bytes], + backend: typing.Any = None, + ): + self._algorithm = algorithm + + max_length = 255 * algorithm.digest_size + + if length > max_length: + raise ValueError( + f"Cannot derive keys larger than {max_length} octets." + ) + + self._length = length + + if info is None: + info = b"" + else: + utils._check_bytes("info", info) + + self._info = info + + self._used = False + + def _expand(self, key_material: bytes) -> bytes: + output = [b""] + counter = 1 + + while self._algorithm.digest_size * (len(output) - 1) < self._length: + h = hmac.HMAC(key_material, self._algorithm) + h.update(output[-1]) + h.update(self._info) + h.update(bytes([counter])) + output.append(h.finalize()) + counter += 1 + + return b"".join(output)[: self._length] + + def derive(self, key_material: bytes) -> bytes: + utils._check_byteslike("key_material", key_material) + if self._used: + raise AlreadyFinalized + + self._used = True + return self._expand(key_material) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py new file mode 100644 index 0000000000000000000000000000000000000000..7f185a9af8d1925aeae56ca9b9739fd500037adf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -0,0 +1,297 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import ( + ciphers, + cmac, + constant_time, + hashes, + hmac, +) +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +class Mode(utils.Enum): + CounterMode = "ctr" + + +class CounterLocation(utils.Enum): + BeforeFixed = "before_fixed" + AfterFixed = "after_fixed" + MiddleFixed = "middle_fixed" + + +class _KBKDFDeriver: + def __init__( + self, + prf: typing.Callable, + mode: Mode, + length: int, + rlen: int, + llen: typing.Optional[int], + location: CounterLocation, + break_location: typing.Optional[int], + label: typing.Optional[bytes], + context: typing.Optional[bytes], + fixed: typing.Optional[bytes], + ): + assert callable(prf) + + if not isinstance(mode, Mode): + raise TypeError("mode must be of type Mode") + + if not isinstance(location, CounterLocation): + raise TypeError("location must be of type CounterLocation") + + if break_location is None and location is CounterLocation.MiddleFixed: + raise ValueError("Please specify a break_location") + + if ( + break_location is not None + and location != CounterLocation.MiddleFixed + ): + raise ValueError( + "break_location is ignored when location is not" + " CounterLocation.MiddleFixed" + ) + + if break_location is not None and not isinstance(break_location, int): + raise TypeError("break_location must be an integer") + + if break_location is not None and break_location < 0: + raise ValueError("break_location must be a positive integer") + + if (label or context) and fixed: + raise ValueError( + "When supplying fixed data, " "label and context are ignored." + ) + + if rlen is None or not self._valid_byte_length(rlen): + raise ValueError("rlen must be between 1 and 4") + + if llen is None and fixed is None: + raise ValueError("Please specify an llen") + + if llen is not None and not isinstance(llen, int): + raise TypeError("llen must be an integer") + + if label is None: + label = b"" + + if context is None: + context = b"" + + utils._check_bytes("label", label) + utils._check_bytes("context", context) + self._prf = prf + self._mode = mode + self._length = length + self._rlen = rlen + self._llen = llen + self._location = location + self._break_location = break_location + self._label = label + self._context = context + self._used = False + self._fixed_data = fixed + + @staticmethod + def _valid_byte_length(value: int) -> bool: + if not isinstance(value, int): + raise TypeError("value must be of type int") + + value_bin = utils.int_to_bytes(1, value) + if not 1 <= len(value_bin) <= 4: + return False + return True + + def derive(self, key_material: bytes, prf_output_size: int) -> bytes: + if self._used: + raise AlreadyFinalized + + utils._check_byteslike("key_material", key_material) + self._used = True + + # inverse floor division (equivalent to ceiling) + rounds = -(-self._length // prf_output_size) + + output = [b""] + + # For counter mode, the number of iterations shall not be + # larger than 2^r-1, where r <= 32 is the binary length of the counter + # This ensures that the counter values used as an input to the + # PRF will not repeat during a particular call to the KDF function. + r_bin = utils.int_to_bytes(1, self._rlen) + if rounds > pow(2, len(r_bin) * 8) - 1: + raise ValueError("There are too many iterations.") + + fixed = self._generate_fixed_input() + + if self._location == CounterLocation.BeforeFixed: + data_before_ctr = b"" + data_after_ctr = fixed + elif self._location == CounterLocation.AfterFixed: + data_before_ctr = fixed + data_after_ctr = b"" + else: + if isinstance( + self._break_location, int + ) and self._break_location > len(fixed): + raise ValueError("break_location offset > len(fixed)") + data_before_ctr = fixed[: self._break_location] + data_after_ctr = fixed[self._break_location :] + + for i in range(1, rounds + 1): + h = self._prf(key_material) + + counter = utils.int_to_bytes(i, self._rlen) + input_data = data_before_ctr + counter + data_after_ctr + + h.update(input_data) + + output.append(h.finalize()) + + return b"".join(output)[: self._length] + + def _generate_fixed_input(self) -> bytes: + if self._fixed_data and isinstance(self._fixed_data, bytes): + return self._fixed_data + + l_val = utils.int_to_bytes(self._length * 8, self._llen) + + return b"".join([self._label, b"\x00", self._context, l_val]) + + +class KBKDFHMAC(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + mode: Mode, + length: int, + rlen: int, + llen: typing.Optional[int], + location: CounterLocation, + label: typing.Optional[bytes], + context: typing.Optional[bytes], + fixed: typing.Optional[bytes], + backend: typing.Any = None, + *, + break_location: typing.Optional[int] = None, + ): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hash algorithm.", + _Reasons.UNSUPPORTED_HASH, + ) + + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + if not ossl.hmac_supported(algorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hmac algorithm.", + _Reasons.UNSUPPORTED_HASH, + ) + + self._algorithm = algorithm + + self._deriver = _KBKDFDeriver( + self._prf, + mode, + length, + rlen, + llen, + location, + break_location, + label, + context, + fixed, + ) + + def _prf(self, key_material: bytes) -> hmac.HMAC: + return hmac.HMAC(key_material, self._algorithm) + + def derive(self, key_material: bytes) -> bytes: + return self._deriver.derive(key_material, self._algorithm.digest_size) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +class KBKDFCMAC(KeyDerivationFunction): + def __init__( + self, + algorithm, + mode: Mode, + length: int, + rlen: int, + llen: typing.Optional[int], + location: CounterLocation, + label: typing.Optional[bytes], + context: typing.Optional[bytes], + fixed: typing.Optional[bytes], + backend: typing.Any = None, + *, + break_location: typing.Optional[int] = None, + ): + if not issubclass( + algorithm, ciphers.BlockCipherAlgorithm + ) or not issubclass(algorithm, ciphers.CipherAlgorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported cipher algorithm.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + self._algorithm = algorithm + self._cipher: typing.Optional[ciphers.BlockCipherAlgorithm] = None + + self._deriver = _KBKDFDeriver( + self._prf, + mode, + length, + rlen, + llen, + location, + break_location, + label, + context, + fixed, + ) + + def _prf(self, _: bytes) -> cmac.CMAC: + assert self._cipher is not None + + return cmac.CMAC(self._cipher) + + def derive(self, key_material: bytes) -> bytes: + self._cipher = self._algorithm(key_material) + + assert self._cipher is not None + + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + if not ossl.cmac_algorithm_supported(self._cipher): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported cipher algorithm.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + return self._deriver.derive(key_material, self._cipher.block_size // 8) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py new file mode 100644 index 0000000000000000000000000000000000000000..8d23f8c250d19988f8d0332540623e3b57bc0247 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -0,0 +1,65 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time, hashes +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +class PBKDF2HMAC(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + salt: bytes, + iterations: int, + backend: typing.Any = None, + ): + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + if not ossl.pbkdf2_hmac_supported(algorithm): + raise UnsupportedAlgorithm( + "{} is not supported for PBKDF2 by this backend.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + self._used = False + self._algorithm = algorithm + self._length = length + utils._check_bytes("salt", salt) + self._salt = salt + self._iterations = iterations + + def derive(self, key_material: bytes) -> bytes: + if self._used: + raise AlreadyFinalized("PBKDF2 instances can only be used once.") + self._used = True + + utils._check_byteslike("key_material", key_material) + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.derive_pbkdf2_hmac( + self._algorithm, + self._length, + self._salt, + self._iterations, + key_material, + ) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + derived_key = self.derive(key_material) + if not constant_time.bytes_eq(derived_key, expected_key): + raise InvalidKey("Keys do not match.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py new file mode 100644 index 0000000000000000000000000000000000000000..286f4388cb2aa9105a395a2b12d88e0ae233a434 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py @@ -0,0 +1,73 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import sys +import typing + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, +) +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +# This is used by the scrypt tests to skip tests that require more memory +# than the MEM_LIMIT +_MEM_LIMIT = sys.maxsize // 2 + + +class Scrypt(KeyDerivationFunction): + def __init__( + self, + salt: bytes, + length: int, + n: int, + r: int, + p: int, + backend: typing.Any = None, + ): + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + if not ossl.scrypt_supported(): + raise UnsupportedAlgorithm( + "This version of OpenSSL does not support scrypt" + ) + self._length = length + utils._check_bytes("salt", salt) + if n < 2 or (n & (n - 1)) != 0: + raise ValueError("n must be greater than 1 and be a power of 2.") + + if r < 1: + raise ValueError("r must be greater than or equal to 1.") + + if p < 1: + raise ValueError("p must be greater than or equal to 1.") + + self._used = False + self._salt = salt + self._n = n + self._r = r + self._p = p + + def derive(self, key_material: bytes) -> bytes: + if self._used: + raise AlreadyFinalized("Scrypt instances can only be used once.") + self._used = True + + utils._check_byteslike("key_material", key_material) + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.derive_scrypt( + key_material, self._salt, self._length, self._n, self._r, self._p + ) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + derived_key = self.derive(key_material) + if not constant_time.bytes_eq(derived_key, expected_key): + raise InvalidKey("Keys do not match.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py new file mode 100644 index 0000000000000000000000000000000000000000..4ab64d08b1c55b8e9cd4b7c3210b15b5d959249f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -0,0 +1,60 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized, InvalidKey +from cryptography.hazmat.primitives import constant_time, hashes +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +def _int_to_u32be(n: int) -> bytes: + return n.to_bytes(length=4, byteorder="big") + + +class X963KDF(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + length: int, + sharedinfo: typing.Optional[bytes], + backend: typing.Any = None, + ): + max_len = algorithm.digest_size * (2**32 - 1) + if length > max_len: + raise ValueError(f"Cannot derive keys larger than {max_len} bits.") + if sharedinfo is not None: + utils._check_bytes("sharedinfo", sharedinfo) + + self._algorithm = algorithm + self._length = length + self._sharedinfo = sharedinfo + self._used = False + + def derive(self, key_material: bytes) -> bytes: + if self._used: + raise AlreadyFinalized + self._used = True + utils._check_byteslike("key_material", key_material) + output = [b""] + outlen = 0 + counter = 1 + + while self._length > outlen: + h = hashes.Hash(self._algorithm) + h.update(key_material) + h.update(_int_to_u32be(counter)) + if self._sharedinfo is not None: + h.update(self._sharedinfo) + output.append(h.finalize()) + outlen += len(output[-1]) + counter += 1 + + return b"".join(output)[: self._length] + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/keywrap.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/keywrap.py new file mode 100644 index 0000000000000000000000000000000000000000..64771ca3c5b0b51cdb91525fe9f5c82482db7672 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/keywrap.py @@ -0,0 +1,176 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.modes import ECB +from cryptography.hazmat.primitives.constant_time import bytes_eq + + +def _wrap_core( + wrapping_key: bytes, + a: bytes, + r: typing.List[bytes], +) -> bytes: + # RFC 3394 Key Wrap - 2.2.1 (index method) + encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() + n = len(r) + for j in range(6): + for i in range(n): + # every encryption operation is a discrete 16 byte chunk (because + # AES has a 128-bit block size) and since we're using ECB it is + # safe to reuse the encryptor for the entire operation + b = encryptor.update(a + r[i]) + a = ( + int.from_bytes(b[:8], byteorder="big") ^ ((n * j) + i + 1) + ).to_bytes(length=8, byteorder="big") + r[i] = b[-8:] + + assert encryptor.finalize() == b"" + + return a + b"".join(r) + + +def aes_key_wrap( + wrapping_key: bytes, + key_to_wrap: bytes, + backend: typing.Any = None, +) -> bytes: + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + if len(key_to_wrap) < 16: + raise ValueError("The key to wrap must be at least 16 bytes") + + if len(key_to_wrap) % 8 != 0: + raise ValueError("The key to wrap must be a multiple of 8 bytes") + + a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" + r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] + return _wrap_core(wrapping_key, a, r) + + +def _unwrap_core( + wrapping_key: bytes, + a: bytes, + r: typing.List[bytes], +) -> typing.Tuple[bytes, typing.List[bytes]]: + # Implement RFC 3394 Key Unwrap - 2.2.2 (index method) + decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() + n = len(r) + for j in reversed(range(6)): + for i in reversed(range(n)): + atr = ( + int.from_bytes(a, byteorder="big") ^ ((n * j) + i + 1) + ).to_bytes(length=8, byteorder="big") + r[i] + # every decryption operation is a discrete 16 byte chunk so + # it is safe to reuse the decryptor for the entire operation + b = decryptor.update(atr) + a = b[:8] + r[i] = b[-8:] + + assert decryptor.finalize() == b"" + return a, r + + +def aes_key_wrap_with_padding( + wrapping_key: bytes, + key_to_wrap: bytes, + backend: typing.Any = None, +) -> bytes: + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + aiv = b"\xA6\x59\x59\xA6" + len(key_to_wrap).to_bytes( + length=4, byteorder="big" + ) + # pad the key to wrap if necessary + pad = (8 - (len(key_to_wrap) % 8)) % 8 + key_to_wrap = key_to_wrap + b"\x00" * pad + if len(key_to_wrap) == 8: + # RFC 5649 - 4.1 - exactly 8 octets after padding + encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() + b = encryptor.update(aiv + key_to_wrap) + assert encryptor.finalize() == b"" + return b + else: + r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] + return _wrap_core(wrapping_key, aiv, r) + + +def aes_key_unwrap_with_padding( + wrapping_key: bytes, + wrapped_key: bytes, + backend: typing.Any = None, +) -> bytes: + if len(wrapped_key) < 16: + raise InvalidUnwrap("Must be at least 16 bytes") + + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + if len(wrapped_key) == 16: + # RFC 5649 - 4.2 - exactly two 64-bit blocks + decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() + out = decryptor.update(wrapped_key) + assert decryptor.finalize() == b"" + a = out[:8] + data = out[8:] + n = 1 + else: + r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] + encrypted_aiv = r.pop(0) + n = len(r) + a, r = _unwrap_core(wrapping_key, encrypted_aiv, r) + data = b"".join(r) + + # 1) Check that MSB(32,A) = A65959A6. + # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let + # MLI = LSB(32,A). + # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of + # the output data are zero. + mli = int.from_bytes(a[4:], byteorder="big") + b = (8 * n) - mli + if ( + not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") + or not 8 * (n - 1) < mli <= 8 * n + or (b != 0 and not bytes_eq(data[-b:], b"\x00" * b)) + ): + raise InvalidUnwrap() + + if b == 0: + return data + else: + return data[:-b] + + +def aes_key_unwrap( + wrapping_key: bytes, + wrapped_key: bytes, + backend: typing.Any = None, +) -> bytes: + if len(wrapped_key) < 24: + raise InvalidUnwrap("Must be at least 24 bytes") + + if len(wrapped_key) % 8 != 0: + raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes") + + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" + r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] + a = r.pop(0) + a, r = _unwrap_core(wrapping_key, a, r) + if not bytes_eq(a, aiv): + raise InvalidUnwrap() + + return b"".join(r) + + +class InvalidUnwrap(Exception): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py new file mode 100644 index 0000000000000000000000000000000000000000..d6c1d91528202c23bc14ea921b3094e35845ee62 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py @@ -0,0 +1,224 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import typing + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized +from cryptography.hazmat.bindings._rust import ( + check_ansix923_padding, + check_pkcs7_padding, +) + + +class PaddingContext(metaclass=abc.ABCMeta): + @abc.abstractmethod + def update(self, data: bytes) -> bytes: + """ + Pads the provided bytes and returns any available data as bytes. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Finalize the padding, returns bytes. + """ + + +def _byte_padding_check(block_size: int) -> None: + if not (0 <= block_size <= 2040): + raise ValueError("block_size must be in range(0, 2041).") + + if block_size % 8 != 0: + raise ValueError("block_size must be a multiple of 8.") + + +def _byte_padding_update( + buffer_: typing.Optional[bytes], data: bytes, block_size: int +) -> typing.Tuple[bytes, bytes]: + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + utils._check_byteslike("data", data) + + buffer_ += bytes(data) + + finished_blocks = len(buffer_) // (block_size // 8) + + result = buffer_[: finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8) :] + + return buffer_, result + + +def _byte_padding_pad( + buffer_: typing.Optional[bytes], + block_size: int, + paddingfn: typing.Callable[[int], bytes], +) -> bytes: + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + pad_size = block_size // 8 - len(buffer_) + return buffer_ + paddingfn(pad_size) + + +def _byte_unpadding_update( + buffer_: typing.Optional[bytes], data: bytes, block_size: int +) -> typing.Tuple[bytes, bytes]: + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + utils._check_byteslike("data", data) + + buffer_ += bytes(data) + + finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) + + result = buffer_[: finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8) :] + + return buffer_, result + + +def _byte_unpadding_check( + buffer_: typing.Optional[bytes], + block_size: int, + checkfn: typing.Callable[[bytes], int], +) -> bytes: + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + if len(buffer_) != block_size // 8: + raise ValueError("Invalid padding bytes.") + + valid = checkfn(buffer_) + + if not valid: + raise ValueError("Invalid padding bytes.") + + pad_size = buffer_[-1] + return buffer_[:-pad_size] + + +class PKCS7: + def __init__(self, block_size: int): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self) -> PaddingContext: + return _PKCS7PaddingContext(self.block_size) + + def unpadder(self) -> PaddingContext: + return _PKCS7UnpaddingContext(self.block_size) + + +class _PKCS7PaddingContext(PaddingContext): + _buffer: typing.Optional[bytes] + + def __init__(self, block_size: int): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data: bytes) -> bytes: + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size + ) + return result + + def _padding(self, size: int) -> bytes: + return bytes([size]) * size + + def finalize(self) -> bytes: + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding + ) + self._buffer = None + return result + + +class _PKCS7UnpaddingContext(PaddingContext): + _buffer: typing.Optional[bytes] + + def __init__(self, block_size: int): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data: bytes) -> bytes: + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size + ) + return result + + def finalize(self) -> bytes: + result = _byte_unpadding_check( + self._buffer, self.block_size, check_pkcs7_padding + ) + self._buffer = None + return result + + +class ANSIX923: + def __init__(self, block_size: int): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self) -> PaddingContext: + return _ANSIX923PaddingContext(self.block_size) + + def unpadder(self) -> PaddingContext: + return _ANSIX923UnpaddingContext(self.block_size) + + +class _ANSIX923PaddingContext(PaddingContext): + _buffer: typing.Optional[bytes] + + def __init__(self, block_size: int): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data: bytes) -> bytes: + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size + ) + return result + + def _padding(self, size: int) -> bytes: + return bytes([0]) * (size - 1) + bytes([size]) + + def finalize(self) -> bytes: + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding + ) + self._buffer = None + return result + + +class _ANSIX923UnpaddingContext(PaddingContext): + _buffer: typing.Optional[bytes] + + def __init__(self, block_size: int): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data: bytes) -> bytes: + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size + ) + return result + + def finalize(self) -> bytes: + result = _byte_unpadding_check( + self._buffer, + self.block_size, + check_ansix923_padding, + ) + self._buffer = None + return result diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/poly1305.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/poly1305.py new file mode 100644 index 0000000000000000000000000000000000000000..7fcf4a50f5752a0c12629fae32e7fb7b4b0b2445 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/poly1305.py @@ -0,0 +1,60 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.poly1305 import _Poly1305Context + + +class Poly1305: + _ctx: typing.Optional[_Poly1305Context] + + def __init__(self, key: bytes): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.poly1305_supported(): + raise UnsupportedAlgorithm( + "poly1305 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_MAC, + ) + self._ctx = backend.create_poly1305_ctx(key) + + def update(self, data: bytes) -> None: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + utils._check_byteslike("data", data) + self._ctx.update(data) + + def finalize(self) -> bytes: + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + mac = self._ctx.finalize() + self._ctx = None + return mac + + def verify(self, tag: bytes) -> None: + utils._check_bytes("tag", tag) + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + ctx, self._ctx = self._ctx, None + ctx.verify(tag) + + @classmethod + def generate_tag(cls, key: bytes, data: bytes) -> bytes: + p = Poly1305(key) + p.update(data) + return p.finalize() + + @classmethod + def verify_tag(cls, key: bytes, data: bytes, tag: bytes) -> None: + p = Poly1305(key) + p.update(data) + p.verify(tag) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..213c49958a74facf1644c0861c721537dc9025f0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py @@ -0,0 +1,62 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.hazmat.primitives._serialization import ( + BestAvailableEncryption, + Encoding, + KeySerializationEncryption, + NoEncryption, + ParameterFormat, + PrivateFormat, + PublicFormat, + _KeySerializationEncryption, +) +from cryptography.hazmat.primitives.serialization.base import ( + load_der_parameters, + load_der_private_key, + load_der_public_key, + load_pem_parameters, + load_pem_private_key, + load_pem_public_key, +) +from cryptography.hazmat.primitives.serialization.ssh import ( + SSHCertificate, + SSHCertificateBuilder, + SSHCertificateType, + SSHCertPrivateKeyTypes, + SSHCertPublicKeyTypes, + SSHPrivateKeyTypes, + SSHPublicKeyTypes, + load_ssh_private_key, + load_ssh_public_identity, + load_ssh_public_key, +) + +__all__ = [ + "load_der_parameters", + "load_der_private_key", + "load_der_public_key", + "load_pem_parameters", + "load_pem_private_key", + "load_pem_public_key", + "load_ssh_private_key", + "load_ssh_public_identity", + "load_ssh_public_key", + "Encoding", + "PrivateFormat", + "PublicFormat", + "ParameterFormat", + "KeySerializationEncryption", + "BestAvailableEncryption", + "NoEncryption", + "_KeySerializationEncryption", + "SSHCertificateBuilder", + "SSHCertificate", + "SSHCertificateType", + "SSHCertPublicKeyTypes", + "SSHCertPrivateKeyTypes", + "SSHPrivateKeyTypes", + "SSHPublicKeyTypes", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58f55f96d07a91391c157d345a1bfd37d6afa75c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..768a4997e0eaa2a349a8ae6b7fad04c92408d87a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e821c310773e27222a019c2c0d7e4bf5e5c2f664 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff0f42e110989797821a4beaa16398d98c7ac1f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6944e81d1ace87f0251f95f66e5769aa0b66b58 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/base.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/base.py new file mode 100644 index 0000000000000000000000000000000000000000..7956ce0feb3fd69781b4acea9652b3fd46d06d3a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/base.py @@ -0,0 +1,72 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography.hazmat.primitives.asymmetric import dh +from cryptography.hazmat.primitives.asymmetric.types import ( + PrivateKeyTypes, + PublicKeyTypes, +) + + +def load_pem_private_key( + data: bytes, + password: typing.Optional[bytes], + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, +) -> PrivateKeyTypes: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_pem_private_key( + data, password, unsafe_skip_rsa_key_validation + ) + + +def load_pem_public_key( + data: bytes, backend: typing.Any = None +) -> PublicKeyTypes: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_pem_public_key(data) + + +def load_pem_parameters( + data: bytes, backend: typing.Any = None +) -> "dh.DHParameters": + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_pem_parameters(data) + + +def load_der_private_key( + data: bytes, + password: typing.Optional[bytes], + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, +) -> PrivateKeyTypes: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_der_private_key( + data, password, unsafe_skip_rsa_key_validation + ) + + +def load_der_public_key( + data: bytes, backend: typing.Any = None +) -> PublicKeyTypes: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_der_public_key(data) + + +def load_der_parameters( + data: bytes, backend: typing.Any = None +) -> "dh.DHParameters": + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_der_parameters(data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py new file mode 100644 index 0000000000000000000000000000000000000000..1d36146a97e494a6c84fd4a6bff01b9924571637 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -0,0 +1,227 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives._serialization import PBES as PBES +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed448, + ed25519, + rsa, +) +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes + +__all__ = [ + "PBES", + "PKCS12PrivateKeyTypes", + "PKCS12Certificate", + "PKCS12KeyAndCertificates", + "load_key_and_certificates", + "load_pkcs12", + "serialize_key_and_certificates", +] + +PKCS12PrivateKeyTypes = typing.Union[ + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, +] + + +class PKCS12Certificate: + def __init__( + self, + cert: x509.Certificate, + friendly_name: typing.Optional[bytes], + ): + if not isinstance(cert, x509.Certificate): + raise TypeError("Expecting x509.Certificate object") + if friendly_name is not None and not isinstance(friendly_name, bytes): + raise TypeError("friendly_name must be bytes or None") + self._cert = cert + self._friendly_name = friendly_name + + @property + def friendly_name(self) -> typing.Optional[bytes]: + return self._friendly_name + + @property + def certificate(self) -> x509.Certificate: + return self._cert + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PKCS12Certificate): + return NotImplemented + + return ( + self.certificate == other.certificate + and self.friendly_name == other.friendly_name + ) + + def __hash__(self) -> int: + return hash((self.certificate, self.friendly_name)) + + def __repr__(self) -> str: + return "<PKCS12Certificate({}, friendly_name={!r})>".format( + self.certificate, self.friendly_name + ) + + +class PKCS12KeyAndCertificates: + def __init__( + self, + key: typing.Optional[PrivateKeyTypes], + cert: typing.Optional[PKCS12Certificate], + additional_certs: typing.List[PKCS12Certificate], + ): + if key is not None and not isinstance( + key, + ( + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + ), + ): + raise TypeError( + "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" + " private key, or None." + ) + if cert is not None and not isinstance(cert, PKCS12Certificate): + raise TypeError("cert must be a PKCS12Certificate object or None") + if not all( + isinstance(add_cert, PKCS12Certificate) + for add_cert in additional_certs + ): + raise TypeError( + "all values in additional_certs must be PKCS12Certificate" + " objects" + ) + self._key = key + self._cert = cert + self._additional_certs = additional_certs + + @property + def key(self) -> typing.Optional[PrivateKeyTypes]: + return self._key + + @property + def cert(self) -> typing.Optional[PKCS12Certificate]: + return self._cert + + @property + def additional_certs(self) -> typing.List[PKCS12Certificate]: + return self._additional_certs + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PKCS12KeyAndCertificates): + return NotImplemented + + return ( + self.key == other.key + and self.cert == other.cert + and self.additional_certs == other.additional_certs + ) + + def __hash__(self) -> int: + return hash((self.key, self.cert, tuple(self.additional_certs))) + + def __repr__(self) -> str: + fmt = ( + "<PKCS12KeyAndCertificates(key={}, cert={}, additional_certs={})>" + ) + return fmt.format(self.key, self.cert, self.additional_certs) + + +def load_key_and_certificates( + data: bytes, + password: typing.Optional[bytes], + backend: typing.Any = None, +) -> typing.Tuple[ + typing.Optional[PrivateKeyTypes], + typing.Optional[x509.Certificate], + typing.List[x509.Certificate], +]: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_key_and_certificates_from_pkcs12(data, password) + + +def load_pkcs12( + data: bytes, + password: typing.Optional[bytes], + backend: typing.Any = None, +) -> PKCS12KeyAndCertificates: + from cryptography.hazmat.backends.openssl.backend import backend as ossl + + return ossl.load_pkcs12(data, password) + + +_PKCS12CATypes = typing.Union[ + x509.Certificate, + PKCS12Certificate, +] + + +def serialize_key_and_certificates( + name: typing.Optional[bytes], + key: typing.Optional[PKCS12PrivateKeyTypes], + cert: typing.Optional[x509.Certificate], + cas: typing.Optional[typing.Iterable[_PKCS12CATypes]], + encryption_algorithm: serialization.KeySerializationEncryption, +) -> bytes: + if key is not None and not isinstance( + key, + ( + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + ), + ): + raise TypeError( + "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" + " private key, or None." + ) + if cert is not None and not isinstance(cert, x509.Certificate): + raise TypeError("cert must be a certificate or None") + + if cas is not None: + cas = list(cas) + if not all( + isinstance( + val, + ( + x509.Certificate, + PKCS12Certificate, + ), + ) + for val in cas + ): + raise TypeError("all values in cas must be certificates") + + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + if key is None and cert is None and not cas: + raise ValueError("You must supply at least one of key, cert, or cas") + + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.serialize_key_and_certificates_to_pkcs12( + name, key, cert, cas, encryption_algorithm + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py new file mode 100644 index 0000000000000000000000000000000000000000..0a72e0df80d5d57fde248cd613ddcadb58afff08 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -0,0 +1,233 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import email.base64mime +import email.generator +import email.message +import email.policy +import io +import typing + +from cryptography import utils, x509 +from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, rsa +from cryptography.utils import _check_byteslike + + +def load_pem_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]: + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.load_pem_pkcs7_certificates(data) + + +def load_der_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]: + from cryptography.hazmat.backends.openssl.backend import backend + + return backend.load_der_pkcs7_certificates(data) + + +def serialize_certificates( + certs: typing.List[x509.Certificate], + encoding: serialization.Encoding, +) -> bytes: + return rust_pkcs7.serialize_certificates(certs, encoding) + + +PKCS7HashTypes = typing.Union[ + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, +] + +PKCS7PrivateKeyTypes = typing.Union[ + rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey +] + + +class PKCS7Options(utils.Enum): + Text = "Add text/plain MIME type" + Binary = "Don't translate input data into canonical MIME format" + DetachedSignature = "Don't embed data in the PKCS7 structure" + NoCapabilities = "Don't embed SMIME capabilities" + NoAttributes = "Don't embed authenticatedAttributes" + NoCerts = "Don't embed signer certificate" + + +class PKCS7SignatureBuilder: + def __init__( + self, + data: typing.Optional[bytes] = None, + signers: typing.List[ + typing.Tuple[ + x509.Certificate, + PKCS7PrivateKeyTypes, + PKCS7HashTypes, + ] + ] = [], + additional_certs: typing.List[x509.Certificate] = [], + ): + self._data = data + self._signers = signers + self._additional_certs = additional_certs + + def set_data(self, data: bytes) -> "PKCS7SignatureBuilder": + _check_byteslike("data", data) + if self._data is not None: + raise ValueError("data may only be set once") + + return PKCS7SignatureBuilder(data, self._signers) + + def add_signer( + self, + certificate: x509.Certificate, + private_key: PKCS7PrivateKeyTypes, + hash_algorithm: PKCS7HashTypes, + ) -> "PKCS7SignatureBuilder": + if not isinstance( + hash_algorithm, + ( + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ): + raise TypeError( + "hash_algorithm must be one of hashes.SHA224, " + "SHA256, SHA384, or SHA512" + ) + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + if not isinstance( + private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) + ): + raise TypeError("Only RSA & EC keys are supported at this time.") + + return PKCS7SignatureBuilder( + self._data, + self._signers + [(certificate, private_key, hash_algorithm)], + ) + + def add_certificate( + self, certificate: x509.Certificate + ) -> "PKCS7SignatureBuilder": + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + return PKCS7SignatureBuilder( + self._data, self._signers, self._additional_certs + [certificate] + ) + + def sign( + self, + encoding: serialization.Encoding, + options: typing.Iterable[PKCS7Options], + backend: typing.Any = None, + ) -> bytes: + if len(self._signers) == 0: + raise ValueError("Must have at least one signer") + if self._data is None: + raise ValueError("You must add data to sign") + options = list(options) + if not all(isinstance(x, PKCS7Options) for x in options): + raise ValueError("options must be from the PKCS7Options enum") + if encoding not in ( + serialization.Encoding.PEM, + serialization.Encoding.DER, + serialization.Encoding.SMIME, + ): + raise ValueError( + "Must be PEM, DER, or SMIME from the Encoding enum" + ) + + # Text is a meaningless option unless it is accompanied by + # DetachedSignature + if ( + PKCS7Options.Text in options + and PKCS7Options.DetachedSignature not in options + ): + raise ValueError( + "When passing the Text option you must also pass " + "DetachedSignature" + ) + + if PKCS7Options.Text in options and encoding in ( + serialization.Encoding.DER, + serialization.Encoding.PEM, + ): + raise ValueError( + "The Text option is only available for SMIME serialization" + ) + + # No attributes implies no capabilities so we'll error if you try to + # pass both. + if ( + PKCS7Options.NoAttributes in options + and PKCS7Options.NoCapabilities in options + ): + raise ValueError( + "NoAttributes is a superset of NoCapabilities. Do not pass " + "both values." + ) + + return rust_pkcs7.sign_and_serialize(self, encoding, options) + + +def _smime_encode( + data: bytes, signature: bytes, micalg: str, text_mode: bool +) -> bytes: + # This function works pretty hard to replicate what OpenSSL does + # precisely. For good and for ill. + + m = email.message.Message() + m.add_header("MIME-Version", "1.0") + m.add_header( + "Content-Type", + "multipart/signed", + protocol="application/x-pkcs7-signature", + micalg=micalg, + ) + + m.preamble = "This is an S/MIME signed message\n" + + msg_part = OpenSSLMimePart() + msg_part.set_payload(data) + if text_mode: + msg_part.add_header("Content-Type", "text/plain") + m.attach(msg_part) + + sig_part = email.message.MIMEPart() + sig_part.add_header( + "Content-Type", "application/x-pkcs7-signature", name="smime.p7s" + ) + sig_part.add_header("Content-Transfer-Encoding", "base64") + sig_part.add_header( + "Content-Disposition", "attachment", filename="smime.p7s" + ) + sig_part.set_payload( + email.base64mime.body_encode(signature, maxlinelen=65) + ) + del sig_part["MIME-Version"] + m.attach(sig_part) + + fp = io.BytesIO() + g = email.generator.BytesGenerator( + fp, + maxheaderlen=0, + mangle_from_=False, + policy=m.policy.clone(linesep="\r\n"), + ) + g.flatten(m) + return fp.getvalue() + + +class OpenSSLMimePart(email.message.MIMEPart): + # A MIMEPart subclass that replicates OpenSSL's behavior of not including + # a newline if there are no headers. + def _write_headers(self, generator) -> None: + if list(self.raw_items()): + generator._write_headers(self) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py new file mode 100644 index 0000000000000000000000000000000000000000..fa278d9ed47a951e6053ddbc8c29a2fc11f0846c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py @@ -0,0 +1,1447 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import binascii +import enum +import os +import re +import typing +import warnings +from base64 import encodebytes as _base64_encode + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + padding, + rsa, +) +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.serialization import ( + Encoding, + KeySerializationEncryption, + NoEncryption, + PrivateFormat, + PublicFormat, + _KeySerializationEncryption, +) + +try: + from bcrypt import kdf as _bcrypt_kdf + + _bcrypt_supported = True +except ImportError: + _bcrypt_supported = False + + def _bcrypt_kdf( + password: bytes, + salt: bytes, + desired_key_bytes: int, + rounds: int, + ignore_few_rounds: bool = False, + ) -> bytes: + raise UnsupportedAlgorithm("Need bcrypt module") + + +_SSH_ED25519 = b"ssh-ed25519" +_SSH_RSA = b"ssh-rsa" +_SSH_DSA = b"ssh-dss" +_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256" +_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384" +_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521" +_CERT_SUFFIX = b"-cert-v01@openssh.com" + +# These are not key types, only algorithms, so they cannot appear +# as a public key type +_SSH_RSA_SHA256 = b"rsa-sha2-256" +_SSH_RSA_SHA512 = b"rsa-sha2-512" + +_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") +_SK_MAGIC = b"openssh-key-v1\0" +_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----" +_SK_END = b"-----END OPENSSH PRIVATE KEY-----" +_BCRYPT = b"bcrypt" +_NONE = b"none" +_DEFAULT_CIPHER = b"aes256-ctr" +_DEFAULT_ROUNDS = 16 + +# re is only way to work on bytes-like data +_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL) + +# padding for max blocksize +_PADDING = memoryview(bytearray(range(1, 1 + 16))) + +# ciphers that are actually used in key wrapping +_SSH_CIPHERS: typing.Dict[ + bytes, + typing.Tuple[ + typing.Type[algorithms.AES], + int, + typing.Union[typing.Type[modes.CTR], typing.Type[modes.CBC]], + int, + ], +] = { + b"aes256-ctr": (algorithms.AES, 32, modes.CTR, 16), + b"aes256-cbc": (algorithms.AES, 32, modes.CBC, 16), +} + +# map local curve name to key type +_ECDSA_KEY_TYPE = { + "secp256r1": _ECDSA_NISTP256, + "secp384r1": _ECDSA_NISTP384, + "secp521r1": _ECDSA_NISTP521, +} + + +def _get_ssh_key_type( + key: typing.Union["SSHPrivateKeyTypes", "SSHPublicKeyTypes"] +) -> bytes: + if isinstance(key, ec.EllipticCurvePrivateKey): + key_type = _ecdsa_key_type(key.public_key()) + elif isinstance(key, ec.EllipticCurvePublicKey): + key_type = _ecdsa_key_type(key) + elif isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): + key_type = _SSH_RSA + elif isinstance(key, (dsa.DSAPrivateKey, dsa.DSAPublicKey)): + key_type = _SSH_DSA + elif isinstance( + key, (ed25519.Ed25519PrivateKey, ed25519.Ed25519PublicKey) + ): + key_type = _SSH_ED25519 + else: + raise ValueError("Unsupported key type") + + return key_type + + +def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes: + """Return SSH key_type and curve_name for private key.""" + curve = public_key.curve + if curve.name not in _ECDSA_KEY_TYPE: + raise ValueError( + f"Unsupported curve for ssh private key: {curve.name!r}" + ) + return _ECDSA_KEY_TYPE[curve.name] + + +def _ssh_pem_encode( + data: bytes, + prefix: bytes = _SK_START + b"\n", + suffix: bytes = _SK_END + b"\n", +) -> bytes: + return b"".join([prefix, _base64_encode(data), suffix]) + + +def _check_block_size(data: bytes, block_len: int) -> None: + """Require data to be full blocks""" + if not data or len(data) % block_len != 0: + raise ValueError("Corrupt data: missing padding") + + +def _check_empty(data: bytes) -> None: + """All data should have been parsed.""" + if data: + raise ValueError("Corrupt data: unparsed data") + + +def _init_cipher( + ciphername: bytes, + password: typing.Optional[bytes], + salt: bytes, + rounds: int, +) -> Cipher[typing.Union[modes.CBC, modes.CTR]]: + """Generate key + iv and return cipher.""" + if not password: + raise ValueError("Key is password-protected.") + + algo, key_len, mode, iv_len = _SSH_CIPHERS[ciphername] + seed = _bcrypt_kdf(password, salt, key_len + iv_len, rounds, True) + return Cipher(algo(seed[:key_len]), mode(seed[key_len:])) + + +def _get_u32(data: memoryview) -> typing.Tuple[int, memoryview]: + """Uint32""" + if len(data) < 4: + raise ValueError("Invalid data") + return int.from_bytes(data[:4], byteorder="big"), data[4:] + + +def _get_u64(data: memoryview) -> typing.Tuple[int, memoryview]: + """Uint64""" + if len(data) < 8: + raise ValueError("Invalid data") + return int.from_bytes(data[:8], byteorder="big"), data[8:] + + +def _get_sshstr(data: memoryview) -> typing.Tuple[memoryview, memoryview]: + """Bytes with u32 length prefix""" + n, data = _get_u32(data) + if n > len(data): + raise ValueError("Invalid data") + return data[:n], data[n:] + + +def _get_mpint(data: memoryview) -> typing.Tuple[int, memoryview]: + """Big integer.""" + val, data = _get_sshstr(data) + if val and val[0] > 0x7F: + raise ValueError("Invalid data") + return int.from_bytes(val, "big"), data + + +def _to_mpint(val: int) -> bytes: + """Storage format for signed bigint.""" + if val < 0: + raise ValueError("negative mpint not allowed") + if not val: + return b"" + nbytes = (val.bit_length() + 8) // 8 + return utils.int_to_bytes(val, nbytes) + + +class _FragList: + """Build recursive structure without data copy.""" + + flist: typing.List[bytes] + + def __init__( + self, init: typing.Optional[typing.List[bytes]] = None + ) -> None: + self.flist = [] + if init: + self.flist.extend(init) + + def put_raw(self, val: bytes) -> None: + """Add plain bytes""" + self.flist.append(val) + + def put_u32(self, val: int) -> None: + """Big-endian uint32""" + self.flist.append(val.to_bytes(length=4, byteorder="big")) + + def put_u64(self, val: int) -> None: + """Big-endian uint64""" + self.flist.append(val.to_bytes(length=8, byteorder="big")) + + def put_sshstr(self, val: typing.Union[bytes, "_FragList"]) -> None: + """Bytes prefixed with u32 length""" + if isinstance(val, (bytes, memoryview, bytearray)): + self.put_u32(len(val)) + self.flist.append(val) + else: + self.put_u32(val.size()) + self.flist.extend(val.flist) + + def put_mpint(self, val: int) -> None: + """Big-endian bigint prefixed with u32 length""" + self.put_sshstr(_to_mpint(val)) + + def size(self) -> int: + """Current number of bytes""" + return sum(map(len, self.flist)) + + def render(self, dstbuf: memoryview, pos: int = 0) -> int: + """Write into bytearray""" + for frag in self.flist: + flen = len(frag) + start, pos = pos, pos + flen + dstbuf[start:pos] = frag + return pos + + def tobytes(self) -> bytes: + """Return as bytes""" + buf = memoryview(bytearray(self.size())) + self.render(buf) + return buf.tobytes() + + +class _SSHFormatRSA: + """Format for RSA keys. + + Public: + mpint e, n + Private: + mpint n, e, d, iqmp, p, q + """ + + def get_public(self, data: memoryview): + """RSA public fields""" + e, data = _get_mpint(data) + n, data = _get_mpint(data) + return (e, n), data + + def load_public( + self, data: memoryview + ) -> typing.Tuple[rsa.RSAPublicKey, memoryview]: + """Make RSA public key from data.""" + (e, n), data = self.get_public(data) + public_numbers = rsa.RSAPublicNumbers(e, n) + public_key = public_numbers.public_key() + return public_key, data + + def load_private( + self, data: memoryview, pubfields + ) -> typing.Tuple[rsa.RSAPrivateKey, memoryview]: + """Make RSA private key from data.""" + n, data = _get_mpint(data) + e, data = _get_mpint(data) + d, data = _get_mpint(data) + iqmp, data = _get_mpint(data) + p, data = _get_mpint(data) + q, data = _get_mpint(data) + + if (e, n) != pubfields: + raise ValueError("Corrupt data: rsa field mismatch") + dmp1 = rsa.rsa_crt_dmp1(d, p) + dmq1 = rsa.rsa_crt_dmq1(d, q) + public_numbers = rsa.RSAPublicNumbers(e, n) + private_numbers = rsa.RSAPrivateNumbers( + p, q, d, dmp1, dmq1, iqmp, public_numbers + ) + private_key = private_numbers.private_key() + return private_key, data + + def encode_public( + self, public_key: rsa.RSAPublicKey, f_pub: _FragList + ) -> None: + """Write RSA public key""" + pubn = public_key.public_numbers() + f_pub.put_mpint(pubn.e) + f_pub.put_mpint(pubn.n) + + def encode_private( + self, private_key: rsa.RSAPrivateKey, f_priv: _FragList + ) -> None: + """Write RSA private key""" + private_numbers = private_key.private_numbers() + public_numbers = private_numbers.public_numbers + + f_priv.put_mpint(public_numbers.n) + f_priv.put_mpint(public_numbers.e) + + f_priv.put_mpint(private_numbers.d) + f_priv.put_mpint(private_numbers.iqmp) + f_priv.put_mpint(private_numbers.p) + f_priv.put_mpint(private_numbers.q) + + +class _SSHFormatDSA: + """Format for DSA keys. + + Public: + mpint p, q, g, y + Private: + mpint p, q, g, y, x + """ + + def get_public( + self, data: memoryview + ) -> typing.Tuple[typing.Tuple, memoryview]: + """DSA public fields""" + p, data = _get_mpint(data) + q, data = _get_mpint(data) + g, data = _get_mpint(data) + y, data = _get_mpint(data) + return (p, q, g, y), data + + def load_public( + self, data: memoryview + ) -> typing.Tuple[dsa.DSAPublicKey, memoryview]: + """Make DSA public key from data.""" + (p, q, g, y), data = self.get_public(data) + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + public_key = public_numbers.public_key() + return public_key, data + + def load_private( + self, data: memoryview, pubfields + ) -> typing.Tuple[dsa.DSAPrivateKey, memoryview]: + """Make DSA private key from data.""" + (p, q, g, y), data = self.get_public(data) + x, data = _get_mpint(data) + + if (p, q, g, y) != pubfields: + raise ValueError("Corrupt data: dsa field mismatch") + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + private_numbers = dsa.DSAPrivateNumbers(x, public_numbers) + private_key = private_numbers.private_key() + return private_key, data + + def encode_public( + self, public_key: dsa.DSAPublicKey, f_pub: _FragList + ) -> None: + """Write DSA public key""" + public_numbers = public_key.public_numbers() + parameter_numbers = public_numbers.parameter_numbers + self._validate(public_numbers) + + f_pub.put_mpint(parameter_numbers.p) + f_pub.put_mpint(parameter_numbers.q) + f_pub.put_mpint(parameter_numbers.g) + f_pub.put_mpint(public_numbers.y) + + def encode_private( + self, private_key: dsa.DSAPrivateKey, f_priv: _FragList + ) -> None: + """Write DSA private key""" + self.encode_public(private_key.public_key(), f_priv) + f_priv.put_mpint(private_key.private_numbers().x) + + def _validate(self, public_numbers: dsa.DSAPublicNumbers) -> None: + parameter_numbers = public_numbers.parameter_numbers + if parameter_numbers.p.bit_length() != 1024: + raise ValueError("SSH supports only 1024 bit DSA keys") + + +class _SSHFormatECDSA: + """Format for ECDSA keys. + + Public: + str curve + bytes point + Private: + str curve + bytes point + mpint secret + """ + + def __init__(self, ssh_curve_name: bytes, curve: ec.EllipticCurve): + self.ssh_curve_name = ssh_curve_name + self.curve = curve + + def get_public( + self, data: memoryview + ) -> typing.Tuple[typing.Tuple, memoryview]: + """ECDSA public fields""" + curve, data = _get_sshstr(data) + point, data = _get_sshstr(data) + if curve != self.ssh_curve_name: + raise ValueError("Curve name mismatch") + if point[0] != 4: + raise NotImplementedError("Need uncompressed point") + return (curve, point), data + + def load_public( + self, data: memoryview + ) -> typing.Tuple[ec.EllipticCurvePublicKey, memoryview]: + """Make ECDSA public key from data.""" + (curve_name, point), data = self.get_public(data) + public_key = ec.EllipticCurvePublicKey.from_encoded_point( + self.curve, point.tobytes() + ) + return public_key, data + + def load_private( + self, data: memoryview, pubfields + ) -> typing.Tuple[ec.EllipticCurvePrivateKey, memoryview]: + """Make ECDSA private key from data.""" + (curve_name, point), data = self.get_public(data) + secret, data = _get_mpint(data) + + if (curve_name, point) != pubfields: + raise ValueError("Corrupt data: ecdsa field mismatch") + private_key = ec.derive_private_key(secret, self.curve) + return private_key, data + + def encode_public( + self, public_key: ec.EllipticCurvePublicKey, f_pub: _FragList + ) -> None: + """Write ECDSA public key""" + point = public_key.public_bytes( + Encoding.X962, PublicFormat.UncompressedPoint + ) + f_pub.put_sshstr(self.ssh_curve_name) + f_pub.put_sshstr(point) + + def encode_private( + self, private_key: ec.EllipticCurvePrivateKey, f_priv: _FragList + ) -> None: + """Write ECDSA private key""" + public_key = private_key.public_key() + private_numbers = private_key.private_numbers() + + self.encode_public(public_key, f_priv) + f_priv.put_mpint(private_numbers.private_value) + + +class _SSHFormatEd25519: + """Format for Ed25519 keys. + + Public: + bytes point + Private: + bytes point + bytes secret_and_point + """ + + def get_public( + self, data: memoryview + ) -> typing.Tuple[typing.Tuple, memoryview]: + """Ed25519 public fields""" + point, data = _get_sshstr(data) + return (point,), data + + def load_public( + self, data: memoryview + ) -> typing.Tuple[ed25519.Ed25519PublicKey, memoryview]: + """Make Ed25519 public key from data.""" + (point,), data = self.get_public(data) + public_key = ed25519.Ed25519PublicKey.from_public_bytes( + point.tobytes() + ) + return public_key, data + + def load_private( + self, data: memoryview, pubfields + ) -> typing.Tuple[ed25519.Ed25519PrivateKey, memoryview]: + """Make Ed25519 private key from data.""" + (point,), data = self.get_public(data) + keypair, data = _get_sshstr(data) + + secret = keypair[:32] + point2 = keypair[32:] + if point != point2 or (point,) != pubfields: + raise ValueError("Corrupt data: ed25519 field mismatch") + private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) + return private_key, data + + def encode_public( + self, public_key: ed25519.Ed25519PublicKey, f_pub: _FragList + ) -> None: + """Write Ed25519 public key""" + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_pub.put_sshstr(raw_public_key) + + def encode_private( + self, private_key: ed25519.Ed25519PrivateKey, f_priv: _FragList + ) -> None: + """Write Ed25519 private key""" + public_key = private_key.public_key() + raw_private_key = private_key.private_bytes( + Encoding.Raw, PrivateFormat.Raw, NoEncryption() + ) + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_keypair = _FragList([raw_private_key, raw_public_key]) + + self.encode_public(public_key, f_priv) + f_priv.put_sshstr(f_keypair) + + +_KEY_FORMATS = { + _SSH_RSA: _SSHFormatRSA(), + _SSH_DSA: _SSHFormatDSA(), + _SSH_ED25519: _SSHFormatEd25519(), + _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()), + _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()), + _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()), +} + + +def _lookup_kformat(key_type: bytes): + """Return valid format or throw error""" + if not isinstance(key_type, bytes): + key_type = memoryview(key_type).tobytes() + if key_type in _KEY_FORMATS: + return _KEY_FORMATS[key_type] + raise UnsupportedAlgorithm(f"Unsupported key type: {key_type!r}") + + +SSHPrivateKeyTypes = typing.Union[ + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ed25519.Ed25519PrivateKey, +] + + +def load_ssh_private_key( + data: bytes, + password: typing.Optional[bytes], + backend: typing.Any = None, +) -> SSHPrivateKeyTypes: + """Load private key from OpenSSH custom encoding.""" + utils._check_byteslike("data", data) + if password is not None: + utils._check_bytes("password", password) + + m = _PEM_RC.search(data) + if not m: + raise ValueError("Not OpenSSH private key format") + p1 = m.start(1) + p2 = m.end(1) + data = binascii.a2b_base64(memoryview(data)[p1:p2]) + if not data.startswith(_SK_MAGIC): + raise ValueError("Not OpenSSH private key format") + data = memoryview(data)[len(_SK_MAGIC) :] + + # parse header + ciphername, data = _get_sshstr(data) + kdfname, data = _get_sshstr(data) + kdfoptions, data = _get_sshstr(data) + nkeys, data = _get_u32(data) + if nkeys != 1: + raise ValueError("Only one key supported") + + # load public key data + pubdata, data = _get_sshstr(data) + pub_key_type, pubdata = _get_sshstr(pubdata) + kformat = _lookup_kformat(pub_key_type) + pubfields, pubdata = kformat.get_public(pubdata) + _check_empty(pubdata) + + # load secret data + edata, data = _get_sshstr(data) + _check_empty(data) + + if (ciphername, kdfname) != (_NONE, _NONE): + ciphername_bytes = ciphername.tobytes() + if ciphername_bytes not in _SSH_CIPHERS: + raise UnsupportedAlgorithm( + f"Unsupported cipher: {ciphername_bytes!r}" + ) + if kdfname != _BCRYPT: + raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}") + blklen = _SSH_CIPHERS[ciphername_bytes][3] + _check_block_size(edata, blklen) + salt, kbuf = _get_sshstr(kdfoptions) + rounds, kbuf = _get_u32(kbuf) + _check_empty(kbuf) + ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds) + edata = memoryview(ciph.decryptor().update(edata)) + else: + blklen = 8 + _check_block_size(edata, blklen) + ck1, edata = _get_u32(edata) + ck2, edata = _get_u32(edata) + if ck1 != ck2: + raise ValueError("Corrupt data: broken checksum") + + # load per-key struct + key_type, edata = _get_sshstr(edata) + if key_type != pub_key_type: + raise ValueError("Corrupt data: key type mismatch") + private_key, edata = kformat.load_private(edata, pubfields) + comment, edata = _get_sshstr(edata) + + # yes, SSH does padding check *after* all other parsing is done. + # need to follow as it writes zero-byte padding too. + if edata != _PADDING[: len(edata)]: + raise ValueError("Corrupt data: invalid padding") + + if isinstance(private_key, dsa.DSAPrivateKey): + warnings.warn( + "SSH DSA keys are deprecated and will be removed in a future " + "release.", + utils.DeprecatedIn40, + stacklevel=2, + ) + + return private_key + + +def _serialize_ssh_private_key( + private_key: SSHPrivateKeyTypes, + password: bytes, + encryption_algorithm: KeySerializationEncryption, +) -> bytes: + """Serialize private key with OpenSSH custom encoding.""" + utils._check_bytes("password", password) + if isinstance(private_key, dsa.DSAPrivateKey): + warnings.warn( + "SSH DSA key support is deprecated and will be " + "removed in a future release", + utils.DeprecatedIn40, + stacklevel=4, + ) + + key_type = _get_ssh_key_type(private_key) + kformat = _lookup_kformat(key_type) + + # setup parameters + f_kdfoptions = _FragList() + if password: + ciphername = _DEFAULT_CIPHER + blklen = _SSH_CIPHERS[ciphername][3] + kdfname = _BCRYPT + rounds = _DEFAULT_ROUNDS + if ( + isinstance(encryption_algorithm, _KeySerializationEncryption) + and encryption_algorithm._kdf_rounds is not None + ): + rounds = encryption_algorithm._kdf_rounds + salt = os.urandom(16) + f_kdfoptions.put_sshstr(salt) + f_kdfoptions.put_u32(rounds) + ciph = _init_cipher(ciphername, password, salt, rounds) + else: + ciphername = kdfname = _NONE + blklen = 8 + ciph = None + nkeys = 1 + checkval = os.urandom(4) + comment = b"" + + # encode public and private parts together + f_public_key = _FragList() + f_public_key.put_sshstr(key_type) + kformat.encode_public(private_key.public_key(), f_public_key) + + f_secrets = _FragList([checkval, checkval]) + f_secrets.put_sshstr(key_type) + kformat.encode_private(private_key, f_secrets) + f_secrets.put_sshstr(comment) + f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)]) + + # top-level structure + f_main = _FragList() + f_main.put_raw(_SK_MAGIC) + f_main.put_sshstr(ciphername) + f_main.put_sshstr(kdfname) + f_main.put_sshstr(f_kdfoptions) + f_main.put_u32(nkeys) + f_main.put_sshstr(f_public_key) + f_main.put_sshstr(f_secrets) + + # copy result info bytearray + slen = f_secrets.size() + mlen = f_main.size() + buf = memoryview(bytearray(mlen + blklen)) + f_main.render(buf) + ofs = mlen - slen + + # encrypt in-place + if ciph is not None: + ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:]) + + return _ssh_pem_encode(buf[:mlen]) + + +SSHPublicKeyTypes = typing.Union[ + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + dsa.DSAPublicKey, + ed25519.Ed25519PublicKey, +] + +SSHCertPublicKeyTypes = typing.Union[ + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + ed25519.Ed25519PublicKey, +] + + +class SSHCertificateType(enum.Enum): + USER = 1 + HOST = 2 + + +class SSHCertificate: + def __init__( + self, + _nonce: memoryview, + _public_key: SSHPublicKeyTypes, + _serial: int, + _cctype: int, + _key_id: memoryview, + _valid_principals: typing.List[bytes], + _valid_after: int, + _valid_before: int, + _critical_options: typing.Dict[bytes, bytes], + _extensions: typing.Dict[bytes, bytes], + _sig_type: memoryview, + _sig_key: memoryview, + _inner_sig_type: memoryview, + _signature: memoryview, + _tbs_cert_body: memoryview, + _cert_key_type: bytes, + _cert_body: memoryview, + ): + self._nonce = _nonce + self._public_key = _public_key + self._serial = _serial + try: + self._type = SSHCertificateType(_cctype) + except ValueError: + raise ValueError("Invalid certificate type") + self._key_id = _key_id + self._valid_principals = _valid_principals + self._valid_after = _valid_after + self._valid_before = _valid_before + self._critical_options = _critical_options + self._extensions = _extensions + self._sig_type = _sig_type + self._sig_key = _sig_key + self._inner_sig_type = _inner_sig_type + self._signature = _signature + self._cert_key_type = _cert_key_type + self._cert_body = _cert_body + self._tbs_cert_body = _tbs_cert_body + + @property + def nonce(self) -> bytes: + return bytes(self._nonce) + + def public_key(self) -> SSHCertPublicKeyTypes: + # make mypy happy until we remove DSA support entirely and + # the underlying union won't have a disallowed type + return typing.cast(SSHCertPublicKeyTypes, self._public_key) + + @property + def serial(self) -> int: + return self._serial + + @property + def type(self) -> SSHCertificateType: + return self._type + + @property + def key_id(self) -> bytes: + return bytes(self._key_id) + + @property + def valid_principals(self) -> typing.List[bytes]: + return self._valid_principals + + @property + def valid_before(self) -> int: + return self._valid_before + + @property + def valid_after(self) -> int: + return self._valid_after + + @property + def critical_options(self) -> typing.Dict[bytes, bytes]: + return self._critical_options + + @property + def extensions(self) -> typing.Dict[bytes, bytes]: + return self._extensions + + def signature_key(self) -> SSHCertPublicKeyTypes: + sigformat = _lookup_kformat(self._sig_type) + signature_key, sigkey_rest = sigformat.load_public(self._sig_key) + _check_empty(sigkey_rest) + return signature_key + + def public_bytes(self) -> bytes: + return ( + bytes(self._cert_key_type) + + b" " + + binascii.b2a_base64(bytes(self._cert_body), newline=False) + ) + + def verify_cert_signature(self) -> None: + signature_key = self.signature_key() + if isinstance(signature_key, ed25519.Ed25519PublicKey): + signature_key.verify( + bytes(self._signature), bytes(self._tbs_cert_body) + ) + elif isinstance(signature_key, ec.EllipticCurvePublicKey): + # The signature is encoded as a pair of big-endian integers + r, data = _get_mpint(self._signature) + s, data = _get_mpint(data) + _check_empty(data) + computed_sig = asym_utils.encode_dss_signature(r, s) + hash_alg = _get_ec_hash_alg(signature_key.curve) + signature_key.verify( + computed_sig, bytes(self._tbs_cert_body), ec.ECDSA(hash_alg) + ) + else: + assert isinstance(signature_key, rsa.RSAPublicKey) + if self._inner_sig_type == _SSH_RSA: + hash_alg = hashes.SHA1() + elif self._inner_sig_type == _SSH_RSA_SHA256: + hash_alg = hashes.SHA256() + else: + assert self._inner_sig_type == _SSH_RSA_SHA512 + hash_alg = hashes.SHA512() + signature_key.verify( + bytes(self._signature), + bytes(self._tbs_cert_body), + padding.PKCS1v15(), + hash_alg, + ) + + +def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm: + if isinstance(curve, ec.SECP256R1): + return hashes.SHA256() + elif isinstance(curve, ec.SECP384R1): + return hashes.SHA384() + else: + assert isinstance(curve, ec.SECP521R1) + return hashes.SHA512() + + +def _load_ssh_public_identity( + data: bytes, + _legacy_dsa_allowed=False, +) -> typing.Union[SSHCertificate, SSHPublicKeyTypes]: + utils._check_byteslike("data", data) + + m = _SSH_PUBKEY_RC.match(data) + if not m: + raise ValueError("Invalid line format") + key_type = orig_key_type = m.group(1) + key_body = m.group(2) + with_cert = False + if key_type.endswith(_CERT_SUFFIX): + with_cert = True + key_type = key_type[: -len(_CERT_SUFFIX)] + if key_type == _SSH_DSA and not _legacy_dsa_allowed: + raise UnsupportedAlgorithm( + "DSA keys aren't supported in SSH certificates" + ) + kformat = _lookup_kformat(key_type) + + try: + rest = memoryview(binascii.a2b_base64(key_body)) + except (TypeError, binascii.Error): + raise ValueError("Invalid format") + + if with_cert: + cert_body = rest + inner_key_type, rest = _get_sshstr(rest) + if inner_key_type != orig_key_type: + raise ValueError("Invalid key format") + if with_cert: + nonce, rest = _get_sshstr(rest) + public_key, rest = kformat.load_public(rest) + if with_cert: + serial, rest = _get_u64(rest) + cctype, rest = _get_u32(rest) + key_id, rest = _get_sshstr(rest) + principals, rest = _get_sshstr(rest) + valid_principals = [] + while principals: + principal, principals = _get_sshstr(principals) + valid_principals.append(bytes(principal)) + valid_after, rest = _get_u64(rest) + valid_before, rest = _get_u64(rest) + crit_options, rest = _get_sshstr(rest) + critical_options = _parse_exts_opts(crit_options) + exts, rest = _get_sshstr(rest) + extensions = _parse_exts_opts(exts) + # Get the reserved field, which is unused. + _, rest = _get_sshstr(rest) + sig_key_raw, rest = _get_sshstr(rest) + sig_type, sig_key = _get_sshstr(sig_key_raw) + if sig_type == _SSH_DSA and not _legacy_dsa_allowed: + raise UnsupportedAlgorithm( + "DSA signatures aren't supported in SSH certificates" + ) + # Get the entire cert body and subtract the signature + tbs_cert_body = cert_body[: -len(rest)] + signature_raw, rest = _get_sshstr(rest) + _check_empty(rest) + inner_sig_type, sig_rest = _get_sshstr(signature_raw) + # RSA certs can have multiple algorithm types + if ( + sig_type == _SSH_RSA + and inner_sig_type + not in [_SSH_RSA_SHA256, _SSH_RSA_SHA512, _SSH_RSA] + ) or (sig_type != _SSH_RSA and inner_sig_type != sig_type): + raise ValueError("Signature key type does not match") + signature, sig_rest = _get_sshstr(sig_rest) + _check_empty(sig_rest) + return SSHCertificate( + nonce, + public_key, + serial, + cctype, + key_id, + valid_principals, + valid_after, + valid_before, + critical_options, + extensions, + sig_type, + sig_key, + inner_sig_type, + signature, + tbs_cert_body, + orig_key_type, + cert_body, + ) + else: + _check_empty(rest) + return public_key + + +def load_ssh_public_identity( + data: bytes, +) -> typing.Union[SSHCertificate, SSHPublicKeyTypes]: + return _load_ssh_public_identity(data) + + +def _parse_exts_opts(exts_opts: memoryview) -> typing.Dict[bytes, bytes]: + result: typing.Dict[bytes, bytes] = {} + last_name = None + while exts_opts: + name, exts_opts = _get_sshstr(exts_opts) + bname: bytes = bytes(name) + if bname in result: + raise ValueError("Duplicate name") + if last_name is not None and bname < last_name: + raise ValueError("Fields not lexically sorted") + value, exts_opts = _get_sshstr(exts_opts) + result[bname] = bytes(value) + last_name = bname + return result + + +def load_ssh_public_key( + data: bytes, backend: typing.Any = None +) -> SSHPublicKeyTypes: + cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True) + public_key: SSHPublicKeyTypes + if isinstance(cert_or_key, SSHCertificate): + public_key = cert_or_key.public_key() + else: + public_key = cert_or_key + + if isinstance(public_key, dsa.DSAPublicKey): + warnings.warn( + "SSH DSA keys are deprecated and will be removed in a future " + "release.", + utils.DeprecatedIn40, + stacklevel=2, + ) + return public_key + + +def serialize_ssh_public_key(public_key: SSHPublicKeyTypes) -> bytes: + """One-line public key format for OpenSSH""" + if isinstance(public_key, dsa.DSAPublicKey): + warnings.warn( + "SSH DSA key support is deprecated and will be " + "removed in a future release", + utils.DeprecatedIn40, + stacklevel=4, + ) + key_type = _get_ssh_key_type(public_key) + kformat = _lookup_kformat(key_type) + + f_pub = _FragList() + f_pub.put_sshstr(key_type) + kformat.encode_public(public_key, f_pub) + + pub = binascii.b2a_base64(f_pub.tobytes()).strip() + return b"".join([key_type, b" ", pub]) + + +SSHCertPrivateKeyTypes = typing.Union[ + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + ed25519.Ed25519PrivateKey, +] + + +# This is an undocumented limit enforced in the openssh codebase for sshd and +# ssh-keygen, but it is undefined in the ssh certificates spec. +_SSHKEY_CERT_MAX_PRINCIPALS = 256 + + +class SSHCertificateBuilder: + def __init__( + self, + _public_key: typing.Optional[SSHCertPublicKeyTypes] = None, + _serial: typing.Optional[int] = None, + _type: typing.Optional[SSHCertificateType] = None, + _key_id: typing.Optional[bytes] = None, + _valid_principals: typing.List[bytes] = [], + _valid_for_all_principals: bool = False, + _valid_before: typing.Optional[int] = None, + _valid_after: typing.Optional[int] = None, + _critical_options: typing.List[typing.Tuple[bytes, bytes]] = [], + _extensions: typing.List[typing.Tuple[bytes, bytes]] = [], + ): + self._public_key = _public_key + self._serial = _serial + self._type = _type + self._key_id = _key_id + self._valid_principals = _valid_principals + self._valid_for_all_principals = _valid_for_all_principals + self._valid_before = _valid_before + self._valid_after = _valid_after + self._critical_options = _critical_options + self._extensions = _extensions + + def public_key( + self, public_key: SSHCertPublicKeyTypes + ) -> "SSHCertificateBuilder": + if not isinstance( + public_key, + ( + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + ed25519.Ed25519PublicKey, + ), + ): + raise TypeError("Unsupported key type") + if self._public_key is not None: + raise ValueError("public_key already set") + + return SSHCertificateBuilder( + _public_key=public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def serial(self, serial: int) -> "SSHCertificateBuilder": + if not isinstance(serial, int): + raise TypeError("serial must be an integer") + if not 0 <= serial < 2**64: + raise ValueError("serial must be between 0 and 2**64") + if self._serial is not None: + raise ValueError("serial already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def type(self, type: SSHCertificateType) -> "SSHCertificateBuilder": + if not isinstance(type, SSHCertificateType): + raise TypeError("type must be an SSHCertificateType") + if self._type is not None: + raise ValueError("type already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def key_id(self, key_id: bytes) -> "SSHCertificateBuilder": + if not isinstance(key_id, bytes): + raise TypeError("key_id must be bytes") + if self._key_id is not None: + raise ValueError("key_id already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_principals( + self, valid_principals: typing.List[bytes] + ) -> "SSHCertificateBuilder": + if self._valid_for_all_principals: + raise ValueError( + "Principals can't be set because the cert is valid " + "for all principals" + ) + if ( + not all(isinstance(x, bytes) for x in valid_principals) + or not valid_principals + ): + raise TypeError( + "principals must be a list of bytes and can't be empty" + ) + if self._valid_principals: + raise ValueError("valid_principals already set") + + if len(valid_principals) > _SSHKEY_CERT_MAX_PRINCIPALS: + raise ValueError( + "Reached or exceeded the maximum number of valid_principals" + ) + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_for_all_principals(self): + if self._valid_principals: + raise ValueError( + "valid_principals already set, can't set " + "valid_for_all_principals" + ) + if self._valid_for_all_principals: + raise ValueError("valid_for_all_principals already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=True, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_before( + self, valid_before: typing.Union[int, float] + ) -> "SSHCertificateBuilder": + if not isinstance(valid_before, (int, float)): + raise TypeError("valid_before must be an int or float") + valid_before = int(valid_before) + if valid_before < 0 or valid_before >= 2**64: + raise ValueError("valid_before must [0, 2**64)") + if self._valid_before is not None: + raise ValueError("valid_before already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_after( + self, valid_after: typing.Union[int, float] + ) -> "SSHCertificateBuilder": + if not isinstance(valid_after, (int, float)): + raise TypeError("valid_after must be an int or float") + valid_after = int(valid_after) + if valid_after < 0 or valid_after >= 2**64: + raise ValueError("valid_after must [0, 2**64)") + if self._valid_after is not None: + raise ValueError("valid_after already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def add_critical_option( + self, name: bytes, value: bytes + ) -> "SSHCertificateBuilder": + if not isinstance(name, bytes) or not isinstance(value, bytes): + raise TypeError("name and value must be bytes") + # This is O(n**2) + if name in [name for name, _ in self._critical_options]: + raise ValueError("Duplicate critical option name") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options + [(name, value)], + _extensions=self._extensions, + ) + + def add_extension( + self, name: bytes, value: bytes + ) -> "SSHCertificateBuilder": + if not isinstance(name, bytes) or not isinstance(value, bytes): + raise TypeError("name and value must be bytes") + # This is O(n**2) + if name in [name for name, _ in self._extensions]: + raise ValueError("Duplicate extension name") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions + [(name, value)], + ) + + def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate: + if not isinstance( + private_key, + ( + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + ed25519.Ed25519PrivateKey, + ), + ): + raise TypeError("Unsupported private key type") + + if self._public_key is None: + raise ValueError("public_key must be set") + + # Not required + serial = 0 if self._serial is None else self._serial + + if self._type is None: + raise ValueError("type must be set") + + # Not required + key_id = b"" if self._key_id is None else self._key_id + + # A zero length list is valid, but means the certificate + # is valid for any principal of the specified type. We require + # the user to explicitly set valid_for_all_principals to get + # that behavior. + if not self._valid_principals and not self._valid_for_all_principals: + raise ValueError( + "valid_principals must be set if valid_for_all_principals " + "is False" + ) + + if self._valid_before is None: + raise ValueError("valid_before must be set") + + if self._valid_after is None: + raise ValueError("valid_after must be set") + + if self._valid_after > self._valid_before: + raise ValueError("valid_after must be earlier than valid_before") + + # lexically sort our byte strings + self._critical_options.sort(key=lambda x: x[0]) + self._extensions.sort(key=lambda x: x[0]) + + key_type = _get_ssh_key_type(self._public_key) + cert_prefix = key_type + _CERT_SUFFIX + + # Marshal the bytes to be signed + nonce = os.urandom(32) + kformat = _lookup_kformat(key_type) + f = _FragList() + f.put_sshstr(cert_prefix) + f.put_sshstr(nonce) + kformat.encode_public(self._public_key, f) + f.put_u64(serial) + f.put_u32(self._type.value) + f.put_sshstr(key_id) + fprincipals = _FragList() + for p in self._valid_principals: + fprincipals.put_sshstr(p) + f.put_sshstr(fprincipals.tobytes()) + f.put_u64(self._valid_after) + f.put_u64(self._valid_before) + fcrit = _FragList() + for name, value in self._critical_options: + fcrit.put_sshstr(name) + fcrit.put_sshstr(value) + f.put_sshstr(fcrit.tobytes()) + fext = _FragList() + for name, value in self._extensions: + fext.put_sshstr(name) + fext.put_sshstr(value) + f.put_sshstr(fext.tobytes()) + f.put_sshstr(b"") # RESERVED FIELD + # encode CA public key + ca_type = _get_ssh_key_type(private_key) + caformat = _lookup_kformat(ca_type) + caf = _FragList() + caf.put_sshstr(ca_type) + caformat.encode_public(private_key.public_key(), caf) + f.put_sshstr(caf.tobytes()) + # Sigs according to the rules defined for the CA's public key + # (RFC4253 section 6.6 for ssh-rsa, RFC5656 for ECDSA, + # and RFC8032 for Ed25519). + if isinstance(private_key, ed25519.Ed25519PrivateKey): + signature = private_key.sign(f.tobytes()) + fsig = _FragList() + fsig.put_sshstr(ca_type) + fsig.put_sshstr(signature) + f.put_sshstr(fsig.tobytes()) + elif isinstance(private_key, ec.EllipticCurvePrivateKey): + hash_alg = _get_ec_hash_alg(private_key.curve) + signature = private_key.sign(f.tobytes(), ec.ECDSA(hash_alg)) + r, s = asym_utils.decode_dss_signature(signature) + fsig = _FragList() + fsig.put_sshstr(ca_type) + fsigblob = _FragList() + fsigblob.put_mpint(r) + fsigblob.put_mpint(s) + fsig.put_sshstr(fsigblob.tobytes()) + f.put_sshstr(fsig.tobytes()) + + else: + assert isinstance(private_key, rsa.RSAPrivateKey) + # Just like Golang, we're going to use SHA512 for RSA + # https://cs.opensource.google/go/x/crypto/+/refs/tags/ + # v0.4.0:ssh/certs.go;l=445 + # RFC 8332 defines SHA256 and 512 as options + fsig = _FragList() + fsig.put_sshstr(_SSH_RSA_SHA512) + signature = private_key.sign( + f.tobytes(), padding.PKCS1v15(), hashes.SHA512() + ) + fsig.put_sshstr(signature) + f.put_sshstr(fsig.tobytes()) + + cert_data = binascii.b2a_base64(f.tobytes()).strip() + # load_ssh_public_identity returns a union, but this is + # guaranteed to be an SSHCertificate, so we cast to make + # mypy happy. + return typing.cast( + SSHCertificate, + load_ssh_public_identity(b"".join([cert_prefix, b" ", cert_data])), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8a8b30f2aa8fc8eefaf368ba16291dcd941a7770 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py @@ -0,0 +1,7 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +class InvalidToken(Exception): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..467f873c2120ae29c0387a82b0f074527eb32415 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..136a62cc86cb842365062dff2504ba45b38d3055 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5e90e915958c868fadaee9c437e56f12f104dc3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py new file mode 100644 index 0000000000000000000000000000000000000000..260822214db9b224b35e5d0e00cedff08093cc05 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py @@ -0,0 +1,91 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import base64 +import typing +from urllib.parse import quote, urlencode + +from cryptography.hazmat.primitives import constant_time, hmac +from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 +from cryptography.hazmat.primitives.twofactor import InvalidToken + +HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512] + + +def _generate_uri( + hotp: "HOTP", + type_name: str, + account_name: str, + issuer: typing.Optional[str], + extra_parameters: typing.List[typing.Tuple[str, int]], +) -> str: + parameters = [ + ("digits", hotp._length), + ("secret", base64.b32encode(hotp._key)), + ("algorithm", hotp._algorithm.name.upper()), + ] + + if issuer is not None: + parameters.append(("issuer", issuer)) + + parameters.extend(extra_parameters) + + label = ( + f"{quote(issuer)}:{quote(account_name)}" + if issuer + else quote(account_name) + ) + return f"otpauth://{type_name}/{label}?{urlencode(parameters)}" + + +class HOTP: + def __init__( + self, + key: bytes, + length: int, + algorithm: HOTPHashTypes, + backend: typing.Any = None, + enforce_key_length: bool = True, + ) -> None: + if len(key) < 16 and enforce_key_length is True: + raise ValueError("Key length has to be at least 128 bits.") + + if not isinstance(length, int): + raise TypeError("Length parameter must be an integer type.") + + if length < 6 or length > 8: + raise ValueError("Length of HOTP has to be between 6 and 8.") + + if not isinstance(algorithm, (SHA1, SHA256, SHA512)): + raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.") + + self._key = key + self._length = length + self._algorithm = algorithm + + def generate(self, counter: int) -> bytes: + truncated_value = self._dynamic_truncate(counter) + hotp = truncated_value % (10**self._length) + return "{0:0{1}}".format(hotp, self._length).encode() + + def verify(self, hotp: bytes, counter: int) -> None: + if not constant_time.bytes_eq(self.generate(counter), hotp): + raise InvalidToken("Supplied HOTP value does not match.") + + def _dynamic_truncate(self, counter: int) -> int: + ctx = hmac.HMAC(self._key, self._algorithm) + ctx.update(counter.to_bytes(length=8, byteorder="big")) + hmac_value = ctx.finalize() + + offset = hmac_value[len(hmac_value) - 1] & 0b1111 + p = hmac_value[offset : offset + 4] + return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF + + def get_provisioning_uri( + self, account_name: str, counter: int, issuer: typing.Optional[str] + ) -> str: + return _generate_uri( + self, "hotp", account_name, issuer, [("counter", int(counter))] + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py new file mode 100644 index 0000000000000000000000000000000000000000..c66fa1de13c9aeb6d17b3cfb3cc2e3658db7bcf2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py @@ -0,0 +1,48 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.hazmat.primitives.twofactor.hotp import ( + HOTP, + HOTPHashTypes, + _generate_uri, +) + + +class TOTP: + def __init__( + self, + key: bytes, + length: int, + algorithm: HOTPHashTypes, + time_step: int, + backend: typing.Any = None, + enforce_key_length: bool = True, + ): + self._time_step = time_step + self._hotp = HOTP( + key, length, algorithm, enforce_key_length=enforce_key_length + ) + + def generate(self, time: typing.Union[int, float]) -> bytes: + counter = int(time / self._time_step) + return self._hotp.generate(counter) + + def verify(self, totp: bytes, time: int) -> None: + if not constant_time.bytes_eq(self.generate(time), totp): + raise InvalidToken("Supplied TOTP value does not match.") + + def get_provisioning_uri( + self, account_name: str, issuer: typing.Optional[str] + ) -> str: + return _generate_uri( + self._hotp, + "totp", + account_name, + issuer, + [("period", int(self._time_step))], + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/py.typed b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1a2d490a25a7b5db0ac6216542dc2934ac3fb46b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/utils.py @@ -0,0 +1,129 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import enum +import sys +import types +import typing +import warnings + + +# We use a UserWarning subclass, instead of DeprecationWarning, because CPython +# decided deprecation warnings should be invisble by default. +class CryptographyDeprecationWarning(UserWarning): + pass + + +# Several APIs were deprecated with no specific end-of-life date because of the +# ubiquity of their use. They should not be removed until we agree on when that +# cycle ends. +DeprecatedIn36 = CryptographyDeprecationWarning +DeprecatedIn37 = CryptographyDeprecationWarning +DeprecatedIn39 = CryptographyDeprecationWarning +DeprecatedIn40 = CryptographyDeprecationWarning + + +def _check_bytes(name: str, value: bytes) -> None: + if not isinstance(value, bytes): + raise TypeError(f"{name} must be bytes") + + +def _check_byteslike(name: str, value: bytes) -> None: + try: + memoryview(value) + except TypeError: + raise TypeError(f"{name} must be bytes-like") + + +def int_to_bytes(integer: int, length: typing.Optional[int] = None) -> bytes: + return integer.to_bytes( + length or (integer.bit_length() + 7) // 8 or 1, "big" + ) + + +def _extract_buffer_length(obj: typing.Any) -> typing.Tuple[int, int]: + from cryptography.hazmat.bindings._rust import _openssl + + buf = _openssl.ffi.from_buffer(obj) + return int(_openssl.ffi.cast("uintptr_t", buf)), len(buf) + + +class InterfaceNotImplemented(Exception): + pass + + +class _DeprecatedValue: + def __init__(self, value: object, message: str, warning_class): + self.value = value + self.message = message + self.warning_class = warning_class + + +class _ModuleWithDeprecations(types.ModuleType): + def __init__(self, module: types.ModuleType): + super().__init__(module.__name__) + self.__dict__["_module"] = module + + def __getattr__(self, attr: str) -> object: + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + obj = obj.value + return obj + + def __setattr__(self, attr: str, value: object) -> None: + setattr(self._module, attr, value) + + def __delattr__(self, attr: str) -> None: + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + + delattr(self._module, attr) + + def __dir__(self) -> typing.Sequence[str]: + return ["_module"] + dir(self._module) + + +def deprecated( + value: object, + module_name: str, + message: str, + warning_class: typing.Type[Warning], + name: typing.Optional[str] = None, +) -> _DeprecatedValue: + module = sys.modules[module_name] + if not isinstance(module, _ModuleWithDeprecations): + sys.modules[module_name] = module = _ModuleWithDeprecations(module) + dv = _DeprecatedValue(value, message, warning_class) + # Maintain backwards compatibility with `name is None` for pyOpenSSL. + if name is not None: + setattr(module, name, dv) + return dv + + +def cached_property(func: typing.Callable) -> property: + cached_name = f"_cached_{func}" + sentinel = object() + + def inner(instance: object): + cache = getattr(instance, cached_name, sentinel) + if cache is not sentinel: + return cache + result = func(instance) + setattr(instance, cached_name, result) + return result + + return property(inner) + + +# Python 3.10 changed representation of enums. We use well-defined object +# representation and string representation from Python 3.9. +class Enum(enum.Enum): + def __repr__(self) -> str: + return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" + + def __str__(self) -> str: + return f"{self.__class__.__name__}.{self._name_}" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ad924ad42dfffe15eba9b3b8e5ffeb5a6f36434e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__init__.py @@ -0,0 +1,250 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.x509 import certificate_transparency +from cryptography.x509.base import ( + Attribute, + AttributeNotFound, + Attributes, + Certificate, + CertificateBuilder, + CertificateRevocationList, + CertificateRevocationListBuilder, + CertificateSigningRequest, + CertificateSigningRequestBuilder, + InvalidVersion, + RevokedCertificate, + RevokedCertificateBuilder, + Version, + load_der_x509_certificate, + load_der_x509_crl, + load_der_x509_csr, + load_pem_x509_certificate, + load_pem_x509_certificates, + load_pem_x509_crl, + load_pem_x509_csr, + random_serial_number, +) +from cryptography.x509.extensions import ( + AccessDescription, + AuthorityInformationAccess, + AuthorityKeyIdentifier, + BasicConstraints, + CertificateIssuer, + CertificatePolicies, + CRLDistributionPoints, + CRLNumber, + CRLReason, + DeltaCRLIndicator, + DistributionPoint, + DuplicateExtension, + ExtendedKeyUsage, + Extension, + ExtensionNotFound, + Extensions, + ExtensionType, + FreshestCRL, + GeneralNames, + InhibitAnyPolicy, + InvalidityDate, + IssuerAlternativeName, + IssuingDistributionPoint, + KeyUsage, + NameConstraints, + NoticeReference, + OCSPNoCheck, + OCSPNonce, + PolicyConstraints, + PolicyInformation, + PrecertificateSignedCertificateTimestamps, + PrecertPoison, + ReasonFlags, + SignedCertificateTimestamps, + SubjectAlternativeName, + SubjectInformationAccess, + SubjectKeyIdentifier, + TLSFeature, + TLSFeatureType, + UnrecognizedExtension, + UserNotice, +) +from cryptography.x509.general_name import ( + DirectoryName, + DNSName, + GeneralName, + IPAddress, + OtherName, + RegisteredID, + RFC822Name, + UniformResourceIdentifier, + UnsupportedGeneralNameType, +) +from cryptography.x509.name import ( + Name, + NameAttribute, + RelativeDistinguishedName, +) +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, + CertificatePoliciesOID, + CRLEntryExtensionOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + SignatureAlgorithmOID, +) + +OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS +OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER +OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS +OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES +OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS +OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE +OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL +OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY +OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME +OID_KEY_USAGE = ExtensionOID.KEY_USAGE +OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS +OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK +OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS +OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS +OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME +OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES +OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS +OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER + +OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1 +OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224 +OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256 +OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1 +OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224 +OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256 +OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384 +OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512 +OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5 +OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1 +OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224 +OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 +OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 +OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 +OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS + +OID_COMMON_NAME = NameOID.COMMON_NAME +OID_COUNTRY_NAME = NameOID.COUNTRY_NAME +OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT +OID_DN_QUALIFIER = NameOID.DN_QUALIFIER +OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS +OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER +OID_GIVEN_NAME = NameOID.GIVEN_NAME +OID_LOCALITY_NAME = NameOID.LOCALITY_NAME +OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME +OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME +OID_PSEUDONYM = NameOID.PSEUDONYM +OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER +OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME +OID_SURNAME = NameOID.SURNAME +OID_TITLE = NameOID.TITLE + +OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH +OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING +OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION +OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING +OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH +OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING + +OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY +OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER +OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE + +OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER +OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON +OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE + +OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS +OID_OCSP = AuthorityInformationAccessOID.OCSP + +__all__ = [ + "certificate_transparency", + "load_pem_x509_certificate", + "load_pem_x509_certificates", + "load_der_x509_certificate", + "load_pem_x509_csr", + "load_der_x509_csr", + "load_pem_x509_crl", + "load_der_x509_crl", + "random_serial_number", + "Attribute", + "AttributeNotFound", + "Attributes", + "InvalidVersion", + "DeltaCRLIndicator", + "DuplicateExtension", + "ExtensionNotFound", + "UnsupportedGeneralNameType", + "NameAttribute", + "Name", + "RelativeDistinguishedName", + "ObjectIdentifier", + "ExtensionType", + "Extensions", + "Extension", + "ExtendedKeyUsage", + "FreshestCRL", + "IssuingDistributionPoint", + "TLSFeature", + "TLSFeatureType", + "OCSPNoCheck", + "BasicConstraints", + "CRLNumber", + "KeyUsage", + "AuthorityInformationAccess", + "SubjectInformationAccess", + "AccessDescription", + "CertificatePolicies", + "PolicyInformation", + "UserNotice", + "NoticeReference", + "SubjectKeyIdentifier", + "NameConstraints", + "CRLDistributionPoints", + "DistributionPoint", + "ReasonFlags", + "InhibitAnyPolicy", + "SubjectAlternativeName", + "IssuerAlternativeName", + "AuthorityKeyIdentifier", + "GeneralNames", + "GeneralName", + "RFC822Name", + "DNSName", + "UniformResourceIdentifier", + "RegisteredID", + "DirectoryName", + "IPAddress", + "OtherName", + "Certificate", + "CertificateRevocationList", + "CertificateRevocationListBuilder", + "CertificateSigningRequest", + "RevokedCertificate", + "RevokedCertificateBuilder", + "CertificateSigningRequestBuilder", + "CertificateBuilder", + "Version", + "OID_CA_ISSUERS", + "OID_OCSP", + "CertificateIssuer", + "CRLReason", + "InvalidityDate", + "UnrecognizedExtension", + "PolicyConstraints", + "PrecertificateSignedCertificateTimestamps", + "PrecertPoison", + "OCSPNonce", + "SignedCertificateTimestamps", + "SignatureAlgorithmOID", + "NameOID", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d815df6c42ba43f6a6eb3c82fb745858ed007ddf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7091007d1add4a4633e2b9fd368fa8f670df1df Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..028979b3ca358bbfcbc5b62901ea79043f45b450 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1996b3bdbcc34aa06b330eb2aaf6c932ae7935a3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7897e3a80d9d7f7ee120becf3401c0d2d137e8cd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8eaf0cf87f58c4a1409cafe461c92ffc71854135 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51e6044d99aaf0d8b0f44984d8ed6a108d8c0069 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b89c0d65f1212790446ed89fc33e90c925e7f054 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/base.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/base.py new file mode 100644 index 0000000000000000000000000000000000000000..35c846d34edab9d9a0a8b7fe3ab4db103122ef8a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/base.py @@ -0,0 +1,1152 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import datetime +import os +import typing + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed448, + ed25519, + rsa, + x448, + x25519, +) +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPrivateKeyTypes, + CertificateIssuerPublicKeyTypes, + CertificatePublicKeyTypes, +) +from cryptography.x509.extensions import ( + Extension, + Extensions, + ExtensionType, + _make_sequence_methods, +) +from cryptography.x509.name import Name, _ASN1Type +from cryptography.x509.oid import ObjectIdentifier + +_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) + +# This must be kept in sync with sign.rs's list of allowable types in +# identify_hash_type +_AllowedHashTypes = typing.Union[ + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, +] + + +class AttributeNotFound(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +def _reject_duplicate_extension( + extension: Extension[ExtensionType], + extensions: typing.List[Extension[ExtensionType]], +) -> None: + # This is quadratic in the number of extensions + for e in extensions: + if e.oid == extension.oid: + raise ValueError("This extension has already been set.") + + +def _reject_duplicate_attribute( + oid: ObjectIdentifier, + attributes: typing.List[ + typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]] + ], +) -> None: + # This is quadratic in the number of attributes + for attr_oid, _, _ in attributes: + if attr_oid == oid: + raise ValueError("This attribute has already been set.") + + +def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: + """Normalizes a datetime to a naive datetime in UTC. + + time -- datetime to normalize. Assumed to be in UTC if not timezone + aware. + """ + if time.tzinfo is not None: + offset = time.utcoffset() + offset = offset if offset else datetime.timedelta() + return time.replace(tzinfo=None) - offset + else: + return time + + +class Attribute: + def __init__( + self, + oid: ObjectIdentifier, + value: bytes, + _type: int = _ASN1Type.UTF8String.value, + ) -> None: + self._oid = oid + self._value = value + self._type = _type + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return f"<Attribute(oid={self.oid}, value={self.value!r})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Attribute): + return NotImplemented + + return ( + self.oid == other.oid + and self.value == other.value + and self._type == other._type + ) + + def __hash__(self) -> int: + return hash((self.oid, self.value, self._type)) + + +class Attributes: + def __init__( + self, + attributes: typing.Iterable[Attribute], + ) -> None: + self._attributes = list(attributes) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes") + + def __repr__(self) -> str: + return f"<Attributes({self._attributes})>" + + def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute: + for attr in self: + if attr.oid == oid: + return attr + + raise AttributeNotFound(f"No {oid} attribute was found", oid) + + +class Version(utils.Enum): + v1 = 0 + v3 = 2 + + +class InvalidVersion(Exception): + def __init__(self, msg: str, parsed_version: int) -> None: + super().__init__(msg) + self.parsed_version = parsed_version + + +class Certificate(metaclass=abc.ABCMeta): + @abc.abstractmethod + def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: + """ + Returns bytes using digest passed. + """ + + @property + @abc.abstractmethod + def serial_number(self) -> int: + """ + Returns certificate serial number + """ + + @property + @abc.abstractmethod + def version(self) -> Version: + """ + Returns the certificate version + """ + + @abc.abstractmethod + def public_key(self) -> CertificatePublicKeyTypes: + """ + Returns the public key + """ + + @property + @abc.abstractmethod + def not_valid_before(self) -> datetime.datetime: + """ + Not before time (represented as UTC datetime) + """ + + @property + @abc.abstractmethod + def not_valid_after(self) -> datetime.datetime: + """ + Not after time (represented as UTC datetime) + """ + + @property + @abc.abstractmethod + def issuer(self) -> Name: + """ + Returns the issuer name object. + """ + + @property + @abc.abstractmethod + def subject(self) -> Name: + """ + Returns the subject name object. + """ + + @property + @abc.abstractmethod + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @property + @abc.abstractmethod + def signature_algorithm_oid(self) -> ObjectIdentifier: + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @property + @abc.abstractmethod + def extensions(self) -> Extensions: + """ + Returns an Extensions object. + """ + + @property + @abc.abstractmethod + def signature(self) -> bytes: + """ + Returns the signature bytes. + """ + + @property + @abc.abstractmethod + def tbs_certificate_bytes(self) -> bytes: + """ + Returns the tbsCertificate payload bytes as defined in RFC 5280. + """ + + @property + @abc.abstractmethod + def tbs_precertificate_bytes(self) -> bytes: + """ + Returns the tbsCertificate payload bytes with the SCT list extension + stripped. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __hash__(self) -> int: + """ + Computes a hash. + """ + + @abc.abstractmethod + def public_bytes(self, encoding: serialization.Encoding) -> bytes: + """ + Serializes the certificate to PEM or DER format. + """ + + @abc.abstractmethod + def verify_directly_issued_by(self, issuer: "Certificate") -> None: + """ + This method verifies that certificate issuer name matches the + issuer subject name and that the certificate is signed by the + issuer's private key. No other validation is performed. + """ + + +# Runtime isinstance checks need this since the rust class is not a subclass. +Certificate.register(rust_x509.Certificate) + + +class RevokedCertificate(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def serial_number(self) -> int: + """ + Returns the serial number of the revoked certificate. + """ + + @property + @abc.abstractmethod + def revocation_date(self) -> datetime.datetime: + """ + Returns the date of when this certificate was revoked. + """ + + @property + @abc.abstractmethod + def extensions(self) -> Extensions: + """ + Returns an Extensions object containing a list of Revoked extensions. + """ + + +# Runtime isinstance checks need this since the rust class is not a subclass. +RevokedCertificate.register(rust_x509.RevokedCertificate) + + +class _RawRevokedCertificate(RevokedCertificate): + def __init__( + self, + serial_number: int, + revocation_date: datetime.datetime, + extensions: Extensions, + ): + self._serial_number = serial_number + self._revocation_date = revocation_date + self._extensions = extensions + + @property + def serial_number(self) -> int: + return self._serial_number + + @property + def revocation_date(self) -> datetime.datetime: + return self._revocation_date + + @property + def extensions(self) -> Extensions: + return self._extensions + + +class CertificateRevocationList(metaclass=abc.ABCMeta): + @abc.abstractmethod + def public_bytes(self, encoding: serialization.Encoding) -> bytes: + """ + Serializes the CRL to PEM or DER format. + """ + + @abc.abstractmethod + def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: + """ + Returns bytes using digest passed. + """ + + @abc.abstractmethod + def get_revoked_certificate_by_serial_number( + self, serial_number: int + ) -> typing.Optional[RevokedCertificate]: + """ + Returns an instance of RevokedCertificate or None if the serial_number + is not in the CRL. + """ + + @property + @abc.abstractmethod + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @property + @abc.abstractmethod + def signature_algorithm_oid(self) -> ObjectIdentifier: + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @property + @abc.abstractmethod + def issuer(self) -> Name: + """ + Returns the X509Name with the issuer of this CRL. + """ + + @property + @abc.abstractmethod + def next_update(self) -> typing.Optional[datetime.datetime]: + """ + Returns the date of next update for this CRL. + """ + + @property + @abc.abstractmethod + def last_update(self) -> datetime.datetime: + """ + Returns the date of last update for this CRL. + """ + + @property + @abc.abstractmethod + def extensions(self) -> Extensions: + """ + Returns an Extensions object containing a list of CRL extensions. + """ + + @property + @abc.abstractmethod + def signature(self) -> bytes: + """ + Returns the signature bytes. + """ + + @property + @abc.abstractmethod + def tbs_certlist_bytes(self) -> bytes: + """ + Returns the tbsCertList payload bytes as defined in RFC 5280. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __len__(self) -> int: + """ + Number of revoked certificates in the CRL. + """ + + @typing.overload + def __getitem__(self, idx: int) -> RevokedCertificate: + ... + + @typing.overload + def __getitem__(self, idx: slice) -> typing.List[RevokedCertificate]: + ... + + @abc.abstractmethod + def __getitem__( + self, idx: typing.Union[int, slice] + ) -> typing.Union[RevokedCertificate, typing.List[RevokedCertificate]]: + """ + Returns a revoked certificate (or slice of revoked certificates). + """ + + @abc.abstractmethod + def __iter__(self) -> typing.Iterator[RevokedCertificate]: + """ + Iterator over the revoked certificates + """ + + @abc.abstractmethod + def is_signature_valid( + self, public_key: CertificateIssuerPublicKeyTypes + ) -> bool: + """ + Verifies signature of revocation list against given public key. + """ + + +CertificateRevocationList.register(rust_x509.CertificateRevocationList) + + +class CertificateSigningRequest(metaclass=abc.ABCMeta): + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __hash__(self) -> int: + """ + Computes a hash. + """ + + @abc.abstractmethod + def public_key(self) -> CertificatePublicKeyTypes: + """ + Returns the public key + """ + + @property + @abc.abstractmethod + def subject(self) -> Name: + """ + Returns the subject name object. + """ + + @property + @abc.abstractmethod + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @property + @abc.abstractmethod + def signature_algorithm_oid(self) -> ObjectIdentifier: + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @property + @abc.abstractmethod + def extensions(self) -> Extensions: + """ + Returns the extensions in the signing request. + """ + + @property + @abc.abstractmethod + def attributes(self) -> Attributes: + """ + Returns an Attributes object. + """ + + @abc.abstractmethod + def public_bytes(self, encoding: serialization.Encoding) -> bytes: + """ + Encodes the request to PEM or DER format. + """ + + @property + @abc.abstractmethod + def signature(self) -> bytes: + """ + Returns the signature bytes. + """ + + @property + @abc.abstractmethod + def tbs_certrequest_bytes(self) -> bytes: + """ + Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC + 2986. + """ + + @property + @abc.abstractmethod + def is_signature_valid(self) -> bool: + """ + Verifies signature of signing request. + """ + + @abc.abstractmethod + def get_attribute_for_oid(self, oid: ObjectIdentifier) -> bytes: + """ + Get the attribute value for a given OID. + """ + + +# Runtime isinstance checks need this since the rust class is not a subclass. +CertificateSigningRequest.register(rust_x509.CertificateSigningRequest) + + +# Backend argument preserved for API compatibility, but ignored. +def load_pem_x509_certificate( + data: bytes, backend: typing.Any = None +) -> Certificate: + return rust_x509.load_pem_x509_certificate(data) + + +def load_pem_x509_certificates(data: bytes) -> typing.List[Certificate]: + return rust_x509.load_pem_x509_certificates(data) + + +# Backend argument preserved for API compatibility, but ignored. +def load_der_x509_certificate( + data: bytes, backend: typing.Any = None +) -> Certificate: + return rust_x509.load_der_x509_certificate(data) + + +# Backend argument preserved for API compatibility, but ignored. +def load_pem_x509_csr( + data: bytes, backend: typing.Any = None +) -> CertificateSigningRequest: + return rust_x509.load_pem_x509_csr(data) + + +# Backend argument preserved for API compatibility, but ignored. +def load_der_x509_csr( + data: bytes, backend: typing.Any = None +) -> CertificateSigningRequest: + return rust_x509.load_der_x509_csr(data) + + +# Backend argument preserved for API compatibility, but ignored. +def load_pem_x509_crl( + data: bytes, backend: typing.Any = None +) -> CertificateRevocationList: + return rust_x509.load_pem_x509_crl(data) + + +# Backend argument preserved for API compatibility, but ignored. +def load_der_x509_crl( + data: bytes, backend: typing.Any = None +) -> CertificateRevocationList: + return rust_x509.load_der_x509_crl(data) + + +class CertificateSigningRequestBuilder: + def __init__( + self, + subject_name: typing.Optional[Name] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + attributes: typing.List[ + typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]] + ] = [], + ): + """ + Creates an empty X.509 certificate request (v1). + """ + self._subject_name = subject_name + self._extensions = extensions + self._attributes = attributes + + def subject_name(self, name: Name) -> "CertificateSigningRequestBuilder": + """ + Sets the certificate requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._subject_name is not None: + raise ValueError("The subject name may only be set once.") + return CertificateSigningRequestBuilder( + name, self._extensions, self._attributes + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateSigningRequestBuilder": + """ + Adds an X.509 extension to the certificate request. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return CertificateSigningRequestBuilder( + self._subject_name, + self._extensions + [extension], + self._attributes, + ) + + def add_attribute( + self, + oid: ObjectIdentifier, + value: bytes, + *, + _tag: typing.Optional[_ASN1Type] = None, + ) -> "CertificateSigningRequestBuilder": + """ + Adds an X.509 attribute with an OID and associated value. + """ + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + + if not isinstance(value, bytes): + raise TypeError("value must be bytes") + + if _tag is not None and not isinstance(_tag, _ASN1Type): + raise TypeError("tag must be _ASN1Type") + + _reject_duplicate_attribute(oid, self._attributes) + + if _tag is not None: + tag = _tag.value + else: + tag = None + + return CertificateSigningRequestBuilder( + self._subject_name, + self._extensions, + self._attributes + [(oid, value, tag)], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: typing.Optional[_AllowedHashTypes], + backend: typing.Any = None, + ) -> CertificateSigningRequest: + """ + Signs the request using the requestor's private key. + """ + if self._subject_name is None: + raise ValueError("A CertificateSigningRequest must have a subject") + return rust_x509.create_x509_csr(self, private_key, algorithm) + + +class CertificateBuilder: + _extensions: typing.List[Extension[ExtensionType]] + + def __init__( + self, + issuer_name: typing.Optional[Name] = None, + subject_name: typing.Optional[Name] = None, + public_key: typing.Optional[CertificatePublicKeyTypes] = None, + serial_number: typing.Optional[int] = None, + not_valid_before: typing.Optional[datetime.datetime] = None, + not_valid_after: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + ) -> None: + self._version = Version.v3 + self._issuer_name = issuer_name + self._subject_name = subject_name + self._public_key = public_key + self._serial_number = serial_number + self._not_valid_before = not_valid_before + self._not_valid_after = not_valid_after + self._extensions = extensions + + def issuer_name(self, name: Name) -> "CertificateBuilder": + """ + Sets the CA's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._issuer_name is not None: + raise ValueError("The issuer name may only be set once.") + return CertificateBuilder( + name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + ) + + def subject_name(self, name: Name) -> "CertificateBuilder": + """ + Sets the requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._subject_name is not None: + raise ValueError("The subject name may only be set once.") + return CertificateBuilder( + self._issuer_name, + name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + ) + + def public_key( + self, + key: CertificatePublicKeyTypes, + ) -> "CertificateBuilder": + """ + Sets the requestor's public key (as found in the signing request). + """ + if not isinstance( + key, + ( + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, + ), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " EllipticCurvePublicKey, Ed25519PublicKey," + " Ed448PublicKey, X25519PublicKey, or " + "X448PublicKey." + ) + if self._public_key is not None: + raise ValueError("The public key may only be set once.") + return CertificateBuilder( + self._issuer_name, + self._subject_name, + key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + ) + + def serial_number(self, number: int) -> "CertificateBuilder": + """ + Sets the certificate serial number. + """ + if not isinstance(number, int): + raise TypeError("Serial number must be of integral type.") + if self._serial_number is not None: + raise ValueError("The serial number may only be set once.") + if number <= 0: + raise ValueError("The serial number should be positive.") + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError( + "The serial number should not be more than 159 " "bits." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + ) + + def not_valid_before( + self, time: datetime.datetime + ) -> "CertificateBuilder": + """ + Sets the certificate activation time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._not_valid_before is not None: + raise ValueError("The not valid before may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The not valid before date must be on or after" + " 1950 January 1)." + ) + if self._not_valid_after is not None and time > self._not_valid_after: + raise ValueError( + "The not valid before date must be before the not valid after " + "date." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + time, + self._not_valid_after, + self._extensions, + ) + + def not_valid_after(self, time: datetime.datetime) -> "CertificateBuilder": + """ + Sets the certificate expiration time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._not_valid_after is not None: + raise ValueError("The not valid after may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The not valid after date must be on or after" + " 1950 January 1." + ) + if ( + self._not_valid_before is not None + and time < self._not_valid_before + ): + raise ValueError( + "The not valid after date must be after the not valid before " + "date." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + time, + self._extensions, + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateBuilder": + """ + Adds an X.509 extension to the certificate. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions + [extension], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: typing.Optional[_AllowedHashTypes], + backend: typing.Any = None, + ) -> Certificate: + """ + Signs the certificate using the CA's private key. + """ + if self._subject_name is None: + raise ValueError("A certificate must have a subject name") + + if self._issuer_name is None: + raise ValueError("A certificate must have an issuer name") + + if self._serial_number is None: + raise ValueError("A certificate must have a serial number") + + if self._not_valid_before is None: + raise ValueError("A certificate must have a not valid before time") + + if self._not_valid_after is None: + raise ValueError("A certificate must have a not valid after time") + + if self._public_key is None: + raise ValueError("A certificate must have a public key") + + return rust_x509.create_x509_certificate(self, private_key, algorithm) + + +class CertificateRevocationListBuilder: + _extensions: typing.List[Extension[ExtensionType]] + _revoked_certificates: typing.List[RevokedCertificate] + + def __init__( + self, + issuer_name: typing.Optional[Name] = None, + last_update: typing.Optional[datetime.datetime] = None, + next_update: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + revoked_certificates: typing.List[RevokedCertificate] = [], + ): + self._issuer_name = issuer_name + self._last_update = last_update + self._next_update = next_update + self._extensions = extensions + self._revoked_certificates = revoked_certificates + + def issuer_name( + self, issuer_name: Name + ) -> "CertificateRevocationListBuilder": + if not isinstance(issuer_name, Name): + raise TypeError("Expecting x509.Name object.") + if self._issuer_name is not None: + raise ValueError("The issuer name may only be set once.") + return CertificateRevocationListBuilder( + issuer_name, + self._last_update, + self._next_update, + self._extensions, + self._revoked_certificates, + ) + + def last_update( + self, last_update: datetime.datetime + ) -> "CertificateRevocationListBuilder": + if not isinstance(last_update, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._last_update is not None: + raise ValueError("Last update may only be set once.") + last_update = _convert_to_naive_utc_time(last_update) + if last_update < _EARLIEST_UTC_TIME: + raise ValueError( + "The last update date must be on or after" " 1950 January 1." + ) + if self._next_update is not None and last_update > self._next_update: + raise ValueError( + "The last update date must be before the next update date." + ) + return CertificateRevocationListBuilder( + self._issuer_name, + last_update, + self._next_update, + self._extensions, + self._revoked_certificates, + ) + + def next_update( + self, next_update: datetime.datetime + ) -> "CertificateRevocationListBuilder": + if not isinstance(next_update, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._next_update is not None: + raise ValueError("Last update may only be set once.") + next_update = _convert_to_naive_utc_time(next_update) + if next_update < _EARLIEST_UTC_TIME: + raise ValueError( + "The last update date must be on or after" " 1950 January 1." + ) + if self._last_update is not None and next_update < self._last_update: + raise ValueError( + "The next update date must be after the last update date." + ) + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + next_update, + self._extensions, + self._revoked_certificates, + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateRevocationListBuilder": + """ + Adds an X.509 extension to the certificate revocation list. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + self._next_update, + self._extensions + [extension], + self._revoked_certificates, + ) + + def add_revoked_certificate( + self, revoked_certificate: RevokedCertificate + ) -> "CertificateRevocationListBuilder": + """ + Adds a revoked certificate to the CRL. + """ + if not isinstance(revoked_certificate, RevokedCertificate): + raise TypeError("Must be an instance of RevokedCertificate") + + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + self._next_update, + self._extensions, + self._revoked_certificates + [revoked_certificate], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: typing.Optional[_AllowedHashTypes], + backend: typing.Any = None, + ) -> CertificateRevocationList: + if self._issuer_name is None: + raise ValueError("A CRL must have an issuer name") + + if self._last_update is None: + raise ValueError("A CRL must have a last update time") + + if self._next_update is None: + raise ValueError("A CRL must have a next update time") + + return rust_x509.create_x509_crl(self, private_key, algorithm) + + +class RevokedCertificateBuilder: + def __init__( + self, + serial_number: typing.Optional[int] = None, + revocation_date: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + ): + self._serial_number = serial_number + self._revocation_date = revocation_date + self._extensions = extensions + + def serial_number(self, number: int) -> "RevokedCertificateBuilder": + if not isinstance(number, int): + raise TypeError("Serial number must be of integral type.") + if self._serial_number is not None: + raise ValueError("The serial number may only be set once.") + if number <= 0: + raise ValueError("The serial number should be positive") + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError( + "The serial number should not be more than 159 " "bits." + ) + return RevokedCertificateBuilder( + number, self._revocation_date, self._extensions + ) + + def revocation_date( + self, time: datetime.datetime + ) -> "RevokedCertificateBuilder": + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._revocation_date is not None: + raise ValueError("The revocation date may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The revocation date must be on or after" " 1950 January 1." + ) + return RevokedCertificateBuilder( + self._serial_number, time, self._extensions + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "RevokedCertificateBuilder": + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + return RevokedCertificateBuilder( + self._serial_number, + self._revocation_date, + self._extensions + [extension], + ) + + def build(self, backend: typing.Any = None) -> RevokedCertificate: + if self._serial_number is None: + raise ValueError("A revoked certificate must have a serial number") + if self._revocation_date is None: + raise ValueError( + "A revoked certificate must have a revocation date" + ) + return _RawRevokedCertificate( + self._serial_number, + self._revocation_date, + Extensions(self._extensions), + ) + + +def random_serial_number() -> int: + return int.from_bytes(os.urandom(20), "big") >> 1 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/certificate_transparency.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/certificate_transparency.py new file mode 100644 index 0000000000000000000000000000000000000000..a67709865d4485dda412e74f56913682965623ce --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/certificate_transparency.py @@ -0,0 +1,96 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import datetime + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.hazmat.primitives.hashes import HashAlgorithm + + +class LogEntryType(utils.Enum): + X509_CERTIFICATE = 0 + PRE_CERTIFICATE = 1 + + +class Version(utils.Enum): + v1 = 0 + + +class SignatureAlgorithm(utils.Enum): + """ + Signature algorithms that are valid for SCTs. + + These are exactly the same as SignatureAlgorithm in RFC 5246 (TLS 1.2). + + See: <https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1> + """ + + ANONYMOUS = 0 + RSA = 1 + DSA = 2 + ECDSA = 3 + + +class SignedCertificateTimestamp(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def version(self) -> Version: + """ + Returns the SCT version. + """ + + @property + @abc.abstractmethod + def log_id(self) -> bytes: + """ + Returns an identifier indicating which log this SCT is for. + """ + + @property + @abc.abstractmethod + def timestamp(self) -> datetime.datetime: + """ + Returns the timestamp for this SCT. + """ + + @property + @abc.abstractmethod + def entry_type(self) -> LogEntryType: + """ + Returns whether this is an SCT for a certificate or pre-certificate. + """ + + @property + @abc.abstractmethod + def signature_hash_algorithm(self) -> HashAlgorithm: + """ + Returns the hash algorithm used for the SCT's signature. + """ + + @property + @abc.abstractmethod + def signature_algorithm(self) -> SignatureAlgorithm: + """ + Returns the signing algorithm used for the SCT's signature. + """ + + @property + @abc.abstractmethod + def signature(self) -> bytes: + """ + Returns the signature for this SCT. + """ + + @property + @abc.abstractmethod + def extension_bytes(self) -> bytes: + """ + Returns the raw bytes of any extensions for this SCT. + """ + + +SignedCertificateTimestamp.register(rust_x509.Sct) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/extensions.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/extensions.py new file mode 100644 index 0000000000000000000000000000000000000000..551887b4a60dab2f02bf6361f2609e4f3e62daff --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/extensions.py @@ -0,0 +1,2126 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import datetime +import hashlib +import ipaddress +import typing + +from cryptography import utils +from cryptography.hazmat.bindings._rust import asn1 +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.hazmat.primitives import constant_time, serialization +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPublicKeyTypes, + CertificatePublicKeyTypes, +) +from cryptography.x509.certificate_transparency import ( + SignedCertificateTimestamp, +) +from cryptography.x509.general_name import ( + DirectoryName, + DNSName, + GeneralName, + IPAddress, + OtherName, + RegisteredID, + RFC822Name, + UniformResourceIdentifier, + _IPAddressTypes, +) +from cryptography.x509.name import Name, RelativeDistinguishedName +from cryptography.x509.oid import ( + CRLEntryExtensionOID, + ExtensionOID, + ObjectIdentifier, + OCSPExtensionOID, +) + +ExtensionTypeVar = typing.TypeVar( + "ExtensionTypeVar", bound="ExtensionType", covariant=True +) + + +def _key_identifier_from_public_key( + public_key: CertificatePublicKeyTypes, +) -> bytes: + if isinstance(public_key, RSAPublicKey): + data = public_key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.PKCS1, + ) + elif isinstance(public_key, EllipticCurvePublicKey): + data = public_key.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + else: + # This is a very slow way to do this. + serialized = public_key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo, + ) + data = asn1.parse_spki_for_data(serialized) + + return hashlib.sha1(data).digest() + + +def _make_sequence_methods(field_name: str): + def len_method(self) -> int: + return len(getattr(self, field_name)) + + def iter_method(self): + return iter(getattr(self, field_name)) + + def getitem_method(self, idx): + return getattr(self, field_name)[idx] + + return len_method, iter_method, getitem_method + + +class DuplicateExtension(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +class ExtensionNotFound(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +class ExtensionType(metaclass=abc.ABCMeta): + oid: typing.ClassVar[ObjectIdentifier] + + def public_bytes(self) -> bytes: + """ + Serializes the extension type to DER. + """ + raise NotImplementedError( + "public_bytes is not implemented for extension type {!r}".format( + self + ) + ) + + +class Extensions: + def __init__( + self, extensions: typing.Iterable["Extension[ExtensionType]"] + ) -> None: + self._extensions = list(extensions) + + def get_extension_for_oid( + self, oid: ObjectIdentifier + ) -> "Extension[ExtensionType]": + for ext in self: + if ext.oid == oid: + return ext + + raise ExtensionNotFound(f"No {oid} extension was found", oid) + + def get_extension_for_class( + self, extclass: typing.Type[ExtensionTypeVar] + ) -> "Extension[ExtensionTypeVar]": + if extclass is UnrecognizedExtension: + raise TypeError( + "UnrecognizedExtension can't be used with " + "get_extension_for_class because more than one instance of the" + " class may be present." + ) + + for ext in self: + if isinstance(ext.value, extclass): + return ext + + raise ExtensionNotFound( + f"No {extclass} extension was found", extclass.oid + ) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") + + def __repr__(self) -> str: + return f"<Extensions({self._extensions})>" + + +class CRLNumber(ExtensionType): + oid = ExtensionOID.CRL_NUMBER + + def __init__(self, crl_number: int) -> None: + if not isinstance(crl_number, int): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLNumber): + return NotImplemented + + return self.crl_number == other.crl_number + + def __hash__(self) -> int: + return hash(self.crl_number) + + def __repr__(self) -> str: + return f"<CRLNumber({self.crl_number})>" + + @property + def crl_number(self) -> int: + return self._crl_number + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AuthorityKeyIdentifier(ExtensionType): + oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER + + def __init__( + self, + key_identifier: typing.Optional[bytes], + authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]], + authority_cert_serial_number: typing.Optional[int], + ) -> None: + if (authority_cert_issuer is None) != ( + authority_cert_serial_number is None + ): + raise ValueError( + "authority_cert_issuer and authority_cert_serial_number " + "must both be present or both None" + ) + + if authority_cert_issuer is not None: + authority_cert_issuer = list(authority_cert_issuer) + if not all( + isinstance(x, GeneralName) for x in authority_cert_issuer + ): + raise TypeError( + "authority_cert_issuer must be a list of GeneralName " + "objects" + ) + + if authority_cert_serial_number is not None and not isinstance( + authority_cert_serial_number, int + ): + raise TypeError("authority_cert_serial_number must be an integer") + + self._key_identifier = key_identifier + self._authority_cert_issuer = authority_cert_issuer + self._authority_cert_serial_number = authority_cert_serial_number + + # This takes a subset of CertificatePublicKeyTypes because an issuer + # cannot have an X25519/X448 key. This introduces some unfortunate + # asymmetry that requires typing users to explicitly + # narrow their type, but we should make this accurate and not just + # convenient. + @classmethod + def from_issuer_public_key( + cls, public_key: CertificateIssuerPublicKeyTypes + ) -> "AuthorityKeyIdentifier": + digest = _key_identifier_from_public_key(public_key) + return cls( + key_identifier=digest, + authority_cert_issuer=None, + authority_cert_serial_number=None, + ) + + @classmethod + def from_issuer_subject_key_identifier( + cls, ski: "SubjectKeyIdentifier" + ) -> "AuthorityKeyIdentifier": + return cls( + key_identifier=ski.digest, + authority_cert_issuer=None, + authority_cert_serial_number=None, + ) + + def __repr__(self) -> str: + return ( + "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " + "authority_cert_issuer={0.authority_cert_issuer}, " + "authority_cert_serial_number={0.authority_cert_serial_number}" + ")>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AuthorityKeyIdentifier): + return NotImplemented + + return ( + self.key_identifier == other.key_identifier + and self.authority_cert_issuer == other.authority_cert_issuer + and self.authority_cert_serial_number + == other.authority_cert_serial_number + ) + + def __hash__(self) -> int: + if self.authority_cert_issuer is None: + aci = None + else: + aci = tuple(self.authority_cert_issuer) + return hash( + (self.key_identifier, aci, self.authority_cert_serial_number) + ) + + @property + def key_identifier(self) -> typing.Optional[bytes]: + return self._key_identifier + + @property + def authority_cert_issuer( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._authority_cert_issuer + + @property + def authority_cert_serial_number(self) -> typing.Optional[int]: + return self._authority_cert_serial_number + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SubjectKeyIdentifier(ExtensionType): + oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER + + def __init__(self, digest: bytes) -> None: + self._digest = digest + + @classmethod + def from_public_key( + cls, public_key: CertificatePublicKeyTypes + ) -> "SubjectKeyIdentifier": + return cls(_key_identifier_from_public_key(public_key)) + + @property + def digest(self) -> bytes: + return self._digest + + @property + def key_identifier(self) -> bytes: + return self._digest + + def __repr__(self) -> str: + return f"<SubjectKeyIdentifier(digest={self.digest!r})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectKeyIdentifier): + return NotImplemented + + return constant_time.bytes_eq(self.digest, other.digest) + + def __hash__(self) -> int: + return hash(self.digest) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AuthorityInformationAccess(ExtensionType): + oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS + + def __init__( + self, descriptions: typing.Iterable["AccessDescription"] + ) -> None: + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") + + def __repr__(self) -> str: + return f"<AuthorityInformationAccess({self._descriptions})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AuthorityInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __hash__(self) -> int: + return hash(tuple(self._descriptions)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SubjectInformationAccess(ExtensionType): + oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS + + def __init__( + self, descriptions: typing.Iterable["AccessDescription"] + ) -> None: + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") + + def __repr__(self) -> str: + return f"<SubjectInformationAccess({self._descriptions})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __hash__(self) -> int: + return hash(tuple(self._descriptions)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AccessDescription: + def __init__( + self, access_method: ObjectIdentifier, access_location: GeneralName + ) -> None: + if not isinstance(access_method, ObjectIdentifier): + raise TypeError("access_method must be an ObjectIdentifier") + + if not isinstance(access_location, GeneralName): + raise TypeError("access_location must be a GeneralName") + + self._access_method = access_method + self._access_location = access_location + + def __repr__(self) -> str: + return ( + "<AccessDescription(access_method={0.access_method}, access_locati" + "on={0.access_location})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AccessDescription): + return NotImplemented + + return ( + self.access_method == other.access_method + and self.access_location == other.access_location + ) + + def __hash__(self) -> int: + return hash((self.access_method, self.access_location)) + + @property + def access_method(self) -> ObjectIdentifier: + return self._access_method + + @property + def access_location(self) -> GeneralName: + return self._access_location + + +class BasicConstraints(ExtensionType): + oid = ExtensionOID.BASIC_CONSTRAINTS + + def __init__(self, ca: bool, path_length: typing.Optional[int]) -> None: + if not isinstance(ca, bool): + raise TypeError("ca must be a boolean value") + + if path_length is not None and not ca: + raise ValueError("path_length must be None when ca is False") + + if path_length is not None and ( + not isinstance(path_length, int) or path_length < 0 + ): + raise TypeError( + "path_length must be a non-negative integer or None" + ) + + self._ca = ca + self._path_length = path_length + + @property + def ca(self) -> bool: + return self._ca + + @property + def path_length(self) -> typing.Optional[int]: + return self._path_length + + def __repr__(self) -> str: + return ( + "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>" + ).format(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BasicConstraints): + return NotImplemented + + return self.ca == other.ca and self.path_length == other.path_length + + def __hash__(self) -> int: + return hash((self.ca, self.path_length)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class DeltaCRLIndicator(ExtensionType): + oid = ExtensionOID.DELTA_CRL_INDICATOR + + def __init__(self, crl_number: int) -> None: + if not isinstance(crl_number, int): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + @property + def crl_number(self) -> int: + return self._crl_number + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DeltaCRLIndicator): + return NotImplemented + + return self.crl_number == other.crl_number + + def __hash__(self) -> int: + return hash(self.crl_number) + + def __repr__(self) -> str: + return f"<DeltaCRLIndicator(crl_number={self.crl_number})>" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CRLDistributionPoints(ExtensionType): + oid = ExtensionOID.CRL_DISTRIBUTION_POINTS + + def __init__( + self, distribution_points: typing.Iterable["DistributionPoint"] + ) -> None: + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) + + def __repr__(self) -> str: + return f"<CRLDistributionPoints({self._distribution_points})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLDistributionPoints): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __hash__(self) -> int: + return hash(tuple(self._distribution_points)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class FreshestCRL(ExtensionType): + oid = ExtensionOID.FRESHEST_CRL + + def __init__( + self, distribution_points: typing.Iterable["DistributionPoint"] + ) -> None: + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) + + def __repr__(self) -> str: + return f"<FreshestCRL({self._distribution_points})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, FreshestCRL): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __hash__(self) -> int: + return hash(tuple(self._distribution_points)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class DistributionPoint: + def __init__( + self, + full_name: typing.Optional[typing.Iterable[GeneralName]], + relative_name: typing.Optional[RelativeDistinguishedName], + reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]], + crl_issuer: typing.Optional[typing.Iterable[GeneralName]], + ) -> None: + if full_name and relative_name: + raise ValueError( + "You cannot provide both full_name and relative_name, at " + "least one must be None." + ) + if not full_name and not relative_name and not crl_issuer: + raise ValueError( + "Either full_name, relative_name or crl_issuer must be " + "provided." + ) + + if full_name is not None: + full_name = list(full_name) + if not all(isinstance(x, GeneralName) for x in full_name): + raise TypeError( + "full_name must be a list of GeneralName objects" + ) + + if relative_name: + if not isinstance(relative_name, RelativeDistinguishedName): + raise TypeError( + "relative_name must be a RelativeDistinguishedName" + ) + + if crl_issuer is not None: + crl_issuer = list(crl_issuer) + if not all(isinstance(x, GeneralName) for x in crl_issuer): + raise TypeError( + "crl_issuer must be None or a list of general names" + ) + + if reasons and ( + not isinstance(reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in reasons) + ): + raise TypeError("reasons must be None or frozenset of ReasonFlags") + + if reasons and ( + ReasonFlags.unspecified in reasons + or ReasonFlags.remove_from_crl in reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in a " + "DistributionPoint" + ) + + self._full_name = full_name + self._relative_name = relative_name + self._reasons = reasons + self._crl_issuer = crl_issuer + + def __repr__(self) -> str: + return ( + "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" + "tive_name}, reasons={0.reasons}, " + "crl_issuer={0.crl_issuer})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.reasons == other.reasons + and self.crl_issuer == other.crl_issuer + ) + + def __hash__(self) -> int: + if self.full_name is not None: + fn: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.full_name + ) + else: + fn = None + + if self.crl_issuer is not None: + crl_issuer: typing.Optional[ + typing.Tuple[GeneralName, ...] + ] = tuple(self.crl_issuer) + else: + crl_issuer = None + + return hash((fn, self.relative_name, self.reasons, crl_issuer)) + + @property + def full_name(self) -> typing.Optional[typing.List[GeneralName]]: + return self._full_name + + @property + def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: + return self._relative_name + + @property + def reasons(self) -> typing.Optional[typing.FrozenSet["ReasonFlags"]]: + return self._reasons + + @property + def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]: + return self._crl_issuer + + +class ReasonFlags(utils.Enum): + unspecified = "unspecified" + key_compromise = "keyCompromise" + ca_compromise = "cACompromise" + affiliation_changed = "affiliationChanged" + superseded = "superseded" + cessation_of_operation = "cessationOfOperation" + certificate_hold = "certificateHold" + privilege_withdrawn = "privilegeWithdrawn" + aa_compromise = "aACompromise" + remove_from_crl = "removeFromCRL" + + +# These are distribution point bit string mappings. Not to be confused with +# CRLReason reason flags bit string mappings. +# ReasonFlags ::= BIT STRING { +# unused (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# privilegeWithdrawn (7), +# aACompromise (8) } +_REASON_BIT_MAPPING = { + 1: ReasonFlags.key_compromise, + 2: ReasonFlags.ca_compromise, + 3: ReasonFlags.affiliation_changed, + 4: ReasonFlags.superseded, + 5: ReasonFlags.cessation_of_operation, + 6: ReasonFlags.certificate_hold, + 7: ReasonFlags.privilege_withdrawn, + 8: ReasonFlags.aa_compromise, +} + +_CRLREASONFLAGS = { + ReasonFlags.key_compromise: 1, + ReasonFlags.ca_compromise: 2, + ReasonFlags.affiliation_changed: 3, + ReasonFlags.superseded: 4, + ReasonFlags.cessation_of_operation: 5, + ReasonFlags.certificate_hold: 6, + ReasonFlags.privilege_withdrawn: 7, + ReasonFlags.aa_compromise: 8, +} + + +class PolicyConstraints(ExtensionType): + oid = ExtensionOID.POLICY_CONSTRAINTS + + def __init__( + self, + require_explicit_policy: typing.Optional[int], + inhibit_policy_mapping: typing.Optional[int], + ) -> None: + if require_explicit_policy is not None and not isinstance( + require_explicit_policy, int + ): + raise TypeError( + "require_explicit_policy must be a non-negative integer or " + "None" + ) + + if inhibit_policy_mapping is not None and not isinstance( + inhibit_policy_mapping, int + ): + raise TypeError( + "inhibit_policy_mapping must be a non-negative integer or None" + ) + + if inhibit_policy_mapping is None and require_explicit_policy is None: + raise ValueError( + "At least one of require_explicit_policy and " + "inhibit_policy_mapping must not be None" + ) + + self._require_explicit_policy = require_explicit_policy + self._inhibit_policy_mapping = inhibit_policy_mapping + + def __repr__(self) -> str: + return ( + "<PolicyConstraints(require_explicit_policy={0.require_explicit" + "_policy}, inhibit_policy_mapping={0.inhibit_policy_" + "mapping})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PolicyConstraints): + return NotImplemented + + return ( + self.require_explicit_policy == other.require_explicit_policy + and self.inhibit_policy_mapping == other.inhibit_policy_mapping + ) + + def __hash__(self) -> int: + return hash( + (self.require_explicit_policy, self.inhibit_policy_mapping) + ) + + @property + def require_explicit_policy(self) -> typing.Optional[int]: + return self._require_explicit_policy + + @property + def inhibit_policy_mapping(self) -> typing.Optional[int]: + return self._inhibit_policy_mapping + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CertificatePolicies(ExtensionType): + oid = ExtensionOID.CERTIFICATE_POLICIES + + def __init__(self, policies: typing.Iterable["PolicyInformation"]) -> None: + policies = list(policies) + if not all(isinstance(x, PolicyInformation) for x in policies): + raise TypeError( + "Every item in the policies list must be a " + "PolicyInformation" + ) + + self._policies = policies + + __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") + + def __repr__(self) -> str: + return f"<CertificatePolicies({self._policies})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CertificatePolicies): + return NotImplemented + + return self._policies == other._policies + + def __hash__(self) -> int: + return hash(tuple(self._policies)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PolicyInformation: + def __init__( + self, + policy_identifier: ObjectIdentifier, + policy_qualifiers: typing.Optional[ + typing.Iterable[typing.Union[str, "UserNotice"]] + ], + ) -> None: + if not isinstance(policy_identifier, ObjectIdentifier): + raise TypeError("policy_identifier must be an ObjectIdentifier") + + self._policy_identifier = policy_identifier + + if policy_qualifiers is not None: + policy_qualifiers = list(policy_qualifiers) + if not all( + isinstance(x, (str, UserNotice)) for x in policy_qualifiers + ): + raise TypeError( + "policy_qualifiers must be a list of strings and/or " + "UserNotice objects or None" + ) + + self._policy_qualifiers = policy_qualifiers + + def __repr__(self) -> str: + return ( + "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" + "y_qualifiers={0.policy_qualifiers})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PolicyInformation): + return NotImplemented + + return ( + self.policy_identifier == other.policy_identifier + and self.policy_qualifiers == other.policy_qualifiers + ) + + def __hash__(self) -> int: + if self.policy_qualifiers is not None: + pq: typing.Optional[ + typing.Tuple[typing.Union[str, "UserNotice"], ...] + ] = tuple(self.policy_qualifiers) + else: + pq = None + + return hash((self.policy_identifier, pq)) + + @property + def policy_identifier(self) -> ObjectIdentifier: + return self._policy_identifier + + @property + def policy_qualifiers( + self, + ) -> typing.Optional[typing.List[typing.Union[str, "UserNotice"]]]: + return self._policy_qualifiers + + +class UserNotice: + def __init__( + self, + notice_reference: typing.Optional["NoticeReference"], + explicit_text: typing.Optional[str], + ) -> None: + if notice_reference and not isinstance( + notice_reference, NoticeReference + ): + raise TypeError( + "notice_reference must be None or a NoticeReference" + ) + + self._notice_reference = notice_reference + self._explicit_text = explicit_text + + def __repr__(self) -> str: + return ( + "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" + "{0.explicit_text!r})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UserNotice): + return NotImplemented + + return ( + self.notice_reference == other.notice_reference + and self.explicit_text == other.explicit_text + ) + + def __hash__(self) -> int: + return hash((self.notice_reference, self.explicit_text)) + + @property + def notice_reference(self) -> typing.Optional["NoticeReference"]: + return self._notice_reference + + @property + def explicit_text(self) -> typing.Optional[str]: + return self._explicit_text + + +class NoticeReference: + def __init__( + self, + organization: typing.Optional[str], + notice_numbers: typing.Iterable[int], + ) -> None: + self._organization = organization + notice_numbers = list(notice_numbers) + if not all(isinstance(x, int) for x in notice_numbers): + raise TypeError("notice_numbers must be a list of integers") + + self._notice_numbers = notice_numbers + + def __repr__(self) -> str: + return ( + "<NoticeReference(organization={0.organization!r}, notice_numbers=" + "{0.notice_numbers})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NoticeReference): + return NotImplemented + + return ( + self.organization == other.organization + and self.notice_numbers == other.notice_numbers + ) + + def __hash__(self) -> int: + return hash((self.organization, tuple(self.notice_numbers))) + + @property + def organization(self) -> typing.Optional[str]: + return self._organization + + @property + def notice_numbers(self) -> typing.List[int]: + return self._notice_numbers + + +class ExtendedKeyUsage(ExtensionType): + oid = ExtensionOID.EXTENDED_KEY_USAGE + + def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None: + usages = list(usages) + if not all(isinstance(x, ObjectIdentifier) for x in usages): + raise TypeError( + "Every item in the usages list must be an ObjectIdentifier" + ) + + self._usages = usages + + __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") + + def __repr__(self) -> str: + return f"<ExtendedKeyUsage({self._usages})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ExtendedKeyUsage): + return NotImplemented + + return self._usages == other._usages + + def __hash__(self) -> int: + return hash(tuple(self._usages)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class OCSPNoCheck(ExtensionType): + oid = ExtensionOID.OCSP_NO_CHECK + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPNoCheck): + return NotImplemented + + return True + + def __hash__(self) -> int: + return hash(OCSPNoCheck) + + def __repr__(self) -> str: + return "<OCSPNoCheck()>" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PrecertPoison(ExtensionType): + oid = ExtensionOID.PRECERT_POISON + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrecertPoison): + return NotImplemented + + return True + + def __hash__(self) -> int: + return hash(PrecertPoison) + + def __repr__(self) -> str: + return "<PrecertPoison()>" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class TLSFeature(ExtensionType): + oid = ExtensionOID.TLS_FEATURE + + def __init__(self, features: typing.Iterable["TLSFeatureType"]) -> None: + features = list(features) + if ( + not all(isinstance(x, TLSFeatureType) for x in features) + or len(features) == 0 + ): + raise TypeError( + "features must be a list of elements from the TLSFeatureType " + "enum" + ) + + self._features = features + + __len__, __iter__, __getitem__ = _make_sequence_methods("_features") + + def __repr__(self) -> str: + return f"<TLSFeature(features={self._features})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TLSFeature): + return NotImplemented + + return self._features == other._features + + def __hash__(self) -> int: + return hash(tuple(self._features)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class TLSFeatureType(utils.Enum): + # status_request is defined in RFC 6066 and is used for what is commonly + # called OCSP Must-Staple when present in the TLS Feature extension in an + # X.509 certificate. + status_request = 5 + # status_request_v2 is defined in RFC 6961 and allows multiple OCSP + # responses to be provided. It is not currently in use by clients or + # servers. + status_request_v2 = 17 + + +_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} + + +class InhibitAnyPolicy(ExtensionType): + oid = ExtensionOID.INHIBIT_ANY_POLICY + + def __init__(self, skip_certs: int) -> None: + if not isinstance(skip_certs, int): + raise TypeError("skip_certs must be an integer") + + if skip_certs < 0: + raise ValueError("skip_certs must be a non-negative integer") + + self._skip_certs = skip_certs + + def __repr__(self) -> str: + return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, InhibitAnyPolicy): + return NotImplemented + + return self.skip_certs == other.skip_certs + + def __hash__(self) -> int: + return hash(self.skip_certs) + + @property + def skip_certs(self) -> int: + return self._skip_certs + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class KeyUsage(ExtensionType): + oid = ExtensionOID.KEY_USAGE + + def __init__( + self, + digital_signature: bool, + content_commitment: bool, + key_encipherment: bool, + data_encipherment: bool, + key_agreement: bool, + key_cert_sign: bool, + crl_sign: bool, + encipher_only: bool, + decipher_only: bool, + ) -> None: + if not key_agreement and (encipher_only or decipher_only): + raise ValueError( + "encipher_only and decipher_only can only be true when " + "key_agreement is true" + ) + + self._digital_signature = digital_signature + self._content_commitment = content_commitment + self._key_encipherment = key_encipherment + self._data_encipherment = data_encipherment + self._key_agreement = key_agreement + self._key_cert_sign = key_cert_sign + self._crl_sign = crl_sign + self._encipher_only = encipher_only + self._decipher_only = decipher_only + + @property + def digital_signature(self) -> bool: + return self._digital_signature + + @property + def content_commitment(self) -> bool: + return self._content_commitment + + @property + def key_encipherment(self) -> bool: + return self._key_encipherment + + @property + def data_encipherment(self) -> bool: + return self._data_encipherment + + @property + def key_agreement(self) -> bool: + return self._key_agreement + + @property + def key_cert_sign(self) -> bool: + return self._key_cert_sign + + @property + def crl_sign(self) -> bool: + return self._crl_sign + + @property + def encipher_only(self) -> bool: + if not self.key_agreement: + raise ValueError( + "encipher_only is undefined unless key_agreement is true" + ) + else: + return self._encipher_only + + @property + def decipher_only(self) -> bool: + if not self.key_agreement: + raise ValueError( + "decipher_only is undefined unless key_agreement is true" + ) + else: + return self._decipher_only + + def __repr__(self) -> str: + try: + encipher_only = self.encipher_only + decipher_only = self.decipher_only + except ValueError: + # Users found None confusing because even though encipher/decipher + # have no meaning unless key_agreement is true, to construct an + # instance of the class you still need to pass False. + encipher_only = False + decipher_only = False + + return ( + "<KeyUsage(digital_signature={0.digital_signature}, " + "content_commitment={0.content_commitment}, " + "key_encipherment={0.key_encipherment}, " + "data_encipherment={0.data_encipherment}, " + "key_agreement={0.key_agreement}, " + "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, " + "encipher_only={1}, decipher_only={2})>" + ).format(self, encipher_only, decipher_only) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, KeyUsage): + return NotImplemented + + return ( + self.digital_signature == other.digital_signature + and self.content_commitment == other.content_commitment + and self.key_encipherment == other.key_encipherment + and self.data_encipherment == other.data_encipherment + and self.key_agreement == other.key_agreement + and self.key_cert_sign == other.key_cert_sign + and self.crl_sign == other.crl_sign + and self._encipher_only == other._encipher_only + and self._decipher_only == other._decipher_only + ) + + def __hash__(self) -> int: + return hash( + ( + self.digital_signature, + self.content_commitment, + self.key_encipherment, + self.data_encipherment, + self.key_agreement, + self.key_cert_sign, + self.crl_sign, + self._encipher_only, + self._decipher_only, + ) + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class NameConstraints(ExtensionType): + oid = ExtensionOID.NAME_CONSTRAINTS + + def __init__( + self, + permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]], + excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]], + ) -> None: + if permitted_subtrees is not None: + permitted_subtrees = list(permitted_subtrees) + if not permitted_subtrees: + raise ValueError( + "permitted_subtrees must be a non-empty list or None" + ) + if not all(isinstance(x, GeneralName) for x in permitted_subtrees): + raise TypeError( + "permitted_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_tree(permitted_subtrees) + + if excluded_subtrees is not None: + excluded_subtrees = list(excluded_subtrees) + if not excluded_subtrees: + raise ValueError( + "excluded_subtrees must be a non-empty list or None" + ) + if not all(isinstance(x, GeneralName) for x in excluded_subtrees): + raise TypeError( + "excluded_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_tree(excluded_subtrees) + + if permitted_subtrees is None and excluded_subtrees is None: + raise ValueError( + "At least one of permitted_subtrees and excluded_subtrees " + "must not be None" + ) + + self._permitted_subtrees = permitted_subtrees + self._excluded_subtrees = excluded_subtrees + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NameConstraints): + return NotImplemented + + return ( + self.excluded_subtrees == other.excluded_subtrees + and self.permitted_subtrees == other.permitted_subtrees + ) + + def _validate_tree(self, tree: typing.Iterable[GeneralName]) -> None: + self._validate_ip_name(tree) + self._validate_dns_name(tree) + + def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None: + if any( + isinstance(name, IPAddress) + and not isinstance( + name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) + ) + for name in tree + ): + raise TypeError( + "IPAddress name constraints must be an IPv4Network or" + " IPv6Network object" + ) + + def _validate_dns_name(self, tree: typing.Iterable[GeneralName]) -> None: + if any( + isinstance(name, DNSName) and "*" in name.value for name in tree + ): + raise ValueError( + "DNSName name constraints must not contain the '*' wildcard" + " character" + ) + + def __repr__(self) -> str: + return ( + "<NameConstraints(permitted_subtrees={0.permitted_subtrees}, " + "excluded_subtrees={0.excluded_subtrees})>".format(self) + ) + + def __hash__(self) -> int: + if self.permitted_subtrees is not None: + ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.permitted_subtrees + ) + else: + ps = None + + if self.excluded_subtrees is not None: + es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.excluded_subtrees + ) + else: + es = None + + return hash((ps, es)) + + @property + def permitted_subtrees( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._permitted_subtrees + + @property + def excluded_subtrees( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._excluded_subtrees + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class Extension(typing.Generic[ExtensionTypeVar]): + def __init__( + self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar + ) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + + if not isinstance(critical, bool): + raise TypeError("critical must be a boolean value") + + self._oid = oid + self._critical = critical + self._value = value + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def critical(self) -> bool: + return self._critical + + @property + def value(self) -> ExtensionTypeVar: + return self._value + + def __repr__(self) -> str: + return ( + "<Extension(oid={0.oid}, critical={0.critical}, " + "value={0.value})>" + ).format(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Extension): + return NotImplemented + + return ( + self.oid == other.oid + and self.critical == other.critical + and self.value == other.value + ) + + def __hash__(self) -> int: + return hash((self.oid, self.critical, self.value)) + + +class GeneralNames: + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + general_names = list(general_names) + if not all(isinstance(x, GeneralName) for x in general_names): + raise TypeError( + "Every item in the general_names list must be an " + "object conforming to the GeneralName interface" + ) + + self._general_names = general_names + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPAddressTypes]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPAddressTypes], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: + # Return the value of each GeneralName, except for OtherName instances + # which we return directly because it has two important properties not + # just one value. + objs = (i for i in self if isinstance(i, type)) + if type != OtherName: + return [i.value for i in objs] + return list(objs) + + def __repr__(self) -> str: + return f"<GeneralNames({self._general_names})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, GeneralNames): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(tuple(self._general_names)) + + +class SubjectAlternativeName(ExtensionType): + oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME + + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPAddressTypes]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPAddressTypes], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"<SubjectAlternativeName({self._general_names})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class IssuerAlternativeName(ExtensionType): + oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME + + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPAddressTypes]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPAddressTypes], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"<IssuerAlternativeName({self._general_names})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IssuerAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CertificateIssuer(ExtensionType): + oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER + + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPAddressTypes]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPAddressTypes], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"<CertificateIssuer({self._general_names})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CertificateIssuer): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CRLReason(ExtensionType): + oid = CRLEntryExtensionOID.CRL_REASON + + def __init__(self, reason: ReasonFlags) -> None: + if not isinstance(reason, ReasonFlags): + raise TypeError("reason must be an element from ReasonFlags") + + self._reason = reason + + def __repr__(self) -> str: + return f"<CRLReason(reason={self._reason})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLReason): + return NotImplemented + + return self.reason == other.reason + + def __hash__(self) -> int: + return hash(self.reason) + + @property + def reason(self) -> ReasonFlags: + return self._reason + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class InvalidityDate(ExtensionType): + oid = CRLEntryExtensionOID.INVALIDITY_DATE + + def __init__(self, invalidity_date: datetime.datetime) -> None: + if not isinstance(invalidity_date, datetime.datetime): + raise TypeError("invalidity_date must be a datetime.datetime") + + self._invalidity_date = invalidity_date + + def __repr__(self) -> str: + return "<InvalidityDate(invalidity_date={})>".format( + self._invalidity_date + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, InvalidityDate): + return NotImplemented + + return self.invalidity_date == other.invalidity_date + + def __hash__(self) -> int: + return hash(self.invalidity_date) + + @property + def invalidity_date(self) -> datetime.datetime: + return self._invalidity_date + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PrecertificateSignedCertificateTimestamps(ExtensionType): + oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__( + self, + signed_certificate_timestamps: typing.Iterable[ + SignedCertificateTimestamp + ], + ) -> None: + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) + + def __repr__(self) -> str: + return "<PrecertificateSignedCertificateTimestamps({})>".format( + list(self) + ) + + def __hash__(self) -> int: + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrecertificateSignedCertificateTimestamps): + return NotImplemented + + return ( + self._signed_certificate_timestamps + == other._signed_certificate_timestamps + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SignedCertificateTimestamps(ExtensionType): + oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__( + self, + signed_certificate_timestamps: typing.Iterable[ + SignedCertificateTimestamp + ], + ) -> None: + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) + + def __repr__(self) -> str: + return f"<SignedCertificateTimestamps({list(self)})>" + + def __hash__(self) -> int: + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SignedCertificateTimestamps): + return NotImplemented + + return ( + self._signed_certificate_timestamps + == other._signed_certificate_timestamps + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class OCSPNonce(ExtensionType): + oid = OCSPExtensionOID.NONCE + + def __init__(self, nonce: bytes) -> None: + if not isinstance(nonce, bytes): + raise TypeError("nonce must be bytes") + + self._nonce = nonce + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPNonce): + return NotImplemented + + return self.nonce == other.nonce + + def __hash__(self) -> int: + return hash(self.nonce) + + def __repr__(self) -> str: + return f"<OCSPNonce(nonce={self.nonce!r})>" + + @property + def nonce(self) -> bytes: + return self._nonce + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class IssuingDistributionPoint(ExtensionType): + oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT + + def __init__( + self, + full_name: typing.Optional[typing.Iterable[GeneralName]], + relative_name: typing.Optional[RelativeDistinguishedName], + only_contains_user_certs: bool, + only_contains_ca_certs: bool, + only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]], + indirect_crl: bool, + only_contains_attribute_certs: bool, + ) -> None: + if full_name is not None: + full_name = list(full_name) + + if only_some_reasons and ( + not isinstance(only_some_reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) + ): + raise TypeError( + "only_some_reasons must be None or frozenset of ReasonFlags" + ) + + if only_some_reasons and ( + ReasonFlags.unspecified in only_some_reasons + or ReasonFlags.remove_from_crl in only_some_reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in an " + "IssuingDistributionPoint" + ) + + if not ( + isinstance(only_contains_user_certs, bool) + and isinstance(only_contains_ca_certs, bool) + and isinstance(indirect_crl, bool) + and isinstance(only_contains_attribute_certs, bool) + ): + raise TypeError( + "only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl and only_contains_attribute_certs " + "must all be boolean." + ) + + crl_constraints = [ + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, + ] + + if len([x for x in crl_constraints if x]) > 1: + raise ValueError( + "Only one of the following can be set to True: " + "only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl, only_contains_attribute_certs" + ) + + if not any( + [ + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, + full_name, + relative_name, + only_some_reasons, + ] + ): + raise ValueError( + "Cannot create empty extension: " + "if only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl, and only_contains_attribute_certs are all False" + ", then either full_name, relative_name, or only_some_reasons " + "must have a value." + ) + + self._only_contains_user_certs = only_contains_user_certs + self._only_contains_ca_certs = only_contains_ca_certs + self._indirect_crl = indirect_crl + self._only_contains_attribute_certs = only_contains_attribute_certs + self._only_some_reasons = only_some_reasons + self._full_name = full_name + self._relative_name = relative_name + + def __repr__(self) -> str: + return ( + "<IssuingDistributionPoint(full_name={0.full_name}, " + "relative_name={0.relative_name}, " + "only_contains_user_certs={0.only_contains_user_certs}, " + "only_contains_ca_certs={0.only_contains_ca_certs}, " + "only_some_reasons={0.only_some_reasons}, " + "indirect_crl={0.indirect_crl}, " + "only_contains_attribute_certs=" + "{0.only_contains_attribute_certs})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IssuingDistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.only_contains_user_certs == other.only_contains_user_certs + and self.only_contains_ca_certs == other.only_contains_ca_certs + and self.only_some_reasons == other.only_some_reasons + and self.indirect_crl == other.indirect_crl + and self.only_contains_attribute_certs + == other.only_contains_attribute_certs + ) + + def __hash__(self) -> int: + return hash( + ( + self.full_name, + self.relative_name, + self.only_contains_user_certs, + self.only_contains_ca_certs, + self.only_some_reasons, + self.indirect_crl, + self.only_contains_attribute_certs, + ) + ) + + @property + def full_name(self) -> typing.Optional[typing.List[GeneralName]]: + return self._full_name + + @property + def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: + return self._relative_name + + @property + def only_contains_user_certs(self) -> bool: + return self._only_contains_user_certs + + @property + def only_contains_ca_certs(self) -> bool: + return self._only_contains_ca_certs + + @property + def only_some_reasons( + self, + ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]: + return self._only_some_reasons + + @property + def indirect_crl(self) -> bool: + return self._indirect_crl + + @property + def only_contains_attribute_certs(self) -> bool: + return self._only_contains_attribute_certs + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class UnrecognizedExtension(ExtensionType): + def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + self._oid = oid + self._value = value + + @property + def oid(self) -> ObjectIdentifier: # type: ignore[override] + return self._oid + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return ( + "<UnrecognizedExtension(oid={0.oid}, " + "value={0.value!r})>".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UnrecognizedExtension): + return NotImplemented + + return self.oid == other.oid and self.value == other.value + + def __hash__(self) -> int: + return hash((self.oid, self.value)) + + def public_bytes(self) -> bytes: + return self.value diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/general_name.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/general_name.py new file mode 100644 index 0000000000000000000000000000000000000000..ce8367b078d1e9ca036e401da08dd4187c28a457 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/general_name.py @@ -0,0 +1,284 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import ipaddress +import typing +from email.utils import parseaddr + +from cryptography.x509.name import Name +from cryptography.x509.oid import ObjectIdentifier + +_IPAddressTypes = typing.Union[ + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, +] + + +class UnsupportedGeneralNameType(Exception): + pass + + +class GeneralName(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def value(self) -> typing.Any: + """ + Return the value of the object + """ + + +class RFC822Name(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "RFC822Name values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + name, address = parseaddr(value) + if name or not address: + # parseaddr has found a name (e.g. Name <email>) or the entire + # value is an empty string. + raise ValueError("Invalid rfc822name value") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation(cls, value: str) -> "RFC822Name": + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"<RFC822Name(value={self.value!r})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RFC822Name): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class DNSName(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "DNSName values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation(cls, value: str) -> "DNSName": + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"<DNSName(value={self.value!r})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DNSName): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class UniformResourceIdentifier(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "URI values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation( + cls, value: str + ) -> "UniformResourceIdentifier": + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"<UniformResourceIdentifier(value={self.value!r})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UniformResourceIdentifier): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class DirectoryName(GeneralName): + def __init__(self, value: Name) -> None: + if not isinstance(value, Name): + raise TypeError("value must be a Name") + + self._value = value + + @property + def value(self) -> Name: + return self._value + + def __repr__(self) -> str: + return f"<DirectoryName(value={self.value})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DirectoryName): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class RegisteredID(GeneralName): + def __init__(self, value: ObjectIdentifier) -> None: + if not isinstance(value, ObjectIdentifier): + raise TypeError("value must be an ObjectIdentifier") + + self._value = value + + @property + def value(self) -> ObjectIdentifier: + return self._value + + def __repr__(self) -> str: + return f"<RegisteredID(value={self.value})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RegisteredID): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class IPAddress(GeneralName): + def __init__(self, value: _IPAddressTypes) -> None: + if not isinstance( + value, + ( + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, + ), + ): + raise TypeError( + "value must be an instance of ipaddress.IPv4Address, " + "ipaddress.IPv6Address, ipaddress.IPv4Network, or " + "ipaddress.IPv6Network" + ) + + self._value = value + + @property + def value(self) -> _IPAddressTypes: + return self._value + + def _packed(self) -> bytes: + if isinstance( + self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) + ): + return self.value.packed + else: + return ( + self.value.network_address.packed + self.value.netmask.packed + ) + + def __repr__(self) -> str: + return f"<IPAddress(value={self.value})>" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IPAddress): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class OtherName(GeneralName): + def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: + if not isinstance(type_id, ObjectIdentifier): + raise TypeError("type_id must be an ObjectIdentifier") + if not isinstance(value, bytes): + raise TypeError("value must be a binary string") + + self._type_id = type_id + self._value = value + + @property + def type_id(self) -> ObjectIdentifier: + return self._type_id + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return "<OtherName(type_id={}, value={!r})>".format( + self.type_id, self.value + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OtherName): + return NotImplemented + + return self.type_id == other.type_id and self.value == other.value + + def __hash__(self) -> int: + return hash((self.type_id, self.value)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/name.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/name.py new file mode 100644 index 0000000000000000000000000000000000000000..fd07820263924a24185242ee2fc34d88535aa6df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/name.py @@ -0,0 +1,460 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import binascii +import re +import sys +import typing +import warnings + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.x509.oid import NameOID, ObjectIdentifier + + +class _ASN1Type(utils.Enum): + BitString = 3 + OctetString = 4 + UTF8String = 12 + NumericString = 18 + PrintableString = 19 + T61String = 20 + IA5String = 22 + UTCTime = 23 + GeneralizedTime = 24 + VisibleString = 26 + UniversalString = 28 + BMPString = 30 + + +_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type} +_NAMEOID_DEFAULT_TYPE: typing.Dict[ObjectIdentifier, _ASN1Type] = { + NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, + NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, + NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, + NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, +} + +# Type alias +_OidNameMap = typing.Mapping[ObjectIdentifier, str] +_NameOidMap = typing.Mapping[str, ObjectIdentifier] + +#: Short attribute names from RFC 4514: +#: https://tools.ietf.org/html/rfc4514#page-7 +_NAMEOID_TO_NAME: _OidNameMap = { + NameOID.COMMON_NAME: "CN", + NameOID.LOCALITY_NAME: "L", + NameOID.STATE_OR_PROVINCE_NAME: "ST", + NameOID.ORGANIZATION_NAME: "O", + NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", + NameOID.COUNTRY_NAME: "C", + NameOID.STREET_ADDRESS: "STREET", + NameOID.DOMAIN_COMPONENT: "DC", + NameOID.USER_ID: "UID", +} +_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()} + + +def _escape_dn_value(val: typing.Union[str, bytes]) -> str: + """Escape special characters in RFC4514 Distinguished Name value.""" + + if not val: + return "" + + # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character + # followed by the hexadecimal encoding of the octets. + if isinstance(val, bytes): + return "#" + binascii.hexlify(val).decode("utf8") + + # See https://tools.ietf.org/html/rfc4514#section-2.4 + val = val.replace("\\", "\\\\") + val = val.replace('"', '\\"') + val = val.replace("+", "\\+") + val = val.replace(",", "\\,") + val = val.replace(";", "\\;") + val = val.replace("<", "\\<") + val = val.replace(">", "\\>") + val = val.replace("\0", "\\00") + + if val[0] in ("#", " "): + val = "\\" + val + if val[-1] == " ": + val = val[:-1] + "\\ " + + return val + + +def _unescape_dn_value(val: str) -> str: + if not val: + return "" + + # See https://tools.ietf.org/html/rfc4514#section-3 + + # special = escaped / SPACE / SHARP / EQUALS + # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE + def sub(m): + val = m.group(1) + # Regular escape + if len(val) == 1: + return val + # Hex-value scape + return chr(int(val, 16)) + + return _RFC4514NameParser._PAIR_RE.sub(sub, val) + + +class NameAttribute: + def __init__( + self, + oid: ObjectIdentifier, + value: typing.Union[str, bytes], + _type: typing.Optional[_ASN1Type] = None, + *, + _validate: bool = True, + ) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + if _type == _ASN1Type.BitString: + if oid != NameOID.X500_UNIQUE_IDENTIFIER: + raise TypeError( + "oid must be X500_UNIQUE_IDENTIFIER for BitString type." + ) + if not isinstance(value, bytes): + raise TypeError("value must be bytes for BitString") + else: + if not isinstance(value, str): + raise TypeError("value argument must be a str") + + if ( + oid == NameOID.COUNTRY_NAME + or oid == NameOID.JURISDICTION_COUNTRY_NAME + ): + assert isinstance(value, str) + c_len = len(value.encode("utf8")) + if c_len != 2 and _validate is True: + raise ValueError( + "Country name must be a 2 character country code" + ) + elif c_len != 2: + warnings.warn( + "Country names should be two characters, but the " + "attribute is {} characters in length.".format(c_len), + stacklevel=2, + ) + + # The appropriate ASN1 string type varies by OID and is defined across + # multiple RFCs including 2459, 3280, and 5280. In general UTF8String + # is preferred (2459), but 3280 and 5280 specify several OIDs with + # alternate types. This means when we see the sentinel value we need + # to look up whether the OID has a non-UTF8 type. If it does, set it + # to that. Otherwise, UTF8! + if _type is None: + _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) + + if not isinstance(_type, _ASN1Type): + raise TypeError("_type must be from the _ASN1Type enum") + + self._oid = oid + self._value = value + self._type = _type + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> typing.Union[str, bytes]: + return self._value + + @property + def rfc4514_attribute_name(self) -> str: + """ + The short attribute name (for example "CN") if available, + otherwise the OID dotted string. + """ + return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) + + def rfc4514_string( + self, attr_name_overrides: typing.Optional[_OidNameMap] = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + + Use short attribute name if available, otherwise fall back to OID + dotted string. + """ + attr_name = ( + attr_name_overrides.get(self.oid) if attr_name_overrides else None + ) + if attr_name is None: + attr_name = self.rfc4514_attribute_name + + return f"{attr_name}={_escape_dn_value(self.value)}" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NameAttribute): + return NotImplemented + + return self.oid == other.oid and self.value == other.value + + def __hash__(self) -> int: + return hash((self.oid, self.value)) + + def __repr__(self) -> str: + return "<NameAttribute(oid={0.oid}, value={0.value!r})>".format(self) + + +class RelativeDistinguishedName: + def __init__(self, attributes: typing.Iterable[NameAttribute]): + attributes = list(attributes) + if not attributes: + raise ValueError("a relative distinguished name cannot be empty") + if not all(isinstance(x, NameAttribute) for x in attributes): + raise TypeError("attributes must be an iterable of NameAttribute") + + # Keep list and frozenset to preserve attribute order where it matters + self._attributes = attributes + self._attribute_set = frozenset(attributes) + + if len(self._attribute_set) != len(attributes): + raise ValueError("duplicate attributes are not allowed") + + def get_attributes_for_oid( + self, oid: ObjectIdentifier + ) -> typing.List[NameAttribute]: + return [i for i in self if i.oid == oid] + + def rfc4514_string( + self, attr_name_overrides: typing.Optional[_OidNameMap] = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + + Within each RDN, attributes are joined by '+', although that is rarely + used in certificates. + """ + return "+".join( + attr.rfc4514_string(attr_name_overrides) + for attr in self._attributes + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RelativeDistinguishedName): + return NotImplemented + + return self._attribute_set == other._attribute_set + + def __hash__(self) -> int: + return hash(self._attribute_set) + + def __iter__(self) -> typing.Iterator[NameAttribute]: + return iter(self._attributes) + + def __len__(self) -> int: + return len(self._attributes) + + def __repr__(self) -> str: + return f"<RelativeDistinguishedName({self.rfc4514_string()})>" + + +class Name: + @typing.overload + def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None: + ... + + @typing.overload + def __init__( + self, attributes: typing.Iterable[RelativeDistinguishedName] + ) -> None: + ... + + def __init__( + self, + attributes: typing.Iterable[ + typing.Union[NameAttribute, RelativeDistinguishedName] + ], + ) -> None: + attributes = list(attributes) + if all(isinstance(x, NameAttribute) for x in attributes): + self._attributes = [ + RelativeDistinguishedName([typing.cast(NameAttribute, x)]) + for x in attributes + ] + elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): + self._attributes = typing.cast( + typing.List[RelativeDistinguishedName], attributes + ) + else: + raise TypeError( + "attributes must be a list of NameAttribute" + " or a list RelativeDistinguishedName" + ) + + @classmethod + def from_rfc4514_string( + cls, + data: str, + attr_name_overrides: typing.Optional[_NameOidMap] = None, + ) -> "Name": + return _RFC4514NameParser(data, attr_name_overrides or {}).parse() + + def rfc4514_string( + self, attr_name_overrides: typing.Optional[_OidNameMap] = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + For example 'CN=foobar.com,O=Foo Corp,C=US' + + An X.509 name is a two-level structure: a list of sets of attributes. + Each list element is separated by ',' and within each list element, set + elements are separated by '+'. The latter is almost never used in + real world certificates. According to RFC4514 section 2.1 the + RDNSequence must be reversed when converting to string representation. + """ + return ",".join( + attr.rfc4514_string(attr_name_overrides) + for attr in reversed(self._attributes) + ) + + def get_attributes_for_oid( + self, oid: ObjectIdentifier + ) -> typing.List[NameAttribute]: + return [i for i in self if i.oid == oid] + + @property + def rdns(self) -> typing.List[RelativeDistinguishedName]: + return self._attributes + + def public_bytes(self, backend: typing.Any = None) -> bytes: + return rust_x509.encode_name_bytes(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Name): + return NotImplemented + + return self._attributes == other._attributes + + def __hash__(self) -> int: + # TODO: this is relatively expensive, if this looks like a bottleneck + # for you, consider optimizing! + return hash(tuple(self._attributes)) + + def __iter__(self) -> typing.Iterator[NameAttribute]: + for rdn in self._attributes: + for ava in rdn: + yield ava + + def __len__(self) -> int: + return sum(len(rdn) for rdn in self._attributes) + + def __repr__(self) -> str: + rdns = ",".join(attr.rfc4514_string() for attr in self._attributes) + return f"<Name({rdns})>" + + +class _RFC4514NameParser: + _OID_RE = re.compile(r"(0|([1-9]\d*))(\.(0|([1-9]\d*)))+") + _DESCR_RE = re.compile(r"[a-zA-Z][a-zA-Z\d-]*") + + _PAIR = r"\\([\\ #=\"\+,;<>]|[\da-zA-Z]{2})" + _PAIR_RE = re.compile(_PAIR) + _LUTF1 = r"[\x01-\x1f\x21\x24-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _SUTF1 = r"[\x01-\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _TUTF1 = r"[\x01-\x1F\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _UTFMB = rf"[\x80-{chr(sys.maxunicode)}]" + _LEADCHAR = rf"{_LUTF1}|{_UTFMB}" + _STRINGCHAR = rf"{_SUTF1}|{_UTFMB}" + _TRAILCHAR = rf"{_TUTF1}|{_UTFMB}" + _STRING_RE = re.compile( + rf""" + ( + ({_LEADCHAR}|{_PAIR}) + ( + ({_STRINGCHAR}|{_PAIR})* + ({_TRAILCHAR}|{_PAIR}) + )? + )? + """, + re.VERBOSE, + ) + _HEXSTRING_RE = re.compile(r"#([\da-zA-Z]{2})+") + + def __init__(self, data: str, attr_name_overrides: _NameOidMap) -> None: + self._data = data + self._idx = 0 + + self._attr_name_overrides = attr_name_overrides + + def _has_data(self) -> bool: + return self._idx < len(self._data) + + def _peek(self) -> typing.Optional[str]: + if self._has_data(): + return self._data[self._idx] + return None + + def _read_char(self, ch: str) -> None: + if self._peek() != ch: + raise ValueError + self._idx += 1 + + def _read_re(self, pat) -> str: + match = pat.match(self._data, pos=self._idx) + if match is None: + raise ValueError + val = match.group() + self._idx += len(val) + return val + + def parse(self) -> Name: + """ + Parses the `data` string and converts it to a Name. + + According to RFC4514 section 2.1 the RDNSequence must be + reversed when converting to string representation. So, when + we parse it, we need to reverse again to get the RDNs on the + correct order. + """ + rdns = [self._parse_rdn()] + + while self._has_data(): + self._read_char(",") + rdns.append(self._parse_rdn()) + + return Name(reversed(rdns)) + + def _parse_rdn(self) -> RelativeDistinguishedName: + nas = [self._parse_na()] + while self._peek() == "+": + self._read_char("+") + nas.append(self._parse_na()) + + return RelativeDistinguishedName(nas) + + def _parse_na(self) -> NameAttribute: + try: + oid_value = self._read_re(self._OID_RE) + except ValueError: + name = self._read_re(self._DESCR_RE) + oid = self._attr_name_overrides.get( + name, _NAME_TO_NAMEOID.get(name) + ) + if oid is None: + raise ValueError + else: + oid = ObjectIdentifier(oid_value) + + self._read_char("=") + if self._peek() == "#": + value = self._read_re(self._HEXSTRING_RE) + value = binascii.unhexlify(value[1:]).decode() + else: + raw_value = self._read_re(self._STRING_RE) + value = _unescape_dn_value(raw_value) + + return NameAttribute(oid, value) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/ocsp.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/ocsp.py new file mode 100644 index 0000000000000000000000000000000000000000..857e75afc191d474a4c95328dc586a0b672be53b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/ocsp.py @@ -0,0 +1,621 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import abc +import datetime +import typing + +from cryptography import utils, x509 +from cryptography.hazmat.bindings._rust import ocsp +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPrivateKeyTypes, +) +from cryptography.x509.base import ( + _EARLIEST_UTC_TIME, + _convert_to_naive_utc_time, + _reject_duplicate_extension, +) + + +class OCSPResponderEncoding(utils.Enum): + HASH = "By Hash" + NAME = "By Name" + + +class OCSPResponseStatus(utils.Enum): + SUCCESSFUL = 0 + MALFORMED_REQUEST = 1 + INTERNAL_ERROR = 2 + TRY_LATER = 3 + SIG_REQUIRED = 5 + UNAUTHORIZED = 6 + + +_ALLOWED_HASHES = ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, +) + + +def _verify_algorithm(algorithm: hashes.HashAlgorithm) -> None: + if not isinstance(algorithm, _ALLOWED_HASHES): + raise ValueError( + "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512" + ) + + +class OCSPCertStatus(utils.Enum): + GOOD = 0 + REVOKED = 1 + UNKNOWN = 2 + + +class _SingleResponse: + def __init__( + self, + cert: x509.Certificate, + issuer: x509.Certificate, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: typing.Optional[datetime.datetime], + revocation_time: typing.Optional[datetime.datetime], + revocation_reason: typing.Optional[x509.ReasonFlags], + ): + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate + ): + raise TypeError("cert and issuer must be a Certificate") + + _verify_algorithm(algorithm) + if not isinstance(this_update, datetime.datetime): + raise TypeError("this_update must be a datetime object") + if next_update is not None and not isinstance( + next_update, datetime.datetime + ): + raise TypeError("next_update must be a datetime object or None") + + self._cert = cert + self._issuer = issuer + self._algorithm = algorithm + self._this_update = this_update + self._next_update = next_update + + if not isinstance(cert_status, OCSPCertStatus): + raise TypeError( + "cert_status must be an item from the OCSPCertStatus enum" + ) + if cert_status is not OCSPCertStatus.REVOKED: + if revocation_time is not None: + raise ValueError( + "revocation_time can only be provided if the certificate " + "is revoked" + ) + if revocation_reason is not None: + raise ValueError( + "revocation_reason can only be provided if the certificate" + " is revoked" + ) + else: + if not isinstance(revocation_time, datetime.datetime): + raise TypeError("revocation_time must be a datetime object") + + revocation_time = _convert_to_naive_utc_time(revocation_time) + if revocation_time < _EARLIEST_UTC_TIME: + raise ValueError( + "The revocation_time must be on or after" + " 1950 January 1." + ) + + if revocation_reason is not None and not isinstance( + revocation_reason, x509.ReasonFlags + ): + raise TypeError( + "revocation_reason must be an item from the ReasonFlags " + "enum or None" + ) + + self._cert_status = cert_status + self._revocation_time = revocation_time + self._revocation_reason = revocation_reason + + +class OCSPRequest(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def issuer_key_hash(self) -> bytes: + """ + The hash of the issuer public key + """ + + @property + @abc.abstractmethod + def issuer_name_hash(self) -> bytes: + """ + The hash of the issuer name + """ + + @property + @abc.abstractmethod + def hash_algorithm(self) -> hashes.HashAlgorithm: + """ + The hash algorithm used in the issuer name and key hashes + """ + + @property + @abc.abstractmethod + def serial_number(self) -> int: + """ + The serial number of the cert whose status is being checked + """ + + @abc.abstractmethod + def public_bytes(self, encoding: serialization.Encoding) -> bytes: + """ + Serializes the request to DER + """ + + @property + @abc.abstractmethod + def extensions(self) -> x509.Extensions: + """ + The list of request extensions. Not single request extensions. + """ + + +class OCSPSingleResponse(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def certificate_status(self) -> OCSPCertStatus: + """ + The status of the certificate (an element from the OCSPCertStatus enum) + """ + + @property + @abc.abstractmethod + def revocation_time(self) -> typing.Optional[datetime.datetime]: + """ + The date of when the certificate was revoked or None if not + revoked. + """ + + @property + @abc.abstractmethod + def revocation_reason(self) -> typing.Optional[x509.ReasonFlags]: + """ + The reason the certificate was revoked or None if not specified or + not revoked. + """ + + @property + @abc.abstractmethod + def this_update(self) -> datetime.datetime: + """ + The most recent time at which the status being indicated is known by + the responder to have been correct + """ + + @property + @abc.abstractmethod + def next_update(self) -> typing.Optional[datetime.datetime]: + """ + The time when newer information will be available + """ + + @property + @abc.abstractmethod + def issuer_key_hash(self) -> bytes: + """ + The hash of the issuer public key + """ + + @property + @abc.abstractmethod + def issuer_name_hash(self) -> bytes: + """ + The hash of the issuer name + """ + + @property + @abc.abstractmethod + def hash_algorithm(self) -> hashes.HashAlgorithm: + """ + The hash algorithm used in the issuer name and key hashes + """ + + @property + @abc.abstractmethod + def serial_number(self) -> int: + """ + The serial number of the cert whose status is being checked + """ + + +class OCSPResponse(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def responses(self) -> typing.Iterator[OCSPSingleResponse]: + """ + An iterator over the individual SINGLERESP structures in the + response + """ + + @property + @abc.abstractmethod + def response_status(self) -> OCSPResponseStatus: + """ + The status of the response. This is a value from the OCSPResponseStatus + enumeration + """ + + @property + @abc.abstractmethod + def signature_algorithm_oid(self) -> x509.ObjectIdentifier: + """ + The ObjectIdentifier of the signature algorithm + """ + + @property + @abc.abstractmethod + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + """ + + @property + @abc.abstractmethod + def signature(self) -> bytes: + """ + The signature bytes + """ + + @property + @abc.abstractmethod + def tbs_response_bytes(self) -> bytes: + """ + The tbsResponseData bytes + """ + + @property + @abc.abstractmethod + def certificates(self) -> typing.List[x509.Certificate]: + """ + A list of certificates used to help build a chain to verify the OCSP + response. This situation occurs when the OCSP responder uses a delegate + certificate. + """ + + @property + @abc.abstractmethod + def responder_key_hash(self) -> typing.Optional[bytes]: + """ + The responder's key hash or None + """ + + @property + @abc.abstractmethod + def responder_name(self) -> typing.Optional[x509.Name]: + """ + The responder's Name or None + """ + + @property + @abc.abstractmethod + def produced_at(self) -> datetime.datetime: + """ + The time the response was produced + """ + + @property + @abc.abstractmethod + def certificate_status(self) -> OCSPCertStatus: + """ + The status of the certificate (an element from the OCSPCertStatus enum) + """ + + @property + @abc.abstractmethod + def revocation_time(self) -> typing.Optional[datetime.datetime]: + """ + The date of when the certificate was revoked or None if not + revoked. + """ + + @property + @abc.abstractmethod + def revocation_reason(self) -> typing.Optional[x509.ReasonFlags]: + """ + The reason the certificate was revoked or None if not specified or + not revoked. + """ + + @property + @abc.abstractmethod + def this_update(self) -> datetime.datetime: + """ + The most recent time at which the status being indicated is known by + the responder to have been correct + """ + + @property + @abc.abstractmethod + def next_update(self) -> typing.Optional[datetime.datetime]: + """ + The time when newer information will be available + """ + + @property + @abc.abstractmethod + def issuer_key_hash(self) -> bytes: + """ + The hash of the issuer public key + """ + + @property + @abc.abstractmethod + def issuer_name_hash(self) -> bytes: + """ + The hash of the issuer name + """ + + @property + @abc.abstractmethod + def hash_algorithm(self) -> hashes.HashAlgorithm: + """ + The hash algorithm used in the issuer name and key hashes + """ + + @property + @abc.abstractmethod + def serial_number(self) -> int: + """ + The serial number of the cert whose status is being checked + """ + + @property + @abc.abstractmethod + def extensions(self) -> x509.Extensions: + """ + The list of response extensions. Not single response extensions. + """ + + @property + @abc.abstractmethod + def single_extensions(self) -> x509.Extensions: + """ + The list of single response extensions. Not response extensions. + """ + + @abc.abstractmethod + def public_bytes(self, encoding: serialization.Encoding) -> bytes: + """ + Serializes the response to DER + """ + + +class OCSPRequestBuilder: + def __init__( + self, + request: typing.Optional[ + typing.Tuple[ + x509.Certificate, x509.Certificate, hashes.HashAlgorithm + ] + ] = None, + request_hash: typing.Optional[ + typing.Tuple[bytes, bytes, int, hashes.HashAlgorithm] + ] = None, + extensions: typing.List[x509.Extension[x509.ExtensionType]] = [], + ) -> None: + self._request = request + self._request_hash = request_hash + self._extensions = extensions + + def add_certificate( + self, + cert: x509.Certificate, + issuer: x509.Certificate, + algorithm: hashes.HashAlgorithm, + ) -> "OCSPRequestBuilder": + if self._request is not None or self._request_hash is not None: + raise ValueError("Only one certificate can be added to a request") + + _verify_algorithm(algorithm) + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate + ): + raise TypeError("cert and issuer must be a Certificate") + + return OCSPRequestBuilder( + (cert, issuer, algorithm), self._request_hash, self._extensions + ) + + def add_certificate_by_hash( + self, + issuer_name_hash: bytes, + issuer_key_hash: bytes, + serial_number: int, + algorithm: hashes.HashAlgorithm, + ) -> "OCSPRequestBuilder": + if self._request is not None or self._request_hash is not None: + raise ValueError("Only one certificate can be added to a request") + + if not isinstance(serial_number, int): + raise TypeError("serial_number must be an integer") + + _verify_algorithm(algorithm) + utils._check_bytes("issuer_name_hash", issuer_name_hash) + utils._check_bytes("issuer_key_hash", issuer_key_hash) + if algorithm.digest_size != len( + issuer_name_hash + ) or algorithm.digest_size != len(issuer_key_hash): + raise ValueError( + "issuer_name_hash and issuer_key_hash must be the same length " + "as the digest size of the algorithm" + ) + + return OCSPRequestBuilder( + self._request, + (issuer_name_hash, issuer_key_hash, serial_number, algorithm), + self._extensions, + ) + + def add_extension( + self, extval: x509.ExtensionType, critical: bool + ) -> "OCSPRequestBuilder": + if not isinstance(extval, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPRequestBuilder( + self._request, self._request_hash, self._extensions + [extension] + ) + + def build(self) -> OCSPRequest: + if self._request is None and self._request_hash is None: + raise ValueError("You must add a certificate before building") + + return ocsp.create_ocsp_request(self) + + +class OCSPResponseBuilder: + def __init__( + self, + response: typing.Optional[_SingleResponse] = None, + responder_id: typing.Optional[ + typing.Tuple[x509.Certificate, OCSPResponderEncoding] + ] = None, + certs: typing.Optional[typing.List[x509.Certificate]] = None, + extensions: typing.List[x509.Extension[x509.ExtensionType]] = [], + ): + self._response = response + self._responder_id = responder_id + self._certs = certs + self._extensions = extensions + + def add_response( + self, + cert: x509.Certificate, + issuer: x509.Certificate, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: typing.Optional[datetime.datetime], + revocation_time: typing.Optional[datetime.datetime], + revocation_reason: typing.Optional[x509.ReasonFlags], + ) -> "OCSPResponseBuilder": + if self._response is not None: + raise ValueError("Only one response per OCSPResponse.") + + singleresp = _SingleResponse( + cert, + issuer, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ) + return OCSPResponseBuilder( + singleresp, + self._responder_id, + self._certs, + self._extensions, + ) + + def responder_id( + self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate + ) -> "OCSPResponseBuilder": + if self._responder_id is not None: + raise ValueError("responder_id can only be set once") + if not isinstance(responder_cert, x509.Certificate): + raise TypeError("responder_cert must be a Certificate") + if not isinstance(encoding, OCSPResponderEncoding): + raise TypeError( + "encoding must be an element from OCSPResponderEncoding" + ) + + return OCSPResponseBuilder( + self._response, + (responder_cert, encoding), + self._certs, + self._extensions, + ) + + def certificates( + self, certs: typing.Iterable[x509.Certificate] + ) -> "OCSPResponseBuilder": + if self._certs is not None: + raise ValueError("certificates may only be set once") + certs = list(certs) + if len(certs) == 0: + raise ValueError("certs must not be an empty list") + if not all(isinstance(x, x509.Certificate) for x in certs): + raise TypeError("certs must be a list of Certificates") + return OCSPResponseBuilder( + self._response, + self._responder_id, + certs, + self._extensions, + ) + + def add_extension( + self, extval: x509.ExtensionType, critical: bool + ) -> "OCSPResponseBuilder": + if not isinstance(extval, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPResponseBuilder( + self._response, + self._responder_id, + self._certs, + self._extensions + [extension], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> OCSPResponse: + if self._response is None: + raise ValueError("You must add a response before signing") + if self._responder_id is None: + raise ValueError("You must add a responder_id before signing") + + return ocsp.create_ocsp_response( + OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm + ) + + @classmethod + def build_unsuccessful( + cls, response_status: OCSPResponseStatus + ) -> OCSPResponse: + if not isinstance(response_status, OCSPResponseStatus): + raise TypeError( + "response_status must be an item from OCSPResponseStatus" + ) + if response_status is OCSPResponseStatus.SUCCESSFUL: + raise ValueError("response_status cannot be SUCCESSFUL") + + return ocsp.create_ocsp_response(response_status, None, None, None) + + +def load_der_ocsp_request(data: bytes) -> OCSPRequest: + return ocsp.load_der_ocsp_request(data) + + +def load_der_ocsp_response(data: bytes) -> OCSPResponse: + return ocsp.load_der_ocsp_response(data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/oid.py b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/oid.py new file mode 100644 index 0000000000000000000000000000000000000000..0d91a54695032faae39257004891a0c14168becf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/cryptography/x509/oid.py @@ -0,0 +1,31 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat._oid import ( + AttributeOID, + AuthorityInformationAccessOID, + CertificatePoliciesOID, + CRLEntryExtensionOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + OCSPExtensionOID, + SignatureAlgorithmOID, + SubjectInformationAccessOID, +) + +__all__ = [ + "AttributeOID", + "AuthorityInformationAccessOID", + "CRLEntryExtensionOID", + "CertificatePoliciesOID", + "ExtendedKeyUsageOID", + "ExtensionOID", + "NameOID", + "OCSPExtensionOID", + "ObjectIdentifier", + "SignatureAlgorithmOID", + "SubjectInformationAccessOID", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..311690c68fe4af37f8136cc05e62e9d51942b46a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/LICENSE @@ -0,0 +1,49 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python +alone or in any derivative version, provided, however, that PSF's +License Agreement and PSF's notice of copyright, i.e., "Copyright (c) +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative +version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..f916e891d0d4cfc97cb9c86817635800e381a682 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/METADATA @@ -0,0 +1,978 @@ +Metadata-Version: 2.1 +Name: defusedxml +Version: 0.7.1 +Summary: XML bomb protection for Python stdlib modules +Home-page: https://github.com/tiran/defusedxml +Author: Christian Heimes +Author-email: christian@python.org +Maintainer: Christian Heimes +Maintainer-email: christian@python.org +License: PSFL +Download-URL: https://pypi.python.org/pypi/defusedxml +Keywords: xml bomb DoS +Platform: all +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: Natural Language :: English +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.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: Topic :: Text Processing :: Markup :: XML +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + +=================================================== +defusedxml -- defusing XML bombs and other exploits +=================================================== + +.. image:: https://img.shields.io/pypi/v/defusedxml.svg + :target: https://pypi.org/project/defusedxml/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/defusedxml.svg + :target: https://pypi.org/project/defusedxml/ + :alt: Supported Python versions + +.. image:: https://travis-ci.org/tiran/defusedxml.svg?branch=master + :target: https://travis-ci.org/tiran/defusedxml + :alt: Travis CI + +.. image:: https://codecov.io/github/tiran/defusedxml/coverage.svg?branch=master + :target: https://codecov.io/github/tiran/defusedxml?branch=master + :alt: codecov + +.. image:: https://img.shields.io/pypi/dm/defusedxml.svg + :target: https://pypistats.org/packages/defusedxml + :alt: PyPI downloads + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: black + +.. + + "It's just XML, what could probably go wrong?" + +Christian Heimes <christian@python.org> + +Synopsis +======== + +The results of an attack on a vulnerable XML library can be fairly dramatic. +With just a few hundred **Bytes** of XML data an attacker can occupy several +**Gigabytes** of memory within **seconds**. An attacker can also keep +CPUs busy for a long time with a small to medium size request. Under some +circumstances it is even possible to access local files on your +server, to circumvent a firewall, or to abuse services to rebound attacks to +third parties. + +The attacks use and abuse less common features of XML and its parsers. The +majority of developers are unacquainted with features such as processing +instructions and entity expansions that XML inherited from SGML. At best +they know about ``<!DOCTYPE>`` from experience with HTML but they are not +aware that a document type definition (DTD) can generate an HTTP request +or load a file from the file system. + +None of the issues is new. They have been known for a long time. Billion +laughs was first reported in 2003. Nevertheless some XML libraries and +applications are still vulnerable and even heavy users of XML are +surprised by these features. It's hard to say whom to blame for the +situation. It's too short sighted to shift all blame on XML parsers and +XML libraries for using insecure default settings. After all they +properly implement XML specifications. Application developers must not rely +that a library is always configured for security and potential harmful data +by default. + + +.. contents:: Table of Contents + :depth: 2 + + +Attack vectors +============== + +billion laughs / exponential entity expansion +--------------------------------------------- + +The `Billion Laughs`_ attack -- also known as exponential entity expansion -- +uses multiple levels of nested entities. The original example uses 9 levels +of 10 expansions in each level to expand the string ``lol`` to a string of +3 * 10 :sup:`9` bytes, hence the name "billion laughs". The resulting string +occupies 3 GB (2.79 GiB) of memory; intermediate strings require additional +memory. Because most parsers don't cache the intermediate step for every +expansion it is repeated over and over again. It increases the CPU load even +more. + +An XML document of just a few hundred bytes can disrupt all services on a +machine within seconds. + +Example XML:: + + <!DOCTYPE xmlbomb [ + <!ENTITY a "1234567890" > + <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;"> + <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;"> + <!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;"> + ]> + <bomb>&d;</bomb> + + +quadratic blowup entity expansion +--------------------------------- + +A quadratic blowup attack is similar to a `Billion Laughs`_ attack; it abuses +entity expansion, too. Instead of nested entities it repeats one large entity +with a couple of thousand chars over and over again. The attack isn't as +efficient as the exponential case but it avoids triggering countermeasures of +parsers against heavily nested entities. Some parsers limit the depth and +breadth of a single entity but not the total amount of expanded text +throughout an entire XML document. + +A medium-sized XML document with a couple of hundred kilobytes can require a +couple of hundred MB to several GB of memory. When the attack is combined +with some level of nested expansion an attacker is able to achieve a higher +ratio of success. + +:: + + <!DOCTYPE bomb [ + <!ENTITY a "xxxxxxx... a couple of ten thousand chars"> + ]> + <bomb>&a;&a;&a;... repeat</bomb> + + +external entity expansion (remote) +---------------------------------- + +Entity declarations can contain more than just text for replacement. They can +also point to external resources by public identifiers or system identifiers. +System identifiers are standard URIs. When the URI is a URL (e.g. a +``http://`` locator) some parsers download the resource from the remote +location and embed them into the XML document verbatim. + +Simple example of a parsed external entity:: + + <!DOCTYPE external [ + <!ENTITY ee SYSTEM "http://www.python.org/some.xml"> + ]> + <root>ⅇ</root> + +The case of parsed external entities works only for valid XML content. The +XML standard also supports unparsed external entities with a +``NData declaration``. + +External entity expansion opens the door to plenty of exploits. An attacker +can abuse a vulnerable XML library and application to rebound and forward +network requests with the IP address of the server. It highly depends +on the parser and the application what kind of exploit is possible. For +example: + +* An attacker can circumvent firewalls and gain access to restricted + resources as all the requests are made from an internal and trustworthy + IP address, not from the outside. +* An attacker can abuse a service to attack, spy on or DoS your servers but + also third party services. The attack is disguised with the IP address of + the server and the attacker is able to utilize the high bandwidth of a big + machine. +* An attacker can exhaust additional resources on the machine, e.g. with + requests to a service that doesn't respond or responds with very large + files. +* An attacker may gain knowledge, when, how often and from which IP address + an XML document is accessed. +* An attacker could send mail from inside your network if the URL handler + supports ``smtp://`` URIs. + + +external entity expansion (local file) +-------------------------------------- + +External entities with references to local files are a sub-case of external +entity expansion. It's listed as an extra attack because it deserves extra +attention. Some XML libraries such as lxml disable network access by default +but still allow entity expansion with local file access by default. Local +files are either referenced with a ``file://`` URL or by a file path (either +relative or absolute). + +An attacker may be able to access and download all files that can be read by +the application process. This may include critical configuration files, too. + +:: + + <!DOCTYPE external [ + <!ENTITY ee SYSTEM "file:///PATH/TO/simple.xml"> + ]> + <root>ⅇ</root> + + +DTD retrieval +------------- + +This case is similar to external entity expansion, too. Some XML libraries +like Python's xml.dom.pulldom retrieve document type definitions from remote +or local locations. Several attack scenarios from the external entity case +apply to this issue as well. + +:: + + <?xml version="1.0" encoding="utf-8"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + <html> + <head/> + <body>text</body> + </html> + + +Python XML Libraries +==================== + +.. csv-table:: vulnerabilities and features + :header: "kind", "sax", "etree", "minidom", "pulldom", "xmlrpc", "lxml", "genshi" + :widths: 24, 7, 8, 8, 7, 8, 8, 8 + :stub-columns: 0 + + "billion laughs", "**True**", "**True**", "**True**", "**True**", "**True**", "False (1)", "False (5)" + "quadratic blowup", "**True**", "**True**", "**True**", "**True**", "**True**", "**True**", "False (5)" + "external entity expansion (remote)", "**True**", "False (3)", "False (4)", "**True**", "false", "False (1)", "False (5)" + "external entity expansion (local file)", "**True**", "False (3)", "False (4)", "**True**", "false", "**True**", "False (5)" + "DTD retrieval", "**True**", "False", "False", "**True**", "false", "False (1)", "False" + "gzip bomb", "False", "False", "False", "False", "**True**", "**partly** (2)", "False" + "xpath support (7)", "False", "False", "False", "False", "False", "**True**", "False" + "xsl(t) support (7)", "False", "False", "False", "False", "False", "**True**", "False" + "xinclude support (7)", "False", "**True** (6)", "False", "False", "False", "**True** (6)", "**True**" + "C library", "expat", "expat", "expat", "expat", "expat", "libxml2", "expat" + +1. Lxml is protected against billion laughs attacks and doesn't do network + lookups by default. +2. libxml2 and lxml are not directly vulnerable to gzip decompression bombs + but they don't protect you against them either. +3. xml.etree doesn't expand entities and raises a ParserError when an entity + occurs. +4. minidom doesn't expand entities and simply returns the unexpanded entity + verbatim. +5. genshi.input of genshi 0.6 doesn't support entity expansion and raises a + ParserError when an entity occurs. +6. Library has (limited) XInclude support but requires an additional step to + process inclusion. +7. These are features but they may introduce exploitable holes, see + `Other things to consider`_ + + +Settings in standard library +---------------------------- + + +xml.sax.handler Features +........................ + +feature_external_ges (http://xml.org/sax/features/external-general-entities) + disables external entity expansion + +feature_external_pes (http://xml.org/sax/features/external-parameter-entities) + the option is ignored and doesn't modify any functionality + +DOM xml.dom.xmlbuilder.Options +.............................. + +external_parameter_entities + ignored + +external_general_entities + ignored + +external_dtd_subset + ignored + +entities + unsure + + +defusedxml +========== + +The `defusedxml package`_ (`defusedxml on PyPI`_) +contains several Python-only workarounds and fixes +for denial of service and other vulnerabilities in Python's XML libraries. +In order to benefit from the protection you just have to import and use the +listed functions / classes from the right defusedxml module instead of the +original module. Merely `defusedxml.xmlrpc`_ is implemented as monkey patch. + +Instead of:: + + >>> from xml.etree.ElementTree import parse + >>> et = parse(xmlfile) + +alter code to:: + + >>> from defusedxml.ElementTree import parse + >>> et = parse(xmlfile) + +Additionally the package has an **untested** function to monkey patch +all stdlib modules with ``defusedxml.defuse_stdlib()``. + +All functions and parser classes accept three additional keyword arguments. +They return either the same objects as the original functions or compatible +subclasses. + +forbid_dtd (default: False) + disallow XML with a ``<!DOCTYPE>`` processing instruction and raise a + *DTDForbidden* exception when a DTD processing instruction is found. + +forbid_entities (default: True) + disallow XML with ``<!ENTITY>`` declarations inside the DTD and raise an + *EntitiesForbidden* exception when an entity is declared. + +forbid_external (default: True) + disallow any access to remote or local resources in external entities + or DTD and raising an *ExternalReferenceForbidden* exception when a DTD + or entity references an external resource. + + +defusedxml (package) +-------------------- + +DefusedXmlException, DTDForbidden, EntitiesForbidden, +ExternalReferenceForbidden, NotSupportedError + +defuse_stdlib() (*experimental*) + + +defusedxml.cElementTree +----------------------- + +**NOTE** ``defusedxml.cElementTree`` is deprecated and will be removed in a +future release. Import from ``defusedxml.ElementTree`` instead. + +parse(), iterparse(), fromstring(), XMLParser + + +defusedxml.ElementTree +----------------------- + +parse(), iterparse(), fromstring(), XMLParser + + +defusedxml.expatreader +---------------------- + +create_parser(), DefusedExpatParser + + +defusedxml.sax +-------------- + +parse(), parseString(), make_parser() + + +defusedxml.expatbuilder +----------------------- + +parse(), parseString(), DefusedExpatBuilder, DefusedExpatBuilderNS + + +defusedxml.minidom +------------------ + +parse(), parseString() + + +defusedxml.pulldom +------------------ + +parse(), parseString() + + +defusedxml.xmlrpc +----------------- + +The fix is implemented as monkey patch for the stdlib's xmlrpc package (3.x) +or xmlrpclib module (2.x). The function `monkey_patch()` enables the fixes, +`unmonkey_patch()` removes the patch and puts the code in its former state. + +The monkey patch protects against XML related attacks as well as +decompression bombs and excessively large requests or responses. The default +setting is 30 MB for requests, responses and gzip decompression. You can +modify the default by changing the module variable `MAX_DATA`. A value of +`-1` disables the limit. + + +defusedxml.lxml +--------------- + +**DEPRECATED** The module is deprecated and will be removed in a future +release. + +The module acts as an *example* how you could protect code that uses +lxml.etree. It implements a custom Element class that filters out +Entity instances, a custom parser factory and a thread local storage for +parser instances. It also has a check_docinfo() function which inspects +a tree for internal or external DTDs and entity declarations. In order to +check for entities lxml > 3.0 is required. + +parse(), fromstring() +RestrictedElement, GlobalParserTLS, getDefaultParser(), check_docinfo() + + +defusedexpat +============ + +The `defusedexpat package`_ (`defusedexpat on PyPI`_) +comes with binary extensions and a +`modified expat`_ library instead of the standard `expat parser`_. It's +basically a stand-alone version of the patches for Python's standard +library C extensions. + +Modifications in expat +---------------------- + +new definitions:: + + XML_BOMB_PROTECTION + XML_DEFAULT_MAX_ENTITY_INDIRECTIONS + XML_DEFAULT_MAX_ENTITY_EXPANSIONS + XML_DEFAULT_RESET_DTD + +new XML_FeatureEnum members:: + + XML_FEATURE_MAX_ENTITY_INDIRECTIONS + XML_FEATURE_MAX_ENTITY_EXPANSIONS + XML_FEATURE_IGNORE_DTD + +new XML_Error members:: + + XML_ERROR_ENTITY_INDIRECTIONS + XML_ERROR_ENTITY_EXPANSION + +new API functions:: + + int XML_GetFeature(XML_Parser parser, + enum XML_FeatureEnum feature, + long *value); + int XML_SetFeature(XML_Parser parser, + enum XML_FeatureEnum feature, + long value); + int XML_GetFeatureDefault(enum XML_FeatureEnum feature, + long *value); + int XML_SetFeatureDefault(enum XML_FeatureEnum feature, + long value); + +XML_FEATURE_MAX_ENTITY_INDIRECTIONS + Limit the amount of indirections that are allowed to occur during the + expansion of a nested entity. A counter starts when an entity reference + is encountered. It resets after the entity is fully expanded. The limit + protects the parser against exponential entity expansion attacks (aka + billion laughs attack). When the limit is exceeded the parser stops and + fails with `XML_ERROR_ENTITY_INDIRECTIONS`. + A value of 0 disables the protection. + + Supported range + 0 .. UINT_MAX + Default + 40 + +XML_FEATURE_MAX_ENTITY_EXPANSIONS + Limit the total length of all entity expansions throughout the entire + document. The lengths of all entities are accumulated in a parser variable. + The setting protects against quadratic blowup attacks (lots of expansions + of a large entity declaration). When the sum of all entities exceeds + the limit, the parser stops and fails with `XML_ERROR_ENTITY_EXPANSION`. + A value of 0 disables the protection. + + Supported range + 0 .. UINT_MAX + Default + 8 MiB + +XML_FEATURE_RESET_DTD + Reset all DTD information after the <!DOCTYPE> block has been parsed. When + the flag is set (default: false) all DTD information after the + endDoctypeDeclHandler has been called. The flag can be set inside the + endDoctypeDeclHandler. Without DTD information any entity reference in + the document body leads to `XML_ERROR_UNDEFINED_ENTITY`. + + Supported range + 0, 1 + Default + 0 + + +How to avoid XML vulnerabilities +================================ + +Best practices +-------------- + +* Don't allow DTDs +* Don't expand entities +* Don't resolve externals +* Limit parse depth +* Limit total input size +* Limit parse time +* Favor a SAX or iterparse-like parser for potential large data +* Validate and properly quote arguments to XSL transformations and + XPath queries +* Don't use XPath expression from untrusted sources +* Don't apply XSL transformations that come untrusted sources + +(based on Brad Hill's `Attacking XML Security`_) + + +Other things to consider +======================== + +XML, XML parsers and processing libraries have more features and possible +issue that could lead to DoS vulnerabilities or security exploits in +applications. I have compiled an incomplete list of theoretical issues that +need further research and more attention. The list is deliberately pessimistic +and a bit paranoid, too. It contains things that might go wrong under daffy +circumstances. + + +attribute blowup / hash collision attack +---------------------------------------- + +XML parsers may use an algorithm with quadratic runtime O(n :sup:`2`) to +handle attributes and namespaces. If it uses hash tables (dictionaries) to +store attributes and namespaces the implementation may be vulnerable to +hash collision attacks, thus reducing the performance to O(n :sup:`2`) again. +In either case an attacker is able to forge a denial of service attack with +an XML document that contains thousands upon thousands of attributes in +a single node. + +I haven't researched yet if expat, pyexpat or libxml2 are vulnerable. + + +decompression bomb +------------------ + +The issue of decompression bombs (aka `ZIP bomb`_) apply to all XML libraries +that can parse compressed XML stream like gzipped HTTP streams or LZMA-ed +files. For an attacker it can reduce the amount of transmitted data by three +magnitudes or more. Gzip is able to compress 1 GiB zeros to roughly 1 MB, +lzma is even better:: + + $ dd if=/dev/zero bs=1M count=1024 | gzip > zeros.gz + $ dd if=/dev/zero bs=1M count=1024 | lzma -z > zeros.xy + $ ls -sh zeros.* + 1020K zeros.gz + 148K zeros.xy + +None of Python's standard XML libraries decompress streams except for +``xmlrpclib``. The module is vulnerable <https://bugs.python.org/issue16043> +to decompression bombs. + +lxml can load and process compressed data through libxml2 transparently. +libxml2 can handle even very large blobs of compressed data efficiently +without using too much memory. But it doesn't protect applications from +decompression bombs. A carefully written SAX or iterparse-like approach can +be safe. + + +Processing Instruction +---------------------- + +`PI`_'s like:: + + <?xml-stylesheet type="text/xsl" href="style.xsl"?> + +may impose more threats for XML processing. It depends if and how a +processor handles processing instructions. The issue of URL retrieval with +network or local file access apply to processing instructions, too. + + +Other DTD features +------------------ + +`DTD`_ has more features like ``<!NOTATION>``. I haven't researched how +these features may be a security threat. + + +XPath +----- + +XPath statements may introduce DoS vulnerabilities. Code should never execute +queries from untrusted sources. An attacker may also be able to create an XML +document that makes certain XPath queries costly or resource hungry. + + +XPath injection attacks +----------------------- + +XPath injeciton attacks pretty much work like SQL injection attacks. +Arguments to XPath queries must be quoted and validated properly, especially +when they are taken from the user. The page `Avoid the dangers of XPath injection`_ +list some ramifications of XPath injections. + +Python's standard library doesn't have XPath support. Lxml supports +parameterized XPath queries which does proper quoting. You just have to use +its xpath() method correctly:: + + # DON'T + >>> tree.xpath("/tag[@id='%s']" % value) + + # instead do + >>> tree.xpath("/tag[@id=$tagid]", tagid=name) + + +XInclude +-------- + +`XML Inclusion`_ is another way to load and include external files:: + + <root xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:include href="filename.txt" parse="text" /> + </root> + +This feature should be disabled when XML files from an untrusted source are +processed. Some Python XML libraries and libxml2 support XInclude but don't +have an option to sandbox inclusion and limit it to allowed directories. + + +XMLSchema location +------------------ + +A validating XML parser may download schema files from the information in a +``xsi:schemaLocation`` attribute. + +:: + + <ead xmlns="urn:isbn:1-931666-22-9" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:isbn:1-931666-22-9 http://www.loc.gov/ead/ead.xsd"> + </ead> + + +XSL Transformation +------------------ + +You should keep in mind that XSLT is a Turing complete language. Never +process XSLT code from unknown or untrusted source! XSLT processors may +allow you to interact with external resources in ways you can't even imagine. +Some processors even support extensions that allow read/write access to file +system, access to JRE objects or scripting with Jython. + +Example from `Attacking XML Security`_ for Xalan-J:: + + <xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" + xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object" + exclude-result-prefixes= "rt ob"> + <xsl:template match="/"> + <xsl:variable name="runtimeObject" select="rt:getRuntime()"/> + <xsl:variable name="command" + select="rt:exec($runtimeObject, 'c:\Windows\system32\cmd.exe')"/> + <xsl:variable name="commandAsString" select="ob:toString($command)"/> + <xsl:value-of select="$commandAsString"/> + </xsl:template> + </xsl:stylesheet> + + +Related CVEs +============ + +CVE-2013-1664 + Unrestricted entity expansion induces DoS vulnerabilities in Python XML + libraries (XML bomb) + +CVE-2013-1665 + External entity expansion in Python XML libraries inflicts potential + security flaws and DoS vulnerabilities + + +Other languages / frameworks +============================= + +Several other programming languages and frameworks are vulnerable as well. A +couple of them are affected by the fact that libxml2 up to 2.9.0 has no +protection against quadratic blowup attacks. Most of them have potential +dangerous default settings for entity expansion and external entities, too. + +Perl +---- + +Perl's XML::Simple is vulnerable to quadratic entity expansion and external +entity expansion (both local and remote). + + +Ruby +---- + +Ruby's REXML document parser is vulnerable to entity expansion attacks +(both quadratic and exponential) but it doesn't do external entity +expansion by default. In order to counteract entity expansion you have to +disable the feature:: + + REXML::Document.entity_expansion_limit = 0 + +libxml-ruby and hpricot don't expand entities in their default configuration. + + +PHP +--- + +PHP's SimpleXML API is vulnerable to quadratic entity expansion and loads +entities from local and remote resources. The option ``LIBXML_NONET`` disables +network access but still allows local file access. ``LIBXML_NOENT`` seems to +have no effect on entity expansion in PHP 5.4.6. + + +C# / .NET / Mono +---------------- + +Information in `XML DoS and Defenses (MSDN)`_ suggest that .NET is +vulnerable with its default settings. The article contains code snippets +how to create a secure XML reader:: + + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ProhibitDtd = false; + settings.MaxCharactersFromEntities = 1024; + settings.XmlResolver = null; + XmlReader reader = XmlReader.Create(stream, settings); + + +Java +---- + +Untested. The documentation of Xerces and its `Xerces SecurityMananger`_ +sounds like Xerces is also vulnerable to billion laugh attacks with its +default settings. It also does entity resolving when an +``org.xml.sax.EntityResolver`` is configured. I'm not yet sure about the +default setting here. + +Java specialists suggest to have a custom builder factory:: + + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setXIncludeAware(False); + builderFactory.setExpandEntityReferences(False); + builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, True); + # either + builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", True); + # or if you need DTDs + builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", False); + builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", False); + builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", False); + builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", False); + + +TODO +==== + +* DOM: Use xml.dom.xmlbuilder options for entity handling +* SAX: take feature_external_ges and feature_external_pes (?) into account +* test experimental monkey patching of stdlib modules +* improve documentation + + +License +======= + +Copyright (c) 2013-2017 by Christian Heimes <christian@python.org> + +Licensed to PSF under a Contributor Agreement. + +See https://www.python.org/psf/license for licensing details. + + +Acknowledgements +================ + +Brett Cannon (Python Core developer) + review and code cleanup + +Antoine Pitrou (Python Core developer) + code review + +Aaron Patterson, Ben Murphy and Michael Koziarski (Ruby community) + Many thanks to Aaron, Ben and Michael from the Ruby community for their + report and assistance. + +Thierry Carrez (OpenStack) + Many thanks to Thierry for his report to the Python Security Response + Team on behalf of the OpenStack security team. + +Carl Meyer (Django) + Many thanks to Carl for his report to PSRT on behalf of the Django security + team. + +Daniel Veillard (libxml2) + Many thanks to Daniel for his insight and assistance with libxml2. + +semantics GmbH (https://www.semantics.de/) + Many thanks to my employer semantics for letting me work on the issue + during working hours as part of semantics's open source initiative. + + +References +========== + +* `XML DoS and Defenses (MSDN)`_ +* `Billion Laughs`_ on Wikipedia +* `ZIP bomb`_ on Wikipedia +* `Configure SAX parsers for secure processing`_ +* `Testing for XML Injection`_ + +.. _defusedxml package: https://github.com/tiran/defusedxml +.. _defusedxml on PyPI: https://pypi.python.org/pypi/defusedxml +.. _defusedexpat package: https://github.com/tiran/defusedexpat +.. _defusedexpat on PyPI: https://pypi.python.org/pypi/defusedexpat +.. _modified expat: https://github.com/tiran/expat +.. _expat parser: http://expat.sourceforge.net/ +.. _Attacking XML Security: https://www.isecpartners.com/media/12976/iSEC-HILL-Attacking-XML-Security-bh07.pdf +.. _Billion Laughs: https://en.wikipedia.org/wiki/Billion_laughs +.. _XML DoS and Defenses (MSDN): https://msdn.microsoft.com/en-us/magazine/ee335713.aspx +.. _ZIP bomb: https://en.wikipedia.org/wiki/Zip_bomb +.. _DTD: https://en.wikipedia.org/wiki/Document_Type_Definition +.. _PI: https://en.wikipedia.org/wiki/Processing_Instruction +.. _Avoid the dangers of XPath injection: http://www.ibm.com/developerworks/xml/library/x-xpathinjection/index.html +.. _Configure SAX parsers for secure processing: http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html +.. _Testing for XML Injection: https://www.owasp.org/index.php/Testing_for_XML_Injection_(OWASP-DV-008) +.. _Xerces SecurityMananger: https://xerces.apache.org/xerces2-j/javadocs/xerces2/org/apache/xerces/util/SecurityManager.html +.. _XML Inclusion: https://www.w3.org/TR/xinclude/#include_element + +Changelog +========= + +defusedxml 0.7.1 +--------------------- + +*Release date: 08-Mar-2021* + +- Fix regression ``defusedxml.ElementTree.ParseError`` (#63) + The ``ParseError`` exception is now the same class object as + ``xml.etree.ElementTree.ParseError`` again. + + +defusedxml 0.7.0 +---------------- + +*Release date: 4-Mar-2021* + +- No changes + + +defusedxml 0.7.0rc2 +------------------- + +*Release date: 12-Jan-2021* + +- Re-add and deprecate ``defusedxml.cElementTree`` +- Use GitHub Actions instead of TravisCI +- Restore ``ElementTree`` attribute of ``xml.etree`` module after patching + +defusedxml 0.7.0rc1 +------------------- + +*Release date: 04-May-2020* + +- Add support for Python 3.9 +- ``defusedxml.cElementTree`` is not available with Python 3.9. +- Python 2 is deprecate. Support for Python 2 will be removed in 0.8.0. + + +defusedxml 0.6.0 +---------------- + +*Release date: 17-Apr-2019* + +- Increase test coverage. +- Add badges to README. + + +defusedxml 0.6.0rc1 +------------------- + +*Release date: 14-Apr-2019* + +- Test on Python 3.7 stable and 3.8-dev +- Drop support for Python 3.4 +- No longer pass *html* argument to XMLParse. It has been deprecated and + ignored for a long time. The DefusedXMLParser still takes a html argument. + A deprecation warning is issued when the argument is False and a TypeError + when it's True. +- defusedxml now fails early when pyexpat stdlib module is not available or + broken. +- defusedxml.ElementTree.__all__ now lists ParseError as public attribute. +- The defusedxml.ElementTree and defusedxml.cElementTree modules had a typo + and used XMLParse instead of XMLParser as an alias for DefusedXMLParser. + Both the old and fixed name are now available. + + +defusedxml 0.5.0 +---------------- + +*Release date: 07-Feb-2017* + +- No changes + + +defusedxml 0.5.0.rc1 +-------------------- + +*Release date: 28-Jan-2017* + +- Add compatibility with Python 3.6 +- Drop support for Python 2.6, 3.1, 3.2, 3.3 +- Fix lxml tests (XMLSyntaxError: Detected an entity reference loop) + + +defusedxml 0.4.1 +---------------- + +*Release date: 28-Mar-2013* + +- Add more demo exploits, e.g. python_external.py and Xalan XSLT demos. +- Improved documentation. + + +defusedxml 0.4 +-------------- + +*Release date: 25-Feb-2013* + +- As per http://seclists.org/oss-sec/2013/q1/340 please REJECT + CVE-2013-0278, CVE-2013-0279 and CVE-2013-0280 and use CVE-2013-1664, + CVE-2013-1665 for OpenStack/etc. +- Add missing parser_list argument to sax.make_parser(). The argument is + ignored, though. (thanks to Florian Apolloner) +- Add demo exploit for external entity attack on Python's SAX parser, XML-RPC + and WebDAV. + + +defusedxml 0.3 +-------------- + +*Release date: 19-Feb-2013* + +- Improve documentation + + +defusedxml 0.2 +-------------- + +*Release date: 15-Feb-2013* + +- Rename ExternalEntitiesForbidden to ExternalReferenceForbidden +- Rename defusedxml.lxml.check_dtd() to check_docinfo() +- Unify argument names in callbacks +- Add arguments and formatted representation to exceptions +- Add forbid_external argument to all functions and classes +- More tests +- LOTS of documentation +- Add example code for other languages (Ruby, Perl, PHP) and parsers (Genshi) +- Add protection against XML and gzip attacks to xmlrpclib + +defusedxml 0.1 +-------------- + +*Release date: 08-Feb-2013* + +- Initial and internal release for PSRT review + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..058176cf81e867bf0029ac47e44a9d749c23d76a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/RECORD @@ -0,0 +1,28 @@ +defusedxml-0.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +defusedxml-0.7.1.dist-info/LICENSE,sha256=uAzp2oxCofkQeWJ_u-K_JyEK4Qig_-Xwd9WwjgdsJMg,2409 +defusedxml-0.7.1.dist-info/METADATA,sha256=Np0872SHDa-En7pxHLjQWn7-PI2asPdjrcNAef43i7E,32518 +defusedxml-0.7.1.dist-info/RECORD,, +defusedxml-0.7.1.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +defusedxml-0.7.1.dist-info/top_level.txt,sha256=QGHa90F50pVKhWSFlERI0jtSKtqDiGyfeZX7dQNZAAw,11 +defusedxml/ElementTree.py,sha256=GLSqpCz58oXGPGyzf_HylsPS9_dcGVP5SN4dK7yvyPw,4640 +defusedxml/__init__.py,sha256=RczeaVJG64p2Fgy1jlCzbuRdchEPnEaCBrxgk8JJ_pM,1444 +defusedxml/__pycache__/ElementTree.cpython-310.pyc,, +defusedxml/__pycache__/__init__.cpython-310.pyc,, +defusedxml/__pycache__/cElementTree.cpython-310.pyc,, +defusedxml/__pycache__/common.cpython-310.pyc,, +defusedxml/__pycache__/expatbuilder.cpython-310.pyc,, +defusedxml/__pycache__/expatreader.cpython-310.pyc,, +defusedxml/__pycache__/lxml.cpython-310.pyc,, +defusedxml/__pycache__/minidom.cpython-310.pyc,, +defusedxml/__pycache__/pulldom.cpython-310.pyc,, +defusedxml/__pycache__/sax.cpython-310.pyc,, +defusedxml/__pycache__/xmlrpc.cpython-310.pyc,, +defusedxml/cElementTree.py,sha256=PpaKMh3rU29sY8amAK4fzHQKl8gcAYD0h1LCoW62Rtk,1449 +defusedxml/common.py,sha256=3d26jNW4fNXzgjWhvUfs83Afiz5EVxFDupQbugkSMZc,4036 +defusedxml/expatbuilder.py,sha256=b4Q05vsBMJ5StkiTFf4my2rGGo1gZyEl_hC5MeFTOAA,3732 +defusedxml/expatreader.py,sha256=KOpSrwkSvj5SGOY9pTXOM26Dnz00rsJt33WueVvzpvc,2196 +defusedxml/lxml.py,sha256=HW-LFKdrfMRzHdi0Vcucq4-n8yz7v_OQwEQWFg1JQYA,4940 +defusedxml/minidom.py,sha256=3QcgygVwJqcWDQ3IZ2iol8zsH4cx3BRX70SPcd0bG2g,1884 +defusedxml/pulldom.py,sha256=DYj2D2lc7xoxZ38gfzujXmdznd8ovzDqGFXqyXbtxjk,1170 +defusedxml/sax.py,sha256=-SF08Msc2mWEYAMw62pJ5FMwWccOctFSnQwDLYLLlVE,1477 +defusedxml/xmlrpc.py,sha256=7rZQey3tqXcc1hrrM3RprOICU6fiFny9B9l4nmTioxA,5364 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..ef99c6cf3283b50a273ac4c6d009a0aa85597070 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..36969f2c4b81b8d563bf352a569328e8c5a75a74 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml-0.7.1.dist-info/top_level.txt @@ -0,0 +1 @@ +defusedxml diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/ElementTree.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/ElementTree.py new file mode 100644 index 0000000000000000000000000000000000000000..5ba765f151349d1feb897aaa95983119a4a1400c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/ElementTree.py @@ -0,0 +1,154 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.etree.ElementTree facade +""" +from __future__ import print_function, absolute_import + +import sys +import warnings +from xml.etree.ElementTree import ParseError +from xml.etree.ElementTree import TreeBuilder as _TreeBuilder +from xml.etree.ElementTree import parse as _parse +from xml.etree.ElementTree import tostring + +from .common import PY3 + +if PY3: + import importlib +else: + from xml.etree.ElementTree import XMLParser as _XMLParser + from xml.etree.ElementTree import iterparse as _iterparse + + +from .common import ( + DTDForbidden, + EntitiesForbidden, + ExternalReferenceForbidden, + _generate_etree_functions, +) + +__origin__ = "xml.etree.ElementTree" + + +def _get_py3_cls(): + """Python 3.3 hides the pure Python code but defusedxml requires it. + + The code is based on test.support.import_fresh_module(). + """ + pymodname = "xml.etree.ElementTree" + cmodname = "_elementtree" + + pymod = sys.modules.pop(pymodname, None) + cmod = sys.modules.pop(cmodname, None) + + sys.modules[cmodname] = None + try: + pure_pymod = importlib.import_module(pymodname) + finally: + # restore module + sys.modules[pymodname] = pymod + if cmod is not None: + sys.modules[cmodname] = cmod + else: + sys.modules.pop(cmodname, None) + # restore attribute on original package + etree_pkg = sys.modules["xml.etree"] + if pymod is not None: + etree_pkg.ElementTree = pymod + elif hasattr(etree_pkg, "ElementTree"): + del etree_pkg.ElementTree + + _XMLParser = pure_pymod.XMLParser + _iterparse = pure_pymod.iterparse + # patch pure module to use ParseError from C extension + pure_pymod.ParseError = ParseError + + return _XMLParser, _iterparse + + +if PY3: + _XMLParser, _iterparse = _get_py3_cls() + + +_sentinel = object() + + +class DefusedXMLParser(_XMLParser): + def __init__( + self, + html=_sentinel, + target=None, + encoding=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): + # Python 2.x old style class + _XMLParser.__init__(self, target=target, encoding=encoding) + if html is not _sentinel: + # the 'html' argument has been deprecated and ignored in all + # supported versions of Python. Python 3.8 finally removed it. + if html: + raise TypeError("'html=True' is no longer supported.") + else: + warnings.warn( + "'html' keyword argument is no longer supported. Pass " + "in arguments as keyword arguments.", + category=DeprecationWarning, + ) + + self.forbid_dtd = forbid_dtd + self.forbid_entities = forbid_entities + self.forbid_external = forbid_external + if PY3: + parser = self.parser + else: + parser = self._parser + if self.forbid_dtd: + parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl + if self.forbid_entities: + parser.EntityDeclHandler = self.defused_entity_decl + parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl + if self.forbid_external: + parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler + + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): + raise DTDForbidden(name, sysid, pubid) + + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): + raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) + + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): + # expat 1.2 + raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover + + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): + raise ExternalReferenceForbidden(context, base, sysid, pubid) + + +# aliases +# XMLParse is a typo, keep it for backwards compatibility +XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser + +parse, iterparse, fromstring = _generate_etree_functions( + DefusedXMLParser, _TreeBuilder, _parse, _iterparse +) +XML = fromstring + + +__all__ = [ + "ParseError", + "XML", + "XMLParse", + "XMLParser", + "XMLTreeBuilder", + "fromstring", + "iterparse", + "parse", + "tostring", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4b5a23009c7f2b29f2bb3766a2143b92b577e728 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__init__.py @@ -0,0 +1,67 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defuse XML bomb denial of service vulnerabilities +""" +from __future__ import print_function, absolute_import + +import warnings + +from .common import ( + DefusedXmlException, + DTDForbidden, + EntitiesForbidden, + ExternalReferenceForbidden, + NotSupportedError, + _apply_defusing, +) + + +def defuse_stdlib(): + """Monkey patch and defuse all stdlib packages + + :warning: The monkey patch is an EXPERIMETNAL feature. + """ + defused = {} + + with warnings.catch_warnings(): + from . import cElementTree + from . import ElementTree + from . import minidom + from . import pulldom + from . import sax + from . import expatbuilder + from . import expatreader + from . import xmlrpc + + xmlrpc.monkey_patch() + defused[xmlrpc] = None + + defused_mods = [ + cElementTree, + ElementTree, + minidom, + pulldom, + sax, + expatbuilder, + expatreader, + ] + + for defused_mod in defused_mods: + stdlib_mod = _apply_defusing(defused_mod) + defused[defused_mod] = stdlib_mod + + return defused + + +__version__ = "0.7.1" + +__all__ = [ + "DefusedXmlException", + "DTDForbidden", + "EntitiesForbidden", + "ExternalReferenceForbidden", + "NotSupportedError", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/ElementTree.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/ElementTree.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae7627dfe4c9c37e94fb36b30c139e403027cb21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/ElementTree.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cdddaba0debf165eb222f9f949188e178fdac1a9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/cElementTree.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/cElementTree.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0f37ee7f2826348a257836b3702d90cf81b91cc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/cElementTree.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/common.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/common.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7846e240bd03d21b8c15d9add97b016b5dbd2299 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/common.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatbuilder.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatbuilder.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..913aaf662c78561c458060ef40db4c05e1bb1703 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatbuilder.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatreader.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatreader.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ada4bc1f42569beda7ca29437ce08935ff4f8f5d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/expatreader.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/lxml.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/lxml.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6ea56c4d65f96bde5c00e5be5d3457e97ba925a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/lxml.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/minidom.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/minidom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52a18fe5e060115aadb6b070ce5b9ae965719060 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/minidom.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/pulldom.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/pulldom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64b132a809f0044c3c55510c581ffd4e7cc7cfab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/pulldom.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/sax.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/sax.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46442009b451c6c608cebe898d8f2ca37502c3d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/sax.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/xmlrpc.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/xmlrpc.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e7729f256974830af87c107266c4e18d165c8a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/__pycache__/xmlrpc.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/cElementTree.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/cElementTree.py new file mode 100644 index 0000000000000000000000000000000000000000..84670c68c0ab70e79d11d2b354ac58ee4b53eb27 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/cElementTree.py @@ -0,0 +1,62 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.etree.cElementTree +""" +from __future__ import absolute_import + +import warnings + +from .common import _generate_etree_functions + +from xml.etree.cElementTree import TreeBuilder as _TreeBuilder +from xml.etree.cElementTree import parse as _parse +from xml.etree.cElementTree import tostring + +# iterparse from ElementTree! +from xml.etree.ElementTree import iterparse as _iterparse + +# This module is an alias for ElementTree just like xml.etree.cElementTree +from .ElementTree import ( + XML, + XMLParse, + XMLParser, + XMLTreeBuilder, + fromstring, + iterparse, + parse, + tostring, + DefusedXMLParser, + ParseError, +) + +__origin__ = "xml.etree.cElementTree" + + +warnings.warn( + "defusedxml.cElementTree is deprecated, import from defusedxml.ElementTree instead.", + category=DeprecationWarning, + stacklevel=2, +) + +# XMLParse is a typo, keep it for backwards compatibility +XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser + +parse, iterparse, fromstring = _generate_etree_functions( + DefusedXMLParser, _TreeBuilder, _parse, _iterparse +) +XML = fromstring + +__all__ = [ + "ParseError", + "XML", + "XMLParse", + "XMLParser", + "XMLTreeBuilder", + "fromstring", + "iterparse", + "parse", + "tostring", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/common.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/common.py new file mode 100644 index 0000000000000000000000000000000000000000..5ceda1fb22f2d159ac8b1b1fd458e4c5bb7d74a6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/common.py @@ -0,0 +1,129 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Common constants, exceptions and helpe functions +""" +import sys +import xml.parsers.expat + +PY3 = sys.version_info[0] == 3 + +# Fail early when pyexpat is not installed correctly +if not hasattr(xml.parsers.expat, "ParserCreate"): + raise ImportError("pyexpat") # pragma: no cover + + +class DefusedXmlException(ValueError): + """Base exception""" + + def __repr__(self): + return str(self) + + +class DTDForbidden(DefusedXmlException): + """Document type definition is forbidden""" + + def __init__(self, name, sysid, pubid): + super(DTDForbidden, self).__init__() + self.name = name + self.sysid = sysid + self.pubid = pubid + + def __str__(self): + tpl = "DTDForbidden(name='{}', system_id={!r}, public_id={!r})" + return tpl.format(self.name, self.sysid, self.pubid) + + +class EntitiesForbidden(DefusedXmlException): + """Entity definition is forbidden""" + + def __init__(self, name, value, base, sysid, pubid, notation_name): + super(EntitiesForbidden, self).__init__() + self.name = name + self.value = value + self.base = base + self.sysid = sysid + self.pubid = pubid + self.notation_name = notation_name + + def __str__(self): + tpl = "EntitiesForbidden(name='{}', system_id={!r}, public_id={!r})" + return tpl.format(self.name, self.sysid, self.pubid) + + +class ExternalReferenceForbidden(DefusedXmlException): + """Resolving an external reference is forbidden""" + + def __init__(self, context, base, sysid, pubid): + super(ExternalReferenceForbidden, self).__init__() + self.context = context + self.base = base + self.sysid = sysid + self.pubid = pubid + + def __str__(self): + tpl = "ExternalReferenceForbidden(system_id='{}', public_id={})" + return tpl.format(self.sysid, self.pubid) + + +class NotSupportedError(DefusedXmlException): + """The operation is not supported""" + + +def _apply_defusing(defused_mod): + assert defused_mod is sys.modules[defused_mod.__name__] + stdlib_name = defused_mod.__origin__ + __import__(stdlib_name, {}, {}, ["*"]) + stdlib_mod = sys.modules[stdlib_name] + stdlib_names = set(dir(stdlib_mod)) + for name, obj in vars(defused_mod).items(): + if name.startswith("_") or name not in stdlib_names: + continue + setattr(stdlib_mod, name, obj) + return stdlib_mod + + +def _generate_etree_functions(DefusedXMLParser, _TreeBuilder, _parse, _iterparse): + """Factory for functions needed by etree, dependent on whether + cElementTree or ElementTree is used.""" + + def parse(source, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True): + if parser is None: + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) + return _parse(source, parser) + + def iterparse( + source, + events=None, + parser=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): + if parser is None: + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) + return _iterparse(source, events, parser) + + def fromstring(text, forbid_dtd=False, forbid_entities=True, forbid_external=True): + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) + parser.feed(text) + return parser.close() + + return parse, iterparse, fromstring diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatbuilder.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatbuilder.py new file mode 100644 index 0000000000000000000000000000000000000000..7bfc57e4f9971426f5e41974cd52940bfc4b1028 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatbuilder.py @@ -0,0 +1,107 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.dom.expatbuilder +""" +from __future__ import print_function, absolute_import + +from xml.dom.expatbuilder import ExpatBuilder as _ExpatBuilder +from xml.dom.expatbuilder import Namespaces as _Namespaces + +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden + +__origin__ = "xml.dom.expatbuilder" + + +class DefusedExpatBuilder(_ExpatBuilder): + """Defused document builder""" + + def __init__( + self, options=None, forbid_dtd=False, forbid_entities=True, forbid_external=True + ): + _ExpatBuilder.__init__(self, options) + self.forbid_dtd = forbid_dtd + self.forbid_entities = forbid_entities + self.forbid_external = forbid_external + + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): + raise DTDForbidden(name, sysid, pubid) + + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): + raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) + + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): + # expat 1.2 + raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover + + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): + raise ExternalReferenceForbidden(context, base, sysid, pubid) + + def install(self, parser): + _ExpatBuilder.install(self, parser) + + if self.forbid_dtd: + parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl + if self.forbid_entities: + # if self._options.entities: + parser.EntityDeclHandler = self.defused_entity_decl + parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl + if self.forbid_external: + parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler + + +class DefusedExpatBuilderNS(_Namespaces, DefusedExpatBuilder): + """Defused document builder that supports namespaces.""" + + def install(self, parser): + DefusedExpatBuilder.install(self, parser) + if self._options.namespace_declarations: + parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler + + def reset(self): + DefusedExpatBuilder.reset(self) + self._initNamespaces() + + +def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True): + """Parse a document, returning the resulting Document node. + + 'file' may be either a file name or an open file object. + """ + if namespaces: + build_builder = DefusedExpatBuilderNS + else: + build_builder = DefusedExpatBuilder + builder = build_builder( + forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external + ) + + if isinstance(file, str): + fp = open(file, "rb") + try: + result = builder.parseFile(fp) + finally: + fp.close() + else: + result = builder.parseFile(file) + return result + + +def parseString( + string, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True +): + """Parse a document from a string, returning the resulting + Document node. + """ + if namespaces: + build_builder = DefusedExpatBuilderNS + else: + build_builder = DefusedExpatBuilder + builder = build_builder( + forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external + ) + return builder.parseString(string) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatreader.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatreader.py new file mode 100644 index 0000000000000000000000000000000000000000..890e1d167e9c4e4bf2d08802c518b27f51c21132 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/expatreader.py @@ -0,0 +1,61 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.sax.expatreader +""" +from __future__ import print_function, absolute_import + +from xml.sax.expatreader import ExpatParser as _ExpatParser + +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden + +__origin__ = "xml.sax.expatreader" + + +class DefusedExpatParser(_ExpatParser): + """Defused SAX driver for the pyexpat C module.""" + + def __init__( + self, + namespaceHandling=0, + bufsize=2 ** 16 - 20, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): + _ExpatParser.__init__(self, namespaceHandling, bufsize) + self.forbid_dtd = forbid_dtd + self.forbid_entities = forbid_entities + self.forbid_external = forbid_external + + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): + raise DTDForbidden(name, sysid, pubid) + + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): + raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) + + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): + # expat 1.2 + raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover + + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): + raise ExternalReferenceForbidden(context, base, sysid, pubid) + + def reset(self): + _ExpatParser.reset(self) + parser = self._parser + if self.forbid_dtd: + parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl + if self.forbid_entities: + parser.EntityDeclHandler = self.defused_entity_decl + parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl + if self.forbid_external: + parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler + + +def create_parser(*args, **kwargs): + return DefusedExpatParser(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/lxml.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/lxml.py new file mode 100644 index 0000000000000000000000000000000000000000..99d5be93f008cbbe3892d42ecb3840dced65e047 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/lxml.py @@ -0,0 +1,153 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""DEPRECATED Example code for lxml.etree protection + +The code has NO protection against decompression bombs. +""" +from __future__ import print_function, absolute_import + +import threading +import warnings + +from lxml import etree as _etree + +from .common import DTDForbidden, EntitiesForbidden, NotSupportedError + +LXML3 = _etree.LXML_VERSION[0] >= 3 + +__origin__ = "lxml.etree" + +tostring = _etree.tostring + + +warnings.warn( + "defusedxml.lxml is no longer supported and will be removed in a future release.", + category=DeprecationWarning, + stacklevel=2, +) + + +class RestrictedElement(_etree.ElementBase): + """A restricted Element class that filters out instances of some classes""" + + __slots__ = () + # blacklist = (etree._Entity, etree._ProcessingInstruction, etree._Comment) + blacklist = _etree._Entity + + def _filter(self, iterator): + blacklist = self.blacklist + for child in iterator: + if isinstance(child, blacklist): + continue + yield child + + def __iter__(self): + iterator = super(RestrictedElement, self).__iter__() + return self._filter(iterator) + + def iterchildren(self, tag=None, reversed=False): + iterator = super(RestrictedElement, self).iterchildren(tag=tag, reversed=reversed) + return self._filter(iterator) + + def iter(self, tag=None, *tags): + iterator = super(RestrictedElement, self).iter(tag=tag, *tags) + return self._filter(iterator) + + def iterdescendants(self, tag=None, *tags): + iterator = super(RestrictedElement, self).iterdescendants(tag=tag, *tags) + return self._filter(iterator) + + def itersiblings(self, tag=None, preceding=False): + iterator = super(RestrictedElement, self).itersiblings(tag=tag, preceding=preceding) + return self._filter(iterator) + + def getchildren(self): + iterator = super(RestrictedElement, self).__iter__() + return list(self._filter(iterator)) + + def getiterator(self, tag=None): + iterator = super(RestrictedElement, self).getiterator(tag) + return self._filter(iterator) + + +class GlobalParserTLS(threading.local): + """Thread local context for custom parser instances""" + + parser_config = { + "resolve_entities": False, + # 'remove_comments': True, + # 'remove_pis': True, + } + + element_class = RestrictedElement + + def createDefaultParser(self): + parser = _etree.XMLParser(**self.parser_config) + element_class = self.element_class + if self.element_class is not None: + lookup = _etree.ElementDefaultClassLookup(element=element_class) + parser.set_element_class_lookup(lookup) + return parser + + def setDefaultParser(self, parser): + self._default_parser = parser + + def getDefaultParser(self): + parser = getattr(self, "_default_parser", None) + if parser is None: + parser = self.createDefaultParser() + self.setDefaultParser(parser) + return parser + + +_parser_tls = GlobalParserTLS() +getDefaultParser = _parser_tls.getDefaultParser + + +def check_docinfo(elementtree, forbid_dtd=False, forbid_entities=True): + """Check docinfo of an element tree for DTD and entity declarations + + The check for entity declarations needs lxml 3 or newer. lxml 2.x does + not support dtd.iterentities(). + """ + docinfo = elementtree.docinfo + if docinfo.doctype: + if forbid_dtd: + raise DTDForbidden(docinfo.doctype, docinfo.system_url, docinfo.public_id) + if forbid_entities and not LXML3: + # lxml < 3 has no iterentities() + raise NotSupportedError("Unable to check for entity declarations " "in lxml 2.x") + + if forbid_entities: + for dtd in docinfo.internalDTD, docinfo.externalDTD: + if dtd is None: + continue + for entity in dtd.iterentities(): + raise EntitiesForbidden(entity.name, entity.content, None, None, None, None) + + +def parse(source, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True): + if parser is None: + parser = getDefaultParser() + elementtree = _etree.parse(source, parser, base_url=base_url) + check_docinfo(elementtree, forbid_dtd, forbid_entities) + return elementtree + + +def fromstring(text, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True): + if parser is None: + parser = getDefaultParser() + rootelement = _etree.fromstring(text, parser, base_url=base_url) + elementtree = rootelement.getroottree() + check_docinfo(elementtree, forbid_dtd, forbid_entities) + return rootelement + + +XML = fromstring + + +def iterparse(*args, **kwargs): + raise NotSupportedError("defused lxml.etree.iterparse not available") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/minidom.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/minidom.py new file mode 100644 index 0000000000000000000000000000000000000000..78033b6cebbcb3bdeedd558f44d0e56fc12a722c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/minidom.py @@ -0,0 +1,63 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.dom.minidom +""" +from __future__ import print_function, absolute_import + +from xml.dom.minidom import _do_pulldom_parse +from . import expatbuilder as _expatbuilder +from . import pulldom as _pulldom + +__origin__ = "xml.dom.minidom" + + +def parse( + file, parser=None, bufsize=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): + """Parse a file into a DOM by filename or file object.""" + if parser is None and not bufsize: + return _expatbuilder.parse( + file, + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) + else: + return _do_pulldom_parse( + _pulldom.parse, + (file,), + { + "parser": parser, + "bufsize": bufsize, + "forbid_dtd": forbid_dtd, + "forbid_entities": forbid_entities, + "forbid_external": forbid_external, + }, + ) + + +def parseString( + string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): + """Parse a file into a DOM from a string.""" + if parser is None: + return _expatbuilder.parseString( + string, + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) + else: + return _do_pulldom_parse( + _pulldom.parseString, + (string,), + { + "parser": parser, + "forbid_dtd": forbid_dtd, + "forbid_entities": forbid_entities, + "forbid_external": forbid_external, + }, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/pulldom.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/pulldom.py new file mode 100644 index 0000000000000000000000000000000000000000..e3b10a467599f09291b22db733115bd0adcbc87e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/pulldom.py @@ -0,0 +1,41 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.dom.pulldom +""" +from __future__ import print_function, absolute_import + +from xml.dom.pulldom import parse as _parse +from xml.dom.pulldom import parseString as _parseString +from .sax import make_parser + +__origin__ = "xml.dom.pulldom" + + +def parse( + stream_or_string, + parser=None, + bufsize=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): + if parser is None: + parser = make_parser() + parser.forbid_dtd = forbid_dtd + parser.forbid_entities = forbid_entities + parser.forbid_external = forbid_external + return _parse(stream_or_string, parser, bufsize) + + +def parseString( + string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): + if parser is None: + parser = make_parser() + parser.forbid_dtd = forbid_dtd + parser.forbid_entities = forbid_entities + parser.forbid_external = forbid_external + return _parseString(string, parser) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/sax.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/sax.py new file mode 100644 index 0000000000000000000000000000000000000000..b2786f74f65e26b759ab6ce364faf1a6a2c25dc0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/sax.py @@ -0,0 +1,60 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xml.sax +""" +from __future__ import print_function, absolute_import + +from xml.sax import InputSource as _InputSource +from xml.sax import ErrorHandler as _ErrorHandler + +from . import expatreader + +__origin__ = "xml.sax" + + +def parse( + source, + handler, + errorHandler=_ErrorHandler(), + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): + parser = make_parser() + parser.setContentHandler(handler) + parser.setErrorHandler(errorHandler) + parser.forbid_dtd = forbid_dtd + parser.forbid_entities = forbid_entities + parser.forbid_external = forbid_external + parser.parse(source) + + +def parseString( + string, + handler, + errorHandler=_ErrorHandler(), + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): + from io import BytesIO + + if errorHandler is None: + errorHandler = _ErrorHandler() + parser = make_parser() + parser.setContentHandler(handler) + parser.setErrorHandler(errorHandler) + parser.forbid_dtd = forbid_dtd + parser.forbid_entities = forbid_entities + parser.forbid_external = forbid_external + + inpsrc = _InputSource() + inpsrc.setByteStream(BytesIO(string)) + parser.parse(inpsrc) + + +def make_parser(parser_list=[]): + return expatreader.create_parser() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/xmlrpc.py b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/xmlrpc.py new file mode 100644 index 0000000000000000000000000000000000000000..fbc674da44e6d7edebc4c15d90bcf9809680be6a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/defusedxml/xmlrpc.py @@ -0,0 +1,153 @@ +# defusedxml +# +# Copyright (c) 2013 by Christian Heimes <christian@python.org> +# Licensed to PSF under a Contributor Agreement. +# See https://www.python.org/psf/license for licensing details. +"""Defused xmlrpclib + +Also defuses gzip bomb +""" +from __future__ import print_function, absolute_import + +import io + +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden, PY3 + +if PY3: + __origin__ = "xmlrpc.client" + from xmlrpc.client import ExpatParser + from xmlrpc import client as xmlrpc_client + from xmlrpc import server as xmlrpc_server + from xmlrpc.client import gzip_decode as _orig_gzip_decode + from xmlrpc.client import GzipDecodedResponse as _OrigGzipDecodedResponse +else: + __origin__ = "xmlrpclib" + from xmlrpclib import ExpatParser + import xmlrpclib as xmlrpc_client + + xmlrpc_server = None + from xmlrpclib import gzip_decode as _orig_gzip_decode + from xmlrpclib import GzipDecodedResponse as _OrigGzipDecodedResponse + +try: + import gzip +except ImportError: # pragma: no cover + gzip = None + + +# Limit maximum request size to prevent resource exhaustion DoS +# Also used to limit maximum amount of gzip decoded data in order to prevent +# decompression bombs +# A value of -1 or smaller disables the limit +MAX_DATA = 30 * 1024 * 1024 # 30 MB + + +def defused_gzip_decode(data, limit=None): + """gzip encoded data -> unencoded data + + Decode data using the gzip content encoding as described in RFC 1952 + """ + if not gzip: # pragma: no cover + raise NotImplementedError + if limit is None: + limit = MAX_DATA + f = io.BytesIO(data) + gzf = gzip.GzipFile(mode="rb", fileobj=f) + try: + if limit < 0: # no limit + decoded = gzf.read() + else: + decoded = gzf.read(limit + 1) + except IOError: # pragma: no cover + raise ValueError("invalid data") + f.close() + gzf.close() + if limit >= 0 and len(decoded) > limit: + raise ValueError("max gzipped payload length exceeded") + return decoded + + +class DefusedGzipDecodedResponse(gzip.GzipFile if gzip else object): + """a file-like object to decode a response encoded with the gzip + method, as described in RFC 1952. + """ + + def __init__(self, response, limit=None): + # response doesn't support tell() and read(), required by + # GzipFile + if not gzip: # pragma: no cover + raise NotImplementedError + self.limit = limit = limit if limit is not None else MAX_DATA + if limit < 0: # no limit + data = response.read() + self.readlength = None + else: + data = response.read(limit + 1) + self.readlength = 0 + if limit >= 0 and len(data) > limit: + raise ValueError("max payload length exceeded") + self.stringio = io.BytesIO(data) + gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio) + + def read(self, n): + if self.limit >= 0: + left = self.limit - self.readlength + n = min(n, left + 1) + data = gzip.GzipFile.read(self, n) + self.readlength += len(data) + if self.readlength > self.limit: + raise ValueError("max payload length exceeded") + return data + else: + return gzip.GzipFile.read(self, n) + + def close(self): + gzip.GzipFile.close(self) + self.stringio.close() + + +class DefusedExpatParser(ExpatParser): + def __init__(self, target, forbid_dtd=False, forbid_entities=True, forbid_external=True): + ExpatParser.__init__(self, target) + self.forbid_dtd = forbid_dtd + self.forbid_entities = forbid_entities + self.forbid_external = forbid_external + parser = self._parser + if self.forbid_dtd: + parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl + if self.forbid_entities: + parser.EntityDeclHandler = self.defused_entity_decl + parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl + if self.forbid_external: + parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler + + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): + raise DTDForbidden(name, sysid, pubid) + + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): + raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) + + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): + # expat 1.2 + raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover + + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): + raise ExternalReferenceForbidden(context, base, sysid, pubid) + + +def monkey_patch(): + xmlrpc_client.FastParser = DefusedExpatParser + xmlrpc_client.GzipDecodedResponse = DefusedGzipDecodedResponse + xmlrpc_client.gzip_decode = defused_gzip_decode + if xmlrpc_server: + xmlrpc_server.gzip_decode = defused_gzip_decode + + +def unmonkey_patch(): + xmlrpc_client.FastParser = None + xmlrpc_client.GzipDecodedResponse = _OrigGzipDecodedResponse + xmlrpc_client.gzip_decode = _orig_gzip_decode + if xmlrpc_server: + xmlrpc_server.gzip_decode = _orig_gzip_decode diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/DESCRIPTION.rst b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000000000000000000000000000000000000..63eeee630fc91308430d01c290d193bc973dcef6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,55 @@ +===================== +django-templated-mail +===================== + +.. image:: https://img.shields.io/pypi/v/django-templated-mail.svg + :target: https://pypi.org/project/django-templated-mail + +.. image:: https://img.shields.io/travis/sunscrapers/django-templated-mail.svg + :target: https://travis-ci.org/sunscrapers/django-templated-mail + +.. image:: https://img.shields.io/codecov/c/github/sunscrapers/django-templated-mail.svg + :target: https://codecov.io/gh/sunscrapers/django-templated-mail + +.. image:: https://img.shields.io/scrutinizer/g/sunscrapers/django-templated-mail.svg + :target: https://scrutinizer-ci.com/g/sunscrapers/django-templated-mail + +A simple wrapper for ``django.core.mail.EmailMultiAlternatives`` which makes +use of Django template system to store email content in separate file. + +Developed by `SUNSCRAPERS <http://sunscrapers.com/>`_ with passion & patience. + +Installation +============ + +Simply install using ``pip``: + +.. code-block:: bash + + $ pip install -U django-templated-mail + +Documentation +============= + +Documentation is available to study at +`http://django-templated-mail.readthedocs.io <http://django-templated-mail.readthedocs.io>`_ +and in ``docs`` directory. + +Contributing and development +============================ + +To start developing on **django-templated-mail**, clone the repository: + +.. code-block:: bash + + $ git clone git@github.com:sunscrapers/django-templated-mail.git + +If you are a **pipenv** user you can quickly setup testing environment by +using Make commands: + +.. code-block:: bash + + $ make init + $ make test + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..074a86231e6c0de38f1ca3f643d342d7303cd14f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.0 +Name: django-templated-mail +Version: 1.1.1 +Summary: Send emails using Django template system. +Home-page: https://github.com/sunscrapers/django-templated-mail +Author: Sunscrapers +Author-email: info@sunscrapers.com +License: MIT +Description-Content-Type: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Django :: 1.8 +Classifier: Framework :: Django :: 1.11 +Classifier: Framework :: Django :: 2.0 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 + +===================== +django-templated-mail +===================== + +.. image:: https://img.shields.io/pypi/v/django-templated-mail.svg + :target: https://pypi.org/project/django-templated-mail + +.. image:: https://img.shields.io/travis/sunscrapers/django-templated-mail.svg + :target: https://travis-ci.org/sunscrapers/django-templated-mail + +.. image:: https://img.shields.io/codecov/c/github/sunscrapers/django-templated-mail.svg + :target: https://codecov.io/gh/sunscrapers/django-templated-mail + +.. image:: https://img.shields.io/scrutinizer/g/sunscrapers/django-templated-mail.svg + :target: https://scrutinizer-ci.com/g/sunscrapers/django-templated-mail + +A simple wrapper for ``django.core.mail.EmailMultiAlternatives`` which makes +use of Django template system to store email content in separate file. + +Developed by `SUNSCRAPERS <http://sunscrapers.com/>`_ with passion & patience. + +Installation +============ + +Simply install using ``pip``: + +.. code-block:: bash + + $ pip install -U django-templated-mail + +Documentation +============= + +Documentation is available to study at +`http://django-templated-mail.readthedocs.io <http://django-templated-mail.readthedocs.io>`_ +and in ``docs`` directory. + +Contributing and development +============================ + +To start developing on **django-templated-mail**, clone the repository: + +.. code-block:: bash + + $ git clone git@github.com:sunscrapers/django-templated-mail.git + +If you are a **pipenv** user you can quickly setup testing environment by +using Make commands: + +.. code-block:: bash + + $ make init + $ make test + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..fc4c39dbb252537ac81086132894907bbee2f958 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/RECORD @@ -0,0 +1,11 @@ +django_templated_mail-1.1.1.dist-info/DESCRIPTION.rst,sha256=UFNu2TdFxb-OoAvTwccnTRxudi5BFDlp_JphpdO8txg,1576 +django_templated_mail-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +django_templated_mail-1.1.1.dist-info/METADATA,sha256=OW2pJs5wkfMLN79tcFfrVUSf-vsjHEVsUkY7RVGEj3U,2436 +django_templated_mail-1.1.1.dist-info/RECORD,, +django_templated_mail-1.1.1.dist-info/WHEEL,sha256=8Lm45v9gcYRm70DrgFGVe4WsUtUMi1_0Tso1hqPGMjA,92 +django_templated_mail-1.1.1.dist-info/metadata.json,sha256=WTIcX1r-PxajSo2BfocMRF0QaN3Wcit5fClVdbHeyrc,960 +django_templated_mail-1.1.1.dist-info/top_level.txt,sha256=3pC3g6EhEeRxLoElDAd84xGcuVtyDv-mvO193uP6VTA,15 +templated_mail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +templated_mail/__pycache__/__init__.cpython-310.pyc,, +templated_mail/__pycache__/mail.cpython-310.pyc,, +templated_mail/mail.py,sha256=eiOabc--5mN0b2BpQ_57kf6TBLfclKgRkdWCQAodgX4,3158 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..6261a26e7a4c380ad73a4316b8a18d8fa839205d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/metadata.json b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..9d5e1ba1593165350e4633e6eb6c00adf1ed4872 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Django :: 1.8", "Framework :: Django :: 1.11", "Framework :: Django :: 2.0", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "info@sunscrapers.com", "name": "Sunscrapers", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/sunscrapers/django-templated-mail"}}}, "generator": "bdist_wheel (0.30.0)", "license": "MIT", "metadata_version": "2.0", "name": "django-templated-mail", "summary": "Send emails using Django template system.", "version": "1.1.1"} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..79dcf2dec95f681b3d4d77c5c66fd58f5d1a25d7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/django_templated_mail-1.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +templated_mail diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/LICENSE.md b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..3dea39c36307692b0643daa89fb5ed624607f6c2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/LICENSE.md @@ -0,0 +1,29 @@ +# License + +Copyright © 2011-present, [Encode OSS Ltd](https://www.encode.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..0cff60dd14f3437232461ea03c2827b9a9a83947 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/METADATA @@ -0,0 +1,266 @@ +Metadata-Version: 2.1 +Name: djangorestframework +Version: 3.14.0 +Summary: Web APIs for Django, made easy. +Home-page: https://www.django-rest-framework.org/ +Author: Tom Christie +Author-email: tom@tomchristie.com +License: BSD +Project-URL: Funding, https://fund.django-rest-framework.org/topics/funding/ +Project-URL: Source, https://github.com/encode/django-rest-framework +Project-URL: Changelog, https://www.django-rest-framework.org/community/release-notes/ +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Django +Classifier: Framework :: Django :: 3.0 +Classifier: Framework :: Django :: 3.1 +Classifier: Framework :: Django :: 3.2 +Classifier: Framework :: Django :: 4.0 +Classifier: Framework :: Django :: 4.1 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.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 :: Only +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +License-File: LICENSE.md +Requires-Dist: django (>=3.0) +Requires-Dist: pytz + +# [Django REST framework][docs] + +[![build-status-image]][build-status] +[![coverage-status-image]][codecov] +[![pypi-version]][pypi] + +**Awesome web-browsable Web APIs.** + +Full documentation for the project is available at [https://www.django-rest-framework.org/][docs]. + +--- + +# Funding + +REST framework is a *collaboratively funded project*. If you use +REST framework commercially we strongly encourage you to invest in its +continued development by [signing up for a paid plan][funding]. + +The initial aim is to provide a single full-time position on REST framework. +*Every single sign-up makes a significant impact towards making that possible.* + +[![][sentry-img]][sentry-url] +[![][stream-img]][stream-url] +[![][spacinov-img]][spacinov-url] +[![][retool-img]][retool-url] +[![][bitio-img]][bitio-url] +[![][posthog-img]][posthog-url] +[![][cryptapi-img]][cryptapi-url] +[![][fezto-img]][fezto-url] + +Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Spacinov][spacinov-url], [Retool][retool-url], [bit.io][bitio-url], [PostHog][posthog-url], [CryptAPI][cryptapi-url], and [FEZTO][fezto-url]. + +--- + +# Overview + +Django REST framework is a powerful and flexible toolkit for building Web APIs. + +Some reasons you might want to use REST framework: + +* The [Web browsable API][sandbox] is a huge usability win for your developers. +* [Authentication policies][authentication] including optional packages for [OAuth1a][oauth1-section] and [OAuth2][oauth2-section]. +* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources. +* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers]. +* [Extensive documentation][docs], and [great community support][group]. + +There is a live example API for testing purposes, [available here][sandbox]. + +**Below**: *Screenshot from the browsable API* + +![Screenshot][image] + +---- + +# Requirements + +* Python 3.6+ +* Django 4.1, 4.0, 3.2, 3.1, 3.0 + +We **highly recommend** and only officially support the latest patch release of +each Python and Django series. + +# Installation + +Install using `pip`... + + pip install djangorestframework + +Add `'rest_framework'` to your `INSTALLED_APPS` setting. +```python +INSTALLED_APPS = [ + ... + 'rest_framework', +] +``` + +# Example + +Let's take a look at a quick example of using REST framework to build a simple model-backed API for accessing users and groups. + +Startup up a new project like so... + + pip install django + pip install djangorestframework + django-admin startproject example . + ./manage.py migrate + ./manage.py createsuperuser + + +Now edit the `example/urls.py` module in your project: + +```python +from django.contrib.auth.models import User +from django.urls import include, path +from rest_framework import routers, serializers, viewsets + + +# Serializers define the API representation. +class UserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = User + fields = ['url', 'username', 'email', 'is_staff'] + + +# ViewSets define the view behavior. +class UserViewSet(viewsets.ModelViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer + + +# Routers provide a way of automatically determining the URL conf. +router = routers.DefaultRouter() +router.register(r'users', UserViewSet) + +# Wire up our API using automatic URL routing. +# Additionally, we include login URLs for the browsable API. +urlpatterns = [ + path('', include(router.urls)), + path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), +] +``` + +We'd also like to configure a couple of settings for our API. + +Add the following to your `settings.py` module: + +```python +INSTALLED_APPS = [ + ... # Make sure to include the default installed apps here. + 'rest_framework', +] + +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', + ] +} +``` + +That's it, we're done! + + ./manage.py runserver + +You can now open the API in your browser at `http://127.0.0.1:8000/`, and view your new 'users' API. If you use the `Login` control in the top right corner you'll also be able to add, create and delete users from the system. + +You can also interact with the API using command line tools such as [`curl`](https://curl.haxx.se/). For example, to list the users endpoint: + + $ curl -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/ + [ + { + "url": "http://127.0.0.1:8000/users/1/", + "username": "admin", + "email": "admin@example.com", + "is_staff": true, + } + ] + +Or to create a new user: + + $ curl -X POST -d username=new -d email=new@example.com -d is_staff=false -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/ + { + "url": "http://127.0.0.1:8000/users/2/", + "username": "new", + "email": "new@example.com", + "is_staff": false, + } + +# Documentation & Support + +Full documentation for the project is available at [https://www.django-rest-framework.org/][docs]. + +For questions and support, use the [REST framework discussion group][group], or `#restframework` on libera.chat IRC. + +You may also want to [follow the author on Twitter][twitter]. + +# Security + +Please see the [security policy][security-policy]. + +[build-status-image]: https://github.com/encode/django-rest-framework/actions/workflows/main.yml/badge.svg +[build-status]: https://github.com/encode/django-rest-framework/actions/workflows/main.yml +[coverage-status-image]: https://img.shields.io/codecov/c/github/encode/django-rest-framework/master.svg +[codecov]: https://codecov.io/github/encode/django-rest-framework?branch=master +[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg +[pypi]: https://pypi.org/project/djangorestframework/ +[twitter]: https://twitter.com/starletdreaming +[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework +[sandbox]: https://restframework.herokuapp.com/ + +[funding]: https://fund.django-rest-framework.org/topics/funding/ +[sponsors]: https://fund.django-rest-framework.org/topics/funding/#our-sponsors + +[sentry-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/sentry-readme.png +[stream-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/stream-readme.png +[spacinov-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/spacinov-readme.png +[retool-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/retool-readme.png +[bitio-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/bitio-readme.png +[posthog-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/posthog-readme.png +[cryptapi-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/cryptapi-readme.png +[fezto-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/fezto-readme.png + +[sentry-url]: https://getsentry.com/welcome/ +[stream-url]: https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage +[spacinov-url]: https://www.spacinov.com/ +[retool-url]: https://retool.com/?utm_source=djangorest&utm_medium=sponsorship +[bitio-url]: https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship +[posthog-url]: https://posthog.com?utm_source=drf&utm_medium=sponsorship&utm_campaign=open-source-sponsorship +[cryptapi-url]: https://cryptapi.io +[fezto-url]: https://www.fezto.xyz/?utm_source=DjangoRESTFramework + +[oauth1-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-rest-framework-oauth +[oauth2-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-oauth-toolkit +[serializer-section]: https://www.django-rest-framework.org/api-guide/serializers/#serializers +[modelserializer-section]: https://www.django-rest-framework.org/api-guide/serializers/#modelserializer +[functionview-section]: https://www.django-rest-framework.org/api-guide/views/#function-based-views +[generic-views]: https://www.django-rest-framework.org/api-guide/generic-views/ +[viewsets]: https://www.django-rest-framework.org/api-guide/viewsets/ +[routers]: https://www.django-rest-framework.org/api-guide/routers/ +[serializers]: https://www.django-rest-framework.org/api-guide/serializers/ +[authentication]: https://www.django-rest-framework.org/api-guide/authentication/ +[image]: https://www.django-rest-framework.org/img/quickstart.png + +[docs]: https://www.django-rest-framework.org/ +[security-policy]: https://github.com/encode/django-rest-framework/security/policy + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..509bda6e31b62e7ea86ee40038495652b2a0d252 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/RECORD @@ -0,0 +1,312 @@ +djangorestframework-3.14.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +djangorestframework-3.14.0.dist-info/LICENSE.md,sha256=zBKwuFNolyF36_QiCJQZuf4-6lcp_ssREFxkD27qzNQ,1537 +djangorestframework-3.14.0.dist-info/METADATA,sha256=LN1lag-Q_SV7Xjth8wOajFfjAjAFjP66NDMT8ymffd8,10703 +djangorestframework-3.14.0.dist-info/RECORD,, +djangorestframework-3.14.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +djangorestframework-3.14.0.dist-info/top_level.txt,sha256=_sDOIN5T7esgAN5zlnfLHLo7AG7TWqBYVTyFKVRdXv4,15 +rest_framework/__init__.py,sha256=Y5v1sE97mbo_oXH_HOakVonXN-F1BAA9z1n8bz1T1N4,967 +rest_framework/__pycache__/__init__.cpython-310.pyc,, +rest_framework/__pycache__/apps.cpython-310.pyc,, +rest_framework/__pycache__/authentication.cpython-310.pyc,, +rest_framework/__pycache__/checks.cpython-310.pyc,, +rest_framework/__pycache__/compat.cpython-310.pyc,, +rest_framework/__pycache__/decorators.cpython-310.pyc,, +rest_framework/__pycache__/documentation.cpython-310.pyc,, +rest_framework/__pycache__/exceptions.cpython-310.pyc,, +rest_framework/__pycache__/fields.cpython-310.pyc,, +rest_framework/__pycache__/filters.cpython-310.pyc,, +rest_framework/__pycache__/generics.cpython-310.pyc,, +rest_framework/__pycache__/metadata.cpython-310.pyc,, +rest_framework/__pycache__/mixins.cpython-310.pyc,, +rest_framework/__pycache__/negotiation.cpython-310.pyc,, +rest_framework/__pycache__/pagination.cpython-310.pyc,, +rest_framework/__pycache__/parsers.cpython-310.pyc,, +rest_framework/__pycache__/permissions.cpython-310.pyc,, +rest_framework/__pycache__/relations.cpython-310.pyc,, +rest_framework/__pycache__/renderers.cpython-310.pyc,, +rest_framework/__pycache__/request.cpython-310.pyc,, +rest_framework/__pycache__/response.cpython-310.pyc,, +rest_framework/__pycache__/reverse.cpython-310.pyc,, +rest_framework/__pycache__/routers.cpython-310.pyc,, +rest_framework/__pycache__/serializers.cpython-310.pyc,, +rest_framework/__pycache__/settings.cpython-310.pyc,, +rest_framework/__pycache__/status.cpython-310.pyc,, +rest_framework/__pycache__/test.cpython-310.pyc,, +rest_framework/__pycache__/throttling.cpython-310.pyc,, +rest_framework/__pycache__/urlpatterns.cpython-310.pyc,, +rest_framework/__pycache__/urls.cpython-310.pyc,, +rest_framework/__pycache__/validators.cpython-310.pyc,, +rest_framework/__pycache__/versioning.cpython-310.pyc,, +rest_framework/__pycache__/views.cpython-310.pyc,, +rest_framework/__pycache__/viewsets.cpython-310.pyc,, +rest_framework/apps.py,sha256=e-soDnr6WzO5YU4VKliGBgP_vneqoR85SiftQ7H7Ge4,255 +rest_framework/authentication.py,sha256=lhMzDRr6MZ9eMCWnEFSK02LYGqpYDS-VRxcmBPADOHk,7739 +rest_framework/authtoken/__init__.py,sha256=Nl2fsQY6cD3321dXmDe0YRhQhef0C4bPothmsyLbavg,116 +rest_framework/authtoken/__pycache__/__init__.cpython-310.pyc,, +rest_framework/authtoken/__pycache__/admin.cpython-310.pyc,, +rest_framework/authtoken/__pycache__/apps.cpython-310.pyc,, +rest_framework/authtoken/__pycache__/models.cpython-310.pyc,, +rest_framework/authtoken/__pycache__/serializers.cpython-310.pyc,, +rest_framework/authtoken/__pycache__/views.cpython-310.pyc,, +rest_framework/authtoken/admin.py,sha256=ajzPY3jEAm2WxHVo7KZpl8pH6DzPAuEhVfFlvaXpVzo,1760 +rest_framework/authtoken/apps.py,sha256=O5R_48w8g0cThVJ0k2TH3x5t7D1KTdN3zsKwPXZDYSQ,198 +rest_framework/authtoken/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/authtoken/management/__pycache__/__init__.cpython-310.pyc,, +rest_framework/authtoken/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/authtoken/management/commands/__pycache__/__init__.cpython-310.pyc,, +rest_framework/authtoken/management/commands/__pycache__/drf_create_token.cpython-310.pyc,, +rest_framework/authtoken/management/commands/drf_create_token.py,sha256=CcGkuS62daT8YXIMt64mbc0Qu1zA5sInKSI0K1Vsx9U,1380 +rest_framework/authtoken/migrations/0001_initial.py,sha256=8hmactx2pKGeJV95raW4F7klyXNlcNQBvmahvnLj2xU,706 +rest_framework/authtoken/migrations/0002_auto_20160226_1747.py,sha256=f2C8kJ1D4A2uTte1H2UCc2-p_gxPWzT4_96oagJ56nk,994 +rest_framework/authtoken/migrations/0003_tokenproxy.py,sha256=bsFvzO_i8iMRaHvebIZU55HKNr08kg2D6LtduZQDXGw,552 +rest_framework/authtoken/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/authtoken/migrations/__pycache__/0001_initial.cpython-310.pyc,, +rest_framework/authtoken/migrations/__pycache__/0002_auto_20160226_1747.cpython-310.pyc,, +rest_framework/authtoken/migrations/__pycache__/0003_tokenproxy.cpython-310.pyc,, +rest_framework/authtoken/migrations/__pycache__/__init__.cpython-310.pyc,, +rest_framework/authtoken/models.py,sha256=XKks3WuKMCyj4lbC__OXl1pzqYYHeXcSYrwV2iNk51U,1563 +rest_framework/authtoken/serializers.py,sha256=gZFJ3qhW17dOPigqY0_Qx9xVQeRD1V8fy1j07QXKmUc,1384 +rest_framework/authtoken/views.py,sha256=IXX6PNUwguRq7ZGebrG-vguAMFkSOmq4qPJI7CTcyAY,2216 +rest_framework/checks.py,sha256=WO57Y9Ks_MQKq0FsFVXoP7odQMQyVIr-LbPt6fcx2LU,970 +rest_framework/compat.py,sha256=ElN6B4YnBSonCAxzZ27fu8qWGkmby5P_ixnjzFzc8K0,5521 +rest_framework/decorators.py,sha256=fP1sigfHs_Iah_0pq_oP0FCvgt9h93-cYWaxJVeVvs8,7785 +rest_framework/documentation.py,sha256=EKZGzMUzXq8H_bri0dRJ89npwT6JwKQOENNPHaYQ5-k,3054 +rest_framework/exceptions.py,sha256=k15a5yZPMk4IT2FbVmIFkeARH15nIENRTX2b5B3LoGI,8159 +rest_framework/fields.py,sha256=z_OmftX14FozERkhs-PJ-DASGcXHpMpSPfd8yY1uUEs,67410 +rest_framework/filters.py,sha256=ORaKCx92DjSFX1HXkX6vGnhdXOC8bIx1AJD_F1coWIg,12488 +rest_framework/generics.py,sha256=riKBm8m9yxSny6adlBiePeCqWmu4RJPvVVkxmiuidIw,10040 +rest_framework/locale/ach/LC_MESSAGES/django.mo,sha256=3LyV_OzlARDfeuhvZp6OCdt6xH4esewLh5fU8a4eXxg,472 +rest_framework/locale/ar/LC_MESSAGES/django.mo,sha256=th7efxoto1P_iFZKFezHyVuQYOyspbvusm-fAnk5j84,12150 +rest_framework/locale/az/LC_MESSAGES/django.mo,sha256=B3IIoIYmYPkM9iOsm0I10Zb__w7rVVZ9HhWMhbvv5bA,10428 +rest_framework/locale/be/LC_MESSAGES/django.mo,sha256=TvqPpcP1PWvOx6RwBM1vO5fUaqXMRddmwRb05TuqTaQ,614 +rest_framework/locale/bg/LC_MESSAGES/django.mo,sha256=j8UXyFO7YdRsZ5OwtI15fUmrN6QnSJonpX_eIo74WCQ,13083 +rest_framework/locale/ca/LC_MESSAGES/django.mo,sha256=5h1KYV14JnFIX02ABU8WeFlqJGKCBKtgbRMcR2lzjpE,9300 +rest_framework/locale/ca_ES/LC_MESSAGES/django.mo,sha256=Toqlh8opAxtm46W5UGvLZW_nsXjkjUoAMQjc5dF-WiQ,487 +rest_framework/locale/cs/LC_MESSAGES/django.mo,sha256=KMLhUh-qAPlAvKWaGZYgFJKCMaLH0N5SdgOY2d0gSig,10519 +rest_framework/locale/da/LC_MESSAGES/django.mo,sha256=_RNWqDszm5SPR6m6LJSkpkLsOlxX6FCm7mV2Ln8JDZw,9955 +rest_framework/locale/de/LC_MESSAGES/django.mo,sha256=8v8nY8HmMIOteF2s24sTFK7lOKTShTxvMWhbm0qMm3A,10490 +rest_framework/locale/el/LC_MESSAGES/django.mo,sha256=RbxSQ08hrFB173iNcfVTvoAU5teTkl9SKsEFLuOK2BI,12933 +rest_framework/locale/el_GR/LC_MESSAGES/django.mo,sha256=_oUBBH7uSAlTcQ3Km2U2kwFRMnpG3Fz0X1CuAQbU_9I,486 +rest_framework/locale/en/LC_MESSAGES/django.mo,sha256=NTQOG7G0S5cILPfjiwr5jGLFS6-BLSkJWz-IZ34WnqU,12285 +rest_framework/locale/en_AU/LC_MESSAGES/django.mo,sha256=6yNdQp3uMV-f63P7xuvX6fzRyb-iG3upwHmz2cJHNlU,491 +rest_framework/locale/en_CA/LC_MESSAGES/django.mo,sha256=JT4wh-kQWfeO4T-be9lwbDaLz0QVu5P0SnK4BDJfOSQ,488 +rest_framework/locale/en_US/LC_MESSAGES/django.mo,sha256=UXCQbz2AxBvh-IQ7bGgjoBnijo8h9DfE9107A-2Mgkk,337 +rest_framework/locale/es/LC_MESSAGES/django.mo,sha256=2NqCq4Rk6k0sZUOk1OO55VWSOgHRnuUuvgcc3wB7MUY,10627 +rest_framework/locale/et/LC_MESSAGES/django.mo,sha256=-ZMrAfUiqMzPnxJD6qNCY3RqRl7m0jY8LjwFz68dxM4,10096 +rest_framework/locale/fa/LC_MESSAGES/django.mo,sha256=a1B7CgBlwt9D_cHqB6VJbj-PUiSvG1QNsij6cPVom_s,11976 +rest_framework/locale/fa_IR/LC_MESSAGES/django.mo,sha256=29zq4NzdtVBc0Q_LaoHROnNYXtwb4kSdrMMKs-yyCyE,11989 +rest_framework/locale/fi/LC_MESSAGES/django.mo,sha256=-TPYxiKlLMCOfjPRM9rvvO5KTuj5XnrJhABw9Db8dSs,10197 +rest_framework/locale/fr/LC_MESSAGES/django.mo,sha256=56a48bfyLGVnGrTiKqGNe6fb4fYDkoJSarLeP3dbmc0,10662 +rest_framework/locale/fr_CA/LC_MESSAGES/django.mo,sha256=AIkTPlyS_J4u1-DtjroxlYZ4_xK8s_dBR8ps593XVTE,486 +rest_framework/locale/gl/LC_MESSAGES/django.mo,sha256=-dhiLFcnF6nZSm2F1jLGOu9JYHAKz468w2hD48Hf7qU,474 +rest_framework/locale/gl_ES/LC_MESSAGES/django.mo,sha256=IQjsBgbgFHZ48iWHMeHzfbnlhReQNoeFq3pCYMSb8gA,628 +rest_framework/locale/he_IL/LC_MESSAGES/django.mo,sha256=JmkZjjtdpkm_51gHbWDa6LnAXK8dHBdxWvkZLVchTPU,487 +rest_framework/locale/hu/LC_MESSAGES/django.mo,sha256=DsEmG9PSPMP_thCE2j_Z4MUIxVb9JY0IPxwxSjit9DI,10844 +rest_framework/locale/hy/LC_MESSAGES/django.mo,sha256=r5Gjh2x7RTGjPt05NzsxzeS6nQxqNClR9J1UYpR1W30,12885 +rest_framework/locale/id/LC_MESSAGES/django.mo,sha256=X8mmBaEYQ0U1PBKpmVzEv07jqdrZAQmWaINMjnFEIGo,5188 +rest_framework/locale/it/LC_MESSAGES/django.mo,sha256=Seuvke2Kb3XZyBgsLndK4kc4ABOHFb1ok2SNWZLBk3o,10480 +rest_framework/locale/ja/LC_MESSAGES/django.mo,sha256=D19OXy2vt0t54yPYCbDe9BGwnrBemcH3zkwXD2YphcA,11759 +rest_framework/locale/ko_KR/LC_MESSAGES/django.mo,sha256=M09dPfSrFqcX8Te7xXGgnhgIk52LhxksiLrooZ3sFvE,11698 +rest_framework/locale/lt/LC_MESSAGES/django.mo,sha256=-6W2uJJ3gYEYkd1H1CF4MfRykn75_HJ2V4vgm0rlu48,5056 +rest_framework/locale/lv/LC_MESSAGES/django.mo,sha256=VcPsDP3hVZt8YMlq1RdgYm_WUIo5QWt4SBTe9KyIn_k,10423 +rest_framework/locale/mk/LC_MESSAGES/django.mo,sha256=HA51S3Es40nX29BcU4Qh1BNbLWLXjpa51p_7c_u-Drk,12121 +rest_framework/locale/nb/LC_MESSAGES/django.mo,sha256=U0jYbFS-Kxj08Thb7fF8oMrab5S2nu1lhlQhsUCpi-A,9928 +rest_framework/locale/ne_NP/LC_MESSAGES/django.mo,sha256=7ohVBTeeKYoPiTFwYA14fSxkqRgx7GBZAgyjDk15OTA,15636 +rest_framework/locale/nl/LC_MESSAGES/django.mo,sha256=ad5I7tegcNW8FOqn9E1O_cqrtHdvlkEoKvHEokjRqQo,10163 +rest_framework/locale/nn/LC_MESSAGES/django.mo,sha256=3oQQnH3UF9nHmTsj3pqv5R2iakv-wdjy0k_EQvbo4ds,483 +rest_framework/locale/no/LC_MESSAGES/django.mo,sha256=ZpgR0-XMg7oQXeS9Q6Pdhk1Y8G6hXnQVx1x3iv8yAA4,475 +rest_framework/locale/pl/LC_MESSAGES/django.mo,sha256=0mc9ltZnrL60-T2yOLavGH8DwRnEN9wu8a8_zB5RkgE,10673 +rest_framework/locale/pt/LC_MESSAGES/django.mo,sha256=j1Y5sfsqtQYVEKWxbrO6AJHw_hfh5adocwYdaVyG9CY,10382 +rest_framework/locale/pt_BR/LC_MESSAGES/django.mo,sha256=mn1IClfteWM9J3Y6uvy5arKR7AdzEwhvqtw1Xvdpuew,10397 +rest_framework/locale/pt_PT/LC_MESSAGES/django.mo,sha256=sCkzHosWkIhNbRljJWvK4x_UlbSK3SNickNyp17cOpM,493 +rest_framework/locale/ro/LC_MESSAGES/django.mo,sha256=CEab6ZJC7xeFrN2v6UKkDWNegXkbGpFBZSWeno0qN0w,10701 +rest_framework/locale/ru/LC_MESSAGES/django.mo,sha256=IxiOtRY_UAVUT6Is4Gh09pGj7kLyqBHaUJh7S3uiRcI,13160 +rest_framework/locale/ru_RU/LC_MESSAGES/django.mo,sha256=AmZPL7_x-1BT9COfEDAitvyhXvkWeYINhXj1htyhq0g,5208 +rest_framework/locale/sk/LC_MESSAGES/django.mo,sha256=hPXX50ijI61arUGVjMhEhz_S-zZqA1WmUNjTEJUgI8I,9164 +rest_framework/locale/sl/LC_MESSAGES/django.mo,sha256=_6IhTyJmeOb73eMhSmeVBVoKztxBQ1ldnwET_N-rT6g,9985 +rest_framework/locale/sv/LC_MESSAGES/django.mo,sha256=OV3cEUiafwnLwesNOlHr3h0fur29GJVMFHAUYUdIHBc,10204 +rest_framework/locale/th/LC_MESSAGES/django.mo,sha256=FHJKADSeYWVdvsQ285jz_865vzUelHIqkxSa4QSLlOw,8880 +rest_framework/locale/tr/LC_MESSAGES/django.mo,sha256=UJEBznyWnRnVKmRn56MwAGc7s0FAcToGXmd-O-k-58g,10073 +rest_framework/locale/tr_TR/LC_MESSAGES/django.mo,sha256=Nm3vmt38r3DxKdl2Astxny_E4IEkJlhDkzYpwiio7NQ,10292 +rest_framework/locale/uk/LC_MESSAGES/django.mo,sha256=fWmrOfNUsagv9jsIfQzP4QYQRKUugCaTBitRfvG-7gg,13245 +rest_framework/locale/vi/LC_MESSAGES/django.mo,sha256=_TekVPiXtQP0HsHrqt0S5fa669Auow5EaDsvoimUzPY,2179 +rest_framework/locale/zh_CN/LC_MESSAGES/django.mo,sha256=K9xrJnn5hyO5dM7sveYajph49Vveoo9kBLxrs9nyXfQ,9915 +rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo,sha256=GVmnW3r-jCqyllmF87w5sxGPLA3p49BaS0n0ufRqsI8,9938 +rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo,sha256=fZErAq1tsNswSyVXhMm96AUqQM3IwIZarbdLTWDhu64,4809 +rest_framework/locale/zh_TW/LC_MESSAGES/django.mo,sha256=x_Ba_GQLy-sIMYRRex0kGn9zZKzY5L8y69SSY2HasZU,481 +rest_framework/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/management/__pycache__/__init__.cpython-310.pyc,, +rest_framework/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/management/commands/__pycache__/__init__.cpython-310.pyc,, +rest_framework/management/commands/__pycache__/generateschema.cpython-310.pyc,, +rest_framework/management/commands/generateschema.py,sha256=egmCNu1eXyDxH-zDf466qjlckNVWrsc7mMMV1uZoK0w,2931 +rest_framework/metadata.py,sha256=EeEPMe8t-TteeGKZLwpiZLJ-KJwbYB8YrskBB4mvzqE,5867 +rest_framework/mixins.py,sha256=bqdlz6p0JlhRNIA3cxhjPkY24dPTWMcMsvWUfx-Mews,2937 +rest_framework/negotiation.py,sha256=-bEEaxcsoxyWRvDFdzyZ3jxraytSqjBVL84zPzO5USw,4044 +rest_framework/pagination.py,sha256=-O2IZPlPQZE_O-8KcVcC4ezHeywoBCkKo3LgX_6AHwM,35676 +rest_framework/parsers.py,sha256=YA21iJdySO33XLlXy-SY8yxyoGilGQyVvM9qEVck4gU,7748 +rest_framework/permissions.py,sha256=LMd_cuGpTvTJIhtlBSc9nPTYIOg3vDnDL1aCc-HrPC8,9234 +rest_framework/relations.py,sha256=9ceYisUF6JNB38Yanjc1dVNrlU53dQ6mhP3gr6NRVEc,21171 +rest_framework/renderers.py,sha256=lW3kW10ToqL9VEaylXDesdLOOFt6OdtwHopNZQ3bOE8,40284 +rest_framework/request.py,sha256=W3835mxTVFmMvTDkefJpm0BcxLDoZB_Q7t_2CjuBpaU,15264 +rest_framework/response.py,sha256=1svv8WGiOOgTiXBef3jfsYu3rN_lrAO6j2_IHKdmn50,3433 +rest_framework/reverse.py,sha256=veLMPqo0v81NP0X7J_I6rCqtirJmCnJ4-Mm3-lOgBbY,2144 +rest_framework/routers.py,sha256=OhqWTDr8ogyvrHu__-FBnt5Z6CxCNjs2Os8ajdZFCZE,12211 +rest_framework/schemas/__init__.py,sha256=1CkgqzGW08pYGEPFqrUO4qjbUohDfcDf2boFe7-TVSw,1781 +rest_framework/schemas/__pycache__/__init__.cpython-310.pyc,, +rest_framework/schemas/__pycache__/coreapi.cpython-310.pyc,, +rest_framework/schemas/__pycache__/generators.cpython-310.pyc,, +rest_framework/schemas/__pycache__/inspectors.cpython-310.pyc,, +rest_framework/schemas/__pycache__/openapi.cpython-310.pyc,, +rest_framework/schemas/__pycache__/utils.cpython-310.pyc,, +rest_framework/schemas/__pycache__/views.cpython-310.pyc,, +rest_framework/schemas/coreapi.py,sha256=Dn2GoUBoT9gKNq8QomXbeNJeRLXVe-LLCo3jKQ8Z6aE,20829 +rest_framework/schemas/generators.py,sha256=HJ71FwiGFEj8EjDd0f7VzWI2msTTGHPTFO0xFynahvU,7995 +rest_framework/schemas/inspectors.py,sha256=gN2tQUF8QMmcs_djzDbqvDJtbZYMF0JdzFAnjvXwbEI,4196 +rest_framework/schemas/openapi.py,sha256=TFQz5au8YltDlVS4xzrBlmki27kyhMXLKVyqgJdGZQk,26826 +rest_framework/schemas/utils.py,sha256=iGGJfS7S-MwTvr2gPystxrEO3TaRb-x0fpyUjDWkkW8,1195 +rest_framework/schemas/views.py,sha256=epv16dSdBIUpmqOMKGvS61wtSCJhlzT1JZH84w4QNHw,1836 +rest_framework/serializers.py,sha256=kqQbZ8tgeqAv91Y6sG71Ig_YB-OaVr4vehK7QjUtWY8,65930 +rest_framework/settings.py,sha256=rAJEzjdthuFSXBzDyWXOp_THgQWa87wPSKBjPZGbe3g,7808 +rest_framework/static/rest_framework/css/bootstrap-theme.min.css,sha256=8uHMIn1ru0GS5KO-zf7Zccf8Uw12IA5DrdEcmMuWLFM,23411 +rest_framework/static/rest_framework/css/bootstrap-theme.min.css.map,sha256=Xrq8Sds3hoHPZBKqAL07ehEaCfKBUjH0tW4pb6xIYTA,75600 +rest_framework/static/rest_framework/css/bootstrap-tweaks.css,sha256=wXtAjvAHjAcfJg_6Gi_KgcWAe5cuM1_r79nrm9P8PgU,3385 +rest_framework/static/rest_framework/css/bootstrap.min.css,sha256=bZLfwXAP04zRMK2BjiO8iu9pf4FbLqX6zitd-tIvLhE,121457 +rest_framework/static/rest_framework/css/bootstrap.min.css.map,sha256=eLWMnr_ULsLGG8T99Gpd-ZjmzZB8dzB2oKbo9Whrr8M,540434 +rest_framework/static/rest_framework/css/default.css,sha256=EWV35tstD5m0GezGG0U5Fa8O_4IGsL8_noeJdxnBs3s,1152 +rest_framework/static/rest_framework/css/font-awesome-4.0.3.css,sha256=MIPo07Id3D8ObWXsNYCqbt-q3KXZc32cqifmojPhzPM,21658 +rest_framework/static/rest_framework/css/prettify.css,sha256=-ZMq8eZ6blEFtxcVudM1hzv4gFwBwqlgPjHpbMSpWBk,817 +rest_framework/static/rest_framework/docs/css/base.css,sha256=fZ9Os4iAF3DBq3Aww8qbbRypx6fkGV_-PjxQ8YqssM4,6156 +rest_framework/static/rest_framework/docs/css/highlight.css,sha256=h-4d4bDFtOId4PkL4xBXl-XtRfav47B8cPUBoYWlc3M,1682 +rest_framework/static/rest_framework/docs/css/jquery.json-view.min.css,sha256=w4_hEoz19Kk_fC7uLct1FzPE3gEIvNulKydv75PFyew,1307 +rest_framework/static/rest_framework/docs/img/favicon.ico,sha256=Ww2bNjGXyE2y9FeO6sW7YksqF2CQ89pdTrksiFbP4n4,5430 +rest_framework/static/rest_framework/docs/img/grid.png,sha256=bipYUDSUpwgQWsZG069cCMjIkDJbt4GiV9EPkf-Wipw,1458 +rest_framework/static/rest_framework/docs/js/api.js,sha256=SZIptx1KE3KDkMbfZmc4OSg5JSNkTLsQalPdb-NwkUY,10391 +rest_framework/static/rest_framework/docs/js/highlight.pack.js,sha256=TpVs16YPyRxjTs122mIsboTVOpoTUb1AmzlBnOHjU4A,300764 +rest_framework/static/rest_framework/docs/js/jquery.json-view.min.js,sha256=xUY7pJMePDtQPh8KrWWP8GcwFpNVJn5AhLbXraVWvZY,2700 +rest_framework/static/rest_framework/fonts/fontawesome-webfont.eot,sha256=OeI3wHQD5i8AvW3fC1nTNJx704aSUKqtw4lBnbaqQO8,38205 +rest_framework/static/rest_framework/fonts/fontawesome-webfont.svg,sha256=m_HPYZuOy2MUAJCBqEjDemn70HtKKnzeM59jQrjrom4,202148 +rest_framework/static/rest_framework/fonts/fontawesome-webfont.ttf,sha256=a0k0itU4htCc5MMvoUbomcgg3j-FqN03BKBiTrO_f6E,80652 +rest_framework/static/rest_framework/fonts/fontawesome-webfont.woff,sha256=D9KP7Onr1ga4sHFGDr0_wu17x6Zu-RyINPEd-sq0qEk,44432 +rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot,sha256=E2NNqH2eI_jD7ZEIzhck0YOjmtBy5z4bPYy_ZG0tBAc,20127 +rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg,sha256=BogzMSnL5KzIuuo7NfgBUocHjzA1ufVnaDid2c-KDZE,108738 +rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf,sha256=45UEQJN1fYKvyxOJV9BqHqk2G9zwtELQahioBRr1dFY,45404 +rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff,sha256=omOU9-3hAMoRjv8u2ghZYnWpg5uVnCJuFUOVV6WoB0I,23424 +rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2,sha256=_hhdEaSWdokNR7t4MxKgzaWkTEA5IUCU55V7TAQO8Rw,18028 +rest_framework/static/rest_framework/img/glyphicons-halflings-white.png,sha256=8ODZWpyKvN-r9GNI4tQoWCm7BJH19q8OBa9Sv_tjJMQ,8777 +rest_framework/static/rest_framework/img/glyphicons-halflings.png,sha256=G9UbUyeER8HbM_AMR3PnEdsh5Vfs3SbZua6Wypk_BeI,12762 +rest_framework/static/rest_framework/img/grid.png,sha256=bipYUDSUpwgQWsZG069cCMjIkDJbt4GiV9EPkf-Wipw,1458 +rest_framework/static/rest_framework/js/ajax-form.js,sha256=pF_s2ECmU-o6iU6vKYyu3VMzqn0esRDgDpR7taSMUHY,3597 +rest_framework/static/rest_framework/js/bootstrap.min.js,sha256=nuL8_2cJ5NDSSwnKD8VqreErSWHtnEP9E7AySL-1ev4,39680 +rest_framework/static/rest_framework/js/coreapi-0.1.1.js,sha256=_gzyPn-2cx0Wgfjvj_tlUhPf4laKnzYbgkcr_uNGW6E,157600 +rest_framework/static/rest_framework/js/csrf.js,sha256=eS0bS4fMRRLgXQYqgmsaDLs6R2Yklj5PkZLIUCk2vdg,1719 +rest_framework/static/rest_framework/js/default.js,sha256=mJOP3JMDyQnRSX60X_T4WgtYzOBNDYpqc1ZhOUC85iM,1268 +rest_framework/static/rest_framework/js/jquery-3.5.1.min.js,sha256=9_aliU8dGd2tb6OSsuzixeV4y_faTqgFtohetphbbj0,89476 +rest_framework/static/rest_framework/js/prettify-min.js,sha256=4uV247xgfNF5_1EZRwEPZF00QaNTE67A29BsRDf4O3c,13632 +rest_framework/status.py,sha256=gJjvtWPVEe2A4SWIQ9olI6_MThRJgSJ1KDSb_ItRiOw,2547 +rest_framework/templates/rest_framework/admin.html,sha256=gf7_-d0EgFYquGMpoYAiYjILGsuw8iwgDqqEIop-ZQw,10904 +rest_framework/templates/rest_framework/admin/detail.html,sha256=_ONyhbRK32d7IsUxmUVKQCWjxzZqwT-zK2u1CgB4lvk,306 +rest_framework/templates/rest_framework/admin/dict_value.html,sha256=KidLEu38kqvPGElnFDjiQMh72xsjT5Sq3L4gchrqMps,242 +rest_framework/templates/rest_framework/admin/list.html,sha256=sFoqx8GeL2gFZ0Yx35dq6DVXEgQIIAFYlA8h-65FEQM,819 +rest_framework/templates/rest_framework/admin/list_value.html,sha256=Z9VmS1f3mwk5LypgA8HAvogVPbDa09hABa389AYxQCo,241 +rest_framework/templates/rest_framework/admin/simple_list_value.html,sha256=d9cVgqyigNa0K0W7CYPNGcvRAqy5M-ZJAzkgA-Al70Q,121 +rest_framework/templates/rest_framework/api.html,sha256=6GkppzK1R50yjAVZJoqFnR_FdGlZBpfftD2m2WNPTVM,116 +rest_framework/templates/rest_framework/base.html,sha256=yI6-j4XBelGxqAdGr69zxEVnqu3rsGdqVccvk8YsyEg,13945 +rest_framework/templates/rest_framework/docs/auth/basic.html,sha256=GsLRwieUOwxvQRSI4nRz2PYVq72e7NLEXiprmoTbzsI,1250 +rest_framework/templates/rest_framework/docs/auth/session.html,sha256=jhtMeLg6Lq5yPb2noOabUj61UAOQe--NQGEYYwWZY_E,1154 +rest_framework/templates/rest_framework/docs/auth/token.html,sha256=0KcVSQ8w2ZvOO8A2oNlTwqmYyJ2O-12eWZL-NCBm1Rc,1618 +rest_framework/templates/rest_framework/docs/document.html,sha256=r7bWwBnt2NGaP3XbABVg-yxCiRkQuB3_-nh1cK1Wr5M,906 +rest_framework/templates/rest_framework/docs/error.html,sha256=AtDy1ZbSUG9B_mm470T8CTY1w9PxzLSJkBYNoJAuXos,1850 +rest_framework/templates/rest_framework/docs/index.html,sha256=dBZQhcy9bzPmtbkBrWJJpshbgWSyCTUsZblk5jGHk-c,2519 +rest_framework/templates/rest_framework/docs/interact.html,sha256=_8yaSo9DUW8eRVH-KEH5zJJ8MBIlI5QM_ajWPb4yrI8,1831 +rest_framework/templates/rest_framework/docs/langs/javascript-intro.html,sha256=TOLjcCnyA0MYI5w99Jtg2mN7w1wjXz0lfSM8b0wabZ4,330 +rest_framework/templates/rest_framework/docs/langs/javascript.html,sha256=vy1N2rMRSTKZjEo5mZ_rIp2g57TSa9PuuHXzeghpksk,714 +rest_framework/templates/rest_framework/docs/langs/python-intro.html,sha256=LBpDVN9qkOO5Itej4M6gl4WynB4Q2CpJ_ZEti1fAY8I,189 +rest_framework/templates/rest_framework/docs/langs/python.html,sha256=y24kdg1AdRDAWl2nu6UksrXMjbMTQcdTXuRpTOXSIJo,676 +rest_framework/templates/rest_framework/docs/langs/shell-intro.html,sha256=TQo-Y2ksj2T9kzsmENH7MEB1Mt940wW941AGGbIRjVE,189 +rest_framework/templates/rest_framework/docs/langs/shell.html,sha256=jcRLGn3Eu0Xc-lr7lGFUj-1z0e9wdMwfbFIi3Cs8mV4,441 +rest_framework/templates/rest_framework/docs/link.html,sha256=ITaS3W3sqL7gOHwVvtMi2fcuETv1eVhQedlkOsT7pTg,4624 +rest_framework/templates/rest_framework/docs/sidebar.html,sha256=S_D8Tbxo08fbmVT9FmEc8No1ESS1JMJID4q5SZRz5ZY,2581 +rest_framework/templates/rest_framework/filters/base.html,sha256=OjBIbd29onA2R-iUmkwrlXw0N5CJIsU1FOpsEJ-ZJRg,610 +rest_framework/templates/rest_framework/filters/ordering.html,sha256=wiAOyvmjypM4DJGMMWbdD4Il26Z8P7J_HcIurjv3xhA,556 +rest_framework/templates/rest_framework/filters/search.html,sha256=rO3_-Z2QVIom9WVErxMprYn-sJEe1inXHH4oAG-juWk,467 +rest_framework/templates/rest_framework/horizontal/checkbox.html,sha256=t8EJW3CIcuDb2NSa7VElCzj49b0S1RcZcS7mdkOEXMw,658 +rest_framework/templates/rest_framework/horizontal/checkbox_multiple.html,sha256=iUVqbdxQ37iejUtfT0x6UeF8RcA4t71B61dhiQsqFgk,1184 +rest_framework/templates/rest_framework/horizontal/dict_field.html,sha256=VgZ3iSqrPK02VU3gDoDuK0szJbu_PGex1HnYIpYx6ao,324 +rest_framework/templates/rest_framework/horizontal/fieldset.html,sha256=bXy7Q_zBGMpE8a7K-2SxJfVDMsHZ24xniLoCw8Xmzyg,480 +rest_framework/templates/rest_framework/horizontal/form.html,sha256=yo9PS2__lzBuYSue812MwGmi3HT6kIAzHvAQBaqJAGY,149 +rest_framework/templates/rest_framework/horizontal/input.html,sha256=pOLeWdni3DNqZCN1Dbvj5xA0D-jdM0QEok_1XpIHfBE,889 +rest_framework/templates/rest_framework/horizontal/list_field.html,sha256=_BlSeMbpE8vpnyqHp6jmou2f441hrtYBvbdBjYxJeew,317 +rest_framework/templates/rest_framework/horizontal/list_fieldset.html,sha256=5W-9tZ-GvTHR4JlHwVdDJo-1FlH6-cmUu33x2RKsnkM,384 +rest_framework/templates/rest_framework/horizontal/radio.html,sha256=xpgDdvdW3FojnB3x-OqWzIiSsdcw9sd1z-g8vYz7ofg,1796 +rest_framework/templates/rest_framework/horizontal/select.html,sha256=_Eow62zUMM9VWJ03P1HlfTNB4vyv9GfqB9WjYRhfTBY,1222 +rest_framework/templates/rest_framework/horizontal/select_multiple.html,sha256=C_98qhJwLTMNfbFBn6nhD3Qjdp6tcHwq82d8S3pFwSw,1229 +rest_framework/templates/rest_framework/horizontal/textarea.html,sha256=8myshnZKHjohQtuVVPN2gmcYN0RTMNGkSh95CEIobx4,782 +rest_framework/templates/rest_framework/inline/checkbox.html,sha256=zpUnpKg-oMZ843vtmW7ec8lzxQttwGpFE7F2vmHxZFw,294 +rest_framework/templates/rest_framework/inline/checkbox_multiple.html,sha256=vGndr0cjo-Q-sj6rn0JdH9LTn2BO27xvcKBY7YBbJ3c,487 +rest_framework/templates/rest_framework/inline/dict_field.html,sha256=4EWRFxidLMSc_2kbaP3VcXSaQFVAjfmPi00gb3pHiKg,228 +rest_framework/templates/rest_framework/inline/fieldset.html,sha256=acBYZDeivx33bLNIYNKlXG_11YDBtIVUihbFeHGmy8M,171 +rest_framework/templates/rest_framework/inline/form.html,sha256=yo9PS2__lzBuYSue812MwGmi3HT6kIAzHvAQBaqJAGY,149 +rest_framework/templates/rest_framework/inline/input.html,sha256=mMWTdifDKSnma20ga7gYoHGuGbHAJuxinBQIrBqjs1A,530 +rest_framework/templates/rest_framework/inline/list_field.html,sha256=bafZBHQw3YqlJYGVaxFJgtj_pon9BiuEuCU7WU6a-LM,221 +rest_framework/templates/rest_framework/inline/list_fieldset.html,sha256=gPL69kBW9RBq_qIRvFrc26a0bvFqrCaWkOnarN5uJsw,62 +rest_framework/templates/rest_framework/inline/radio.html,sha256=nqjfBZcfpFjZ-ELyaLkio-wlw5fkPAG1OAlEbAsxk2Q,793 +rest_framework/templates/rest_framework/inline/select.html,sha256=rIDuGfGFZuc-5CUVMIRne4x0vBbAg-z_MWz139hVJvw,879 +rest_framework/templates/rest_framework/inline/select_multiple.html,sha256=3zoyMlBWFNDVT7yI-zgN3lMVPGmWOBRKB6-Qyzlu174,917 +rest_framework/templates/rest_framework/inline/textarea.html,sha256=0ZpewR8LDx9xLoMgs59r12AQsZVnbolNf4P7EsnIrEc,376 +rest_framework/templates/rest_framework/login.html,sha256=mZOh88AfLsiRWGPjJlvvOkvuvmMQwxTyjGZrzcXkxlQ,122 +rest_framework/templates/rest_framework/login_base.html,sha256=ZsWKtNWD0Em0cxHn-bjkeEFTecTOzsL4Qu_pgAO48L0,2857 +rest_framework/templates/rest_framework/pagination/numbers.html,sha256=6cnFpCm_xLvgUCkyGPUtV2zMgBz_mvBJhu98aYWbOoM,1183 +rest_framework/templates/rest_framework/pagination/previous_and_next.html,sha256=tvVdDzQeAX_mqre0ei8PO-bviFlTmEWVEGpfPQ9tmuc,456 +rest_framework/templates/rest_framework/raw_data_form.html,sha256=-96O3lHTPA0zP3zq19xofYvzT8oPbmghHY5DvP-laIM,335 +rest_framework/templates/rest_framework/schema.js,sha256=UFL1wg4ArGD2gAyDfqVNCTm1V9_5dxv7kYGyR5oBaGc,136 +rest_framework/templates/rest_framework/vertical/checkbox.html,sha256=5ZMJNFq6ERwAI06iGHL5m3XmMIgTmJG7vaw6WczjTfg,543 +rest_framework/templates/rest_framework/vertical/checkbox_multiple.html,sha256=MzJT5dw-vV2zNaJYgmL6W9lTlDx_CDGV-vA8AEEW6Fs,1157 +rest_framework/templates/rest_framework/vertical/dict_field.html,sha256=Pqk22yWIWaXUJYhqYCHmGwOCiKbhvUPjl-IWsC8uSbs,252 +rest_framework/templates/rest_framework/vertical/fieldset.html,sha256=TQsf1yWktrPAiPZCavwjyX3p5p9IjFk1bQOAXynS73E,346 +rest_framework/templates/rest_framework/vertical/form.html,sha256=yo9PS2__lzBuYSue812MwGmi3HT6kIAzHvAQBaqJAGY,149 +rest_framework/templates/rest_framework/vertical/input.html,sha256=lLcDs6xixer6eQZqjI5x-5pThUDNcil9lWNYTmNOIkk,801 +rest_framework/templates/rest_framework/vertical/list_field.html,sha256=JySAf36X8WXjDtNObb1kpYb6_lJXsLqB6Z99-c2_MnE,245 +rest_framework/templates/rest_framework/vertical/list_fieldset.html,sha256=TvSzps4U1WQTvbxWRrubRvjfiD8KdUym4wthTRxsumg,222 +rest_framework/templates/rest_framework/vertical/radio.html,sha256=xOYpOkf0SkCnNOwLSXZ9nJkjIc-KY3XnRU1_JJwcd8g,1809 +rest_framework/templates/rest_framework/vertical/select.html,sha256=qZcO0qN2XZIcGw1Rrsdkm8dfVqWw4nKMVaUettX-W3k,1162 +rest_framework/templates/rest_framework/vertical/select_multiple.html,sha256=97Rtt11FQHTX0yk-ksj3dchMXO7BBC2U4_6WZqqpegI,1184 +rest_framework/templates/rest_framework/vertical/textarea.html,sha256=xaGbiWJDGIWHgWLSCBpZXjf8FVDBo0LvCqHlSs-h5EY,694 +rest_framework/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/templatetags/__pycache__/__init__.cpython-310.pyc,, +rest_framework/templatetags/__pycache__/rest_framework.cpython-310.pyc,, +rest_framework/templatetags/rest_framework.py,sha256=hnS0VzRCtl-_A39iV7LXqN6yQ-aI20Hkttafa1tNf0A,9870 +rest_framework/test.py,sha256=AROxaj23n6CB0aSsW5wFV7JGDCX8Am2AcL7BrfQKeZo,15085 +rest_framework/throttling.py,sha256=WGKkN9i2u2O0EcSQMQKSpaufZOMZIjEsuaR4srg7cK0,8067 +rest_framework/urlpatterns.py,sha256=j2SytOi_09uhyvZsVQLhkvnlc8slxE2_4jWUxf0pRb8,4235 +rest_framework/urls.py,sha256=JiEpSQau4E-m8xjNj-4mdcP3oGdf5MnsvFdnTFk7y0Y,615 +rest_framework/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework/utils/__pycache__/__init__.cpython-310.pyc,, +rest_framework/utils/__pycache__/breadcrumbs.cpython-310.pyc,, +rest_framework/utils/__pycache__/encoders.cpython-310.pyc,, +rest_framework/utils/__pycache__/field_mapping.cpython-310.pyc,, +rest_framework/utils/__pycache__/formatting.cpython-310.pyc,, +rest_framework/utils/__pycache__/html.cpython-310.pyc,, +rest_framework/utils/__pycache__/humanize_datetime.cpython-310.pyc,, +rest_framework/utils/__pycache__/json.cpython-310.pyc,, +rest_framework/utils/__pycache__/mediatypes.cpython-310.pyc,, +rest_framework/utils/__pycache__/model_meta.cpython-310.pyc,, +rest_framework/utils/__pycache__/representation.cpython-310.pyc,, +rest_framework/utils/__pycache__/serializer_helpers.cpython-310.pyc,, +rest_framework/utils/__pycache__/urls.cpython-310.pyc,, +rest_framework/utils/breadcrumbs.py,sha256=IwjiRRwqTjXkdFR4sIt76EV9ucvzQA-ORiF1yI1Tj2I,2039 +rest_framework/utils/encoders.py,sha256=jKzfbZmqXXqeHAZUWClq2Y4TRrrEjHhEfUkCiCoimMA,2523 +rest_framework/utils/field_mapping.py,sha256=WdMgIIc5ijmTOtm4jCgFwonnktrOA-MKknBamQ-DSuU,11516 +rest_framework/utils/formatting.py,sha256=z292GYwr3WpcgRECnlouhQZgQk-m7LhsoQXRz1O0p-M,3015 +rest_framework/utils/html.py,sha256=2Bas2KS7dst6mdGUVSROPi9RUyD38Z1SPza_0WbV8Ts,2294 +rest_framework/utils/humanize_datetime.py,sha256=CeC4QWwfFKdn2RXHGYRaqVcOwp0J80J_AJsnx2ClVJ0,1281 +rest_framework/utils/json.py,sha256=1qVOOt_DuaQqO4ePub-jT29lZG-9sNmGLDEqW42BAZ0,1027 +rest_framework/utils/mediatypes.py,sha256=WsnUkTOEowf_PWG1txUqzqnIOzeETz0QjMhiEJ1r5j0,2494 +rest_framework/utils/model_meta.py,sha256=XAyM0os1O3m-lKIH6Qod3_k_7b1njSSgs_lCog5KQcE,5245 +rest_framework/utils/representation.py,sha256=Twi111DBDw-wWZz28tyW5bL0UxBfVCY80AAgh3Z_9FI,2976 +rest_framework/utils/serializer_helpers.py,sha256=cR1s_HyO7bGeFBaqD50iIdtjvVV0_FYiyFXcrQ9V9jI,5924 +rest_framework/utils/urls.py,sha256=5hagmITUV4AvYmhFRHccOvXx3Yn-OL6yEA1eYT4_bk8,1052 +rest_framework/validators.py,sha256=6lCy8AnQBipJSqDwF1_c5CiS6YW0zoWkId4X7GzFUG8,10338 +rest_framework/versioning.py,sha256=Uqnd1FKUJw0xQqHiIKWMyxhUfhtauVDn-39LYOAfayc,6791 +rest_framework/views.py,sha256=R7Q0LkGui_aSpHDj0Uc1Pbk00LU0eyKY-ge5QgrsGsM,18777 +rest_framework/viewsets.py,sha256=xJoWLUy1g7Ijwq0D9LQdVXNa_lIL8jCM7efks7ksVcY,9049 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..becc9a66ea739ba941d48a749e248761cc6e658a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..6adea4d54c6f904cacec4a4633d4ccb335c37473 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework-3.14.0.dist-info/top_level.txt @@ -0,0 +1 @@ +rest_framework diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/LICENSE.txt b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f17f358356f4199303b6eb33f06a8390677afed --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright 2017 David Sanders + +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/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..8fd8cc3d4e9f0d71d79aeb968150a76926f6b737 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/METADATA @@ -0,0 +1,99 @@ +Metadata-Version: 2.1 +Name: djangorestframework-simplejwt +Version: 4.8.0 +Summary: A minimal JSON Web Token authentication plugin for Django REST Framework +Home-page: https://github.com/jazzband/djangorestframework-simplejwt +Author: David Sanders +Author-email: davesque@gmail.com +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Django +Classifier: Framework :: Django :: 2.2 +Classifier: Framework :: Django :: 3.1 +Classifier: Framework :: Django :: 3.2 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.7 +License-File: LICENSE.txt +Requires-Dist: django +Requires-Dist: djangorestframework +Requires-Dist: pyjwt (<3,>=2) +Provides-Extra: dev +Requires-Dist: pytest-watch ; extra == 'dev' +Requires-Dist: wheel ; extra == 'dev' +Requires-Dist: twine ; extra == 'dev' +Requires-Dist: ipython ; extra == 'dev' +Requires-Dist: cryptography ; extra == 'dev' +Requires-Dist: pytest-cov ; extra == 'dev' +Requires-Dist: pytest-django ; extra == 'dev' +Requires-Dist: pytest-xdist ; extra == 'dev' +Requires-Dist: pytest ; extra == 'dev' +Requires-Dist: tox ; extra == 'dev' +Requires-Dist: flake8 ; extra == 'dev' +Requires-Dist: pep8 ; extra == 'dev' +Requires-Dist: isort ; extra == 'dev' +Requires-Dist: Sphinx (<2,>=1.6.5) ; extra == 'dev' +Requires-Dist: sphinx-rtd-theme (>=0.1.9) ; extra == 'dev' +Requires-Dist: python-jose (==3.0.0) ; extra == 'dev' +Provides-Extra: doc +Requires-Dist: Sphinx (<2,>=1.6.5) ; extra == 'doc' +Requires-Dist: sphinx-rtd-theme (>=0.1.9) ; extra == 'doc' +Provides-Extra: lint +Requires-Dist: flake8 ; extra == 'lint' +Requires-Dist: pep8 ; extra == 'lint' +Requires-Dist: isort ; extra == 'lint' +Provides-Extra: python-jose +Requires-Dist: python-jose (==3.0.0) ; extra == 'python-jose' +Provides-Extra: test +Requires-Dist: cryptography ; extra == 'test' +Requires-Dist: pytest-cov ; extra == 'test' +Requires-Dist: pytest-django ; extra == 'test' +Requires-Dist: pytest-xdist ; extra == 'test' +Requires-Dist: pytest ; extra == 'test' +Requires-Dist: tox ; extra == 'test' + +Simple JWT +========== + +.. image:: https://jazzband.co/static/img/badge.svg + :target: https://jazzband.co/ + :alt: Jazzband +.. image:: https://github.com/jazzband/djangorestframework-simplejwt/workflows/Test/badge.svg + :target: https://github.com/jazzband/djangorestframework-simplejwt/actions + :alt: GitHub Actions +.. image:: https://codecov.io/gh/jazzband/djangorestframework-simplejwt/branch/master/graph/badge.svg + :target: https://codecov.io/gh/jazzband/djangorestframework-simplejwt +.. image:: https://img.shields.io/pypi/v/djangorestframework-simplejwt.svg + :target: https://pypi.python.org/pypi/djangorestframework-simplejwt +.. image:: https://img.shields.io/pypi/pyversions/djangorestframework-simplejwt.svg + :target: https://pypi.python.org/pypi/djangorestframework-simplejwt +.. image:: https://img.shields.io/pypi/djversions/djangorestframework-simplejwt.svg + :target: https://pypi.python.org/pypi/djangorestframework-simplejwt +.. image:: https://readthedocs.org/projects/django-rest-framework-simplejwt/badge/?version=latest + :target: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/ + +Abstract +-------- + +Simple JWT is a JSON Web Token authentication plugin for the `Django REST +Framework <http://www.django-rest-framework.org/>`__. + +For full documentation, visit `django-rest-framework-simplejwt.readthedocs.io +<https://django-rest-framework-simplejwt.readthedocs.io/en/latest/>`__. + +Looking for Maintainers +----------------------- + +For more information, see `here +<https://github.com/jazzband/djangorestframework-simplejwt/issues/207>`__. + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..77628512134e45dc444176f8dbf169ec289dfc64 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/RECORD @@ -0,0 +1,86 @@ +djangorestframework_simplejwt-4.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +djangorestframework_simplejwt-4.8.0.dist-info/LICENSE.txt,sha256=ciQ8ALb0EdxGfuovFpFHIOHbMu3sbmGzV66o1F46vVs,1053 +djangorestframework_simplejwt-4.8.0.dist-info/METADATA,sha256=NRaV0VYj2HH2933YF-kamglurGBqMP35PxRaCc6j2eM,4056 +djangorestframework_simplejwt-4.8.0.dist-info/RECORD,, +djangorestframework_simplejwt-4.8.0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +djangorestframework_simplejwt-4.8.0.dist-info/top_level.txt,sha256=ULa72yxXIj-d43kS2qYIdb-929ri5OcYWJk3P-7wd0E,25 +rest_framework_simplejwt/__init__.py,sha256=KCwO-HeNg-Jt9D6B1TAXIQGjhrEEV4-SCdTaW9npAK4,230 +rest_framework_simplejwt/__pycache__/__init__.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/authentication.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/backends.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/compat.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/exceptions.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/models.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/serializers.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/settings.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/state.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/tokens.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/utils.cpython-310.pyc,, +rest_framework_simplejwt/__pycache__/views.cpython-310.pyc,, +rest_framework_simplejwt/authentication.py,sha256=LSdSlrynk5cDwZJ_mlHKKdmeSAG9fb8OX2dbRxJc7uo,5038 +rest_framework_simplejwt/backends.py,sha256=wS0BTPmkU41KH1JRW0gBA5Y4AkRLAbs5XG8n2rFXpu8,3376 +rest_framework_simplejwt/compat.py,sha256=7RlpILv87I-eyNLWRx_Um9fknto6Lv1Rs0cv74jQ_Ok,1286 +rest_framework_simplejwt/exceptions.py,sha256=bPl2BhMg7w41yAUviU6UnuwhlsPM5qrAx4dN8BXzreE,994 +rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.mo,sha256=gIts-nw3-UkC3BZop3FMOIYQoX95UtbE5mytLYWvxoQ,2050 +rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.po,sha256=aLK4JFyVvTtcLqAhxC-ibi0fS7wne3jwAHyEfElbeIk,2814 +rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.mo,sha256=8v2_6RbtiwT7kPoXJER1RORDfdjioYb9TCFuL2KPBr0,2057 +rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.po,sha256=Ld9MT_6ysotXNE7XJfZRkAEj2RAW2VFGMlZ5vpsKtjY,2833 +rest_framework_simplejwt/locale/es/LC_MESSAGES/django.mo,sha256=D-A6lAwaU4_ydEC4fESwCCvXOneQAGNJkNpis1ZoDFc,2349 +rest_framework_simplejwt/locale/es/LC_MESSAGES/django.po,sha256=y6O3iOBsTg7T5vhnXSLUHG2PzS-mkBc92KU4yoGihQo,2988 +rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.mo,sha256=Vbd9o4d_NeyH-5ea7v7HoecLdIZYGl-OOVlcziFFkC0,2166 +rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.po,sha256=-8u_ohQMZ90JaWFHzwwKo6QPfsHuoOc_rO821JvWsXk,3031 +rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.mo,sha256=7j2aI8wjaUvkNiN0FwiOmjtMRfZYMflFWjAzqoD0j2A,2128 +rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.po,sha256=iyVB-bxV3tXKCzCpXvNr_xUUH37IlzWL-kKdyyiXvEU,2914 +rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.mo,sha256=7TNTTxFmuIrhDe0PkBg-NWdVVKhVmpIvSu8DUPcvxMg,2363 +rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.po,sha256=QVYPPEUlT4GyiMkLlbdHZdMmOglLEfVeTBBNUz8RLQE,3136 +rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.mo,sha256=z0ZtzKkGYjaIeFb0z8apGswKZySX2IMT3cGmr8mhJ0g,2352 +rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.po,sha256=QGfKSdbvuA6gnZVPz6xlFmPP9zEY8SQvKovONGzD51I,2996 +rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.mo,sha256=rJjX8T_hbAPk1f7TQmxn7CWmvvAg3orU0Qvva97QFXU,2333 +rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.po,sha256=9eRpMPGNagQPOMSMsrBKiWbosvxVaZ0aJl3Ej7X86dI,2972 +rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.mo,sha256=qWXz8NAll-sPs-QgoAJPPY2LJ1koqUL9LPAXH10I8UE,2433 +rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.po,sha256=EwWdaEtYSdgEP_4_3LRAtBUwx4_dL3B5OIB0Mhs6rK4,3083 +rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.mo,sha256=dvfmoRBUtvba6JtyXXGJ3RsBUyk7KT2iKVMbSD0-zYw,1989 +rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.po,sha256=QFMUopUG0pUupW8Byl5wKQQbRylS-m93rb-RDIM2KOk,2767 +rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.mo,sha256=i3FV5EshMgmZXmwtL8gIWy96VaUhwtjsxdVd6-yZxyY,2106 +rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.po,sha256=e9lzPZYS0Ry9CmdhdvfVEDaoManF_naqjCt5rq-wN_g,2876 +rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.mo,sha256=ZLUB0sYVw30sXmVrD5pPF9Ap2XOHf4GRUIF14TD83g4,2324 +rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.po,sha256=SZYumNYU-LhDbkE2sihQASRqnXpZFWLn4jKZjRtkFz8,2961 +rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.mo,sha256=TEUJ1ZcybkRAPYTiHfFhujTdg5DKmNWCWxyAULN9CSE,2784 +rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.po,sha256=G2Lc1OCBpTWkCV4RqCNRhmRkh4evquwa-ckW_5zq1-Y,3578 +rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.mo,sha256=EdndFgTOeg3QI54kgkiefp6-Zp8ahHcI7fOmG8-iYYM,3039 +rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.po,sha256=GnpjM3cAAd4o5FncvWq6bEge8Fdk-f-1my5KGFEBvuM,4342 +rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.mo,sha256=6GCeHocaKNDVskioSPa6OiMMKwU-liZInizILJFtn20,2162 +rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.po,sha256=Tg7MJHiGSuW4paVryUpV1dcVOCXsWNzB69DBaUUnxFM,2842 +rest_framework_simplejwt/models.py,sha256=DLpfldNCaM5EGb41GyQtHjQDmfNPhzXm-wPGsQA04Xw,2832 +rest_framework_simplejwt/serializers.py,sha256=Km86qhTwMXWKnhX5lHaBGZty5SAClLyk4DjYeHLMGIM,4467 +rest_framework_simplejwt/settings.py,sha256=XaXhjJlLnmf2CpFDlYIQCPHyUD90FsoyO_9hqdot2HM,2464 +rest_framework_simplejwt/state.py,sha256=CMPLc8XjraIpcAvzIwy_faHaO85C6DCy1CQMrDugHPM,296 +rest_framework_simplejwt/token_blacklist/__init__.py,sha256=n4YaJkf0tv_BeWgv86DRdFf1JPRO62W5VeIdOgQ-j68,143 +rest_framework_simplejwt/token_blacklist/__pycache__/__init__.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/__pycache__/admin.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/__pycache__/apps.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/__pycache__/models.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/admin.py,sha256=OBKc_SLMxuTFW09v1ZrSljM5LJxOCz2QgghEi4nDV8A,2344 +rest_framework_simplejwt/token_blacklist/apps.py,sha256=ZdgzcmsSxGdJ0DxssQ8YEbHPAxIC3SK1Z9BaKfKePkc,281 +rest_framework_simplejwt/token_blacklist/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework_simplejwt/token_blacklist/management/__pycache__/__init__.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework_simplejwt/token_blacklist/management/commands/__pycache__/__init__.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/management/commands/flushexpiredtokens.py,sha256=DW4ErXmkniSJ89Plc2KpCjqufAMIQyLtfRRYtLbIhqI,370 +rest_framework_simplejwt/token_blacklist/migrations/0001_initial.py,sha256=hc2KYhJlSSE5PJQBVbrjjUZWbWQTM1IemIYxxwdpN7c,1471 +rest_framework_simplejwt/token_blacklist/migrations/0002_outstandingtoken_jti_hex.py,sha256=Pc6WadwU4lfKB323YBBnHrhkTgUwLrUi5MwB6yMrQCU,367 +rest_framework_simplejwt/token_blacklist/migrations/0003_auto_20171017_2007.py,sha256=NhFgckBbJmFzbJYSyy-zwJMUVp9UtsielQTiwVXlx88,907 +rest_framework_simplejwt/token_blacklist/migrations/0004_auto_20171017_2013.py,sha256=ZtYlshbdqLnVpS_X1OpLrenU0Mieu4830DAb2gLtMJo,370 +rest_framework_simplejwt/token_blacklist/migrations/0005_remove_outstandingtoken_jti.py,sha256=d9XWNzFgi-UARWk2SsCbSoiBjsgS55JEkPqMbe2FMY0,294 +rest_framework_simplejwt/token_blacklist/migrations/0006_auto_20171017_2113.py,sha256=LttI2YUbunFeus9-1cPG7xWzt_ak-Ri3ZWpFdYtFNPo,339 +rest_framework_simplejwt/token_blacklist/migrations/0007_auto_20171017_2214.py,sha256=q78cLOVgDCDutGnC0am3ECWxg2kEpmYyi2HxnuO3DaY,681 +rest_framework_simplejwt/token_blacklist/migrations/0008_migrate_to_bigautofield.py,sha256=eVFF-UDwPOXVK-ZltFtaU9hqUG4_tciFn3hYsHvEqG0,632 +rest_framework_simplejwt/token_blacklist/migrations/0010_fix_migrate_to_bigautofield.py,sha256=Wsdi4v5bcvQ_i8OzIQG0YF9DCD8sQTgPwAZBCvf9YY8,693 +rest_framework_simplejwt/token_blacklist/migrations/0011_linearizes_history.py,sha256=NMLmpXzB8zzbDfbXrg5-nyS2Nt0zEB114bXV68KTj3I,606 +rest_framework_simplejwt/token_blacklist/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rest_framework_simplejwt/token_blacklist/migrations/__pycache__/0001_initial.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/migrations/__pycache__/__init__.cpython-310.pyc,, +rest_framework_simplejwt/token_blacklist/models.py,sha256=iq7F3ANIui5OZ5ibs-XZvTPBkd0hllvvrx4yvgR5po4,1598 +rest_framework_simplejwt/tokens.py,sha256=f-9nrU7J4UDjL9UbpCllMnBnQk2WSXK304TkabhEphM,10107 +rest_framework_simplejwt/utils.py,sha256=5Yy-3cK5b-Ij_2zlaLyyYgJx2pZElc_b75eqSjSlIQY,637 +rest_framework_simplejwt/views.py,sha256=COe9Z23M9iCxUvYqlXXgw0cMxcxMbdXhKTHn2s8V25Y,2394 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..5bad85fdc1cd08553756d0fb2c7be8b5ad6af7fb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..d88fdcf05e08575afe3cc33faf5a3aa64aa05ec7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djangorestframework_simplejwt-4.8.0.dist-info/top_level.txt @@ -0,0 +1 @@ +rest_framework_simplejwt diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f3e9df420af31d6ea8d86c82c25315c63af0416b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2019 SUNSCRAPERS + +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/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..8f708f47d5a12421b82fbd23d149ae837b1b7faf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/METADATA @@ -0,0 +1,208 @@ +Metadata-Version: 2.1 +Name: djoser +Version: 2.1.0 +Summary: REST implementation of Django authentication system. +Home-page: https://github.com/sunscrapers/djoser +License: MIT +Author: Sunscrapers +Author-email: info@sunscrapers.com +Maintainer: Tomasz Wójcik +Maintainer-email: t.wojcik@sunscrapers.com +Requires-Python: >=3.6.1,<4.0.0 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Django +Classifier: Framework :: Django :: 2.2 +Classifier: Framework :: Django :: 3.1 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Provides-Extra: test +Requires-Dist: asgiref (>=3.2.10,<4.0.0) +Requires-Dist: codecov (>=2.0.16,<3.0.0); extra == "test" +Requires-Dist: coreapi (>=2.3.3,<3.0.0) +Requires-Dist: coverage (>=5.3,<6.0); extra == "test" +Requires-Dist: django-templated-mail (>=1.1.1,<2.0.0) +Requires-Dist: djangorestframework-simplejwt (>=4.3.0,<5.0.0) +Requires-Dist: djet (>=0.2.2,<0.3.0); extra == "test" +Requires-Dist: importlib-metadata (>=1.0,<2.0); python_version < "3.8" +Requires-Dist: pytest (>=6.0.2,<7.0.0); extra == "test" +Requires-Dist: pytest-cov (>=2.10.1,<3.0.0); extra == "test" +Requires-Dist: pytest-django (>=3.10.0,<4.0.0); extra == "test" +Requires-Dist: pytest-pythonpath (>=0.7.3,<0.8.0); extra == "test" +Requires-Dist: social-auth-app-django (>=4.0.0,<5.0.0) +Project-URL: Documentation, https://djoser.readthedocs.io/ +Project-URL: Repository, https://github.com/sunscrapers/djoser +Description-Content-Type: text/x-rst + +====== +djoser +====== + +.. image:: https://img.shields.io/pypi/v/djoser.svg + :target: https://pypi.org/project/djoser + +.. image:: https://img.shields.io/travis/sunscrapers/djoser/master.svg + :target: https://travis-ci.org/sunscrapers/djoser + +.. image:: https://img.shields.io/codecov/c/github/sunscrapers/djoser.svg + :target: https://codecov.io/gh/sunscrapers/djoser + +.. image:: https://api.codacy.com/project/badge/Grade/c9bf80318d2741e5bb63912a5e0b32dc + :alt: Codacy Badge + :target: https://app.codacy.com/app/dekoza/djoser?utm_source=github.com&utm_medium=referral&utm_content=sunscrapers/djoser&utm_campaign=Badge_Grade_Dashboard + +.. image:: https://img.shields.io/pypi/dm/djoser + :target: https://img.shields.io/pypi/dm/djoser + + +REST implementation of `Django <https://www.djangoproject.com/>`_ authentication +system. **djoser** library provides a set of `Django Rest Framework <https://www.django-rest-framework.org/>`_ +views to handle basic actions such as registration, login, logout, password +reset and account activation. It works with +`custom user model <https://docs.djangoproject.com/en/dev/topics/auth/customizing/>`_. + +Instead of reusing Django code (e.g. ``PasswordResetForm``), we reimplemented +few things to fit better into `Single Page App <https://en.wikipedia.org/wiki/Single-page_application>`_ +architecture. + +Developed by `SUNSCRAPERS <http://sunscrapers.com/>`_ with passion & patience. + +.. image:: https://asciinema.org/a/94J4eG2tSBD2iEfF30a6vGtXw.png + :target: https://asciinema.org/a/94J4eG2tSBD2iEfF30a6vGtXw + +Requirements +============ + +To be able to run **djoser** you have to meet following requirements: + +- Python (3.6, 3.7, 3.8, 3.9) +- Django (2.2, 3.1) +- Django REST Framework 3.11.1 + +If you need to support other versions, please use djoser<2. + +Installation +============ + +Simply install using ``pip``: + +.. code-block:: bash + + $ pip install djoser + +And continue with the steps described at +`configuration <https://djoser.readthedocs.io/en/latest/getting_started.html#configuration>`_ +guide. + +Documentation +============= + +Documentation is available to study at +`https://djoser.readthedocs.io <https://djoser.readthedocs.io>`_ +and in ``docs`` directory. + +Contributing and development +============================ + +To start developing on **djoser**, clone the repository: + +.. code-block:: bash + + $ git clone git@github.com:sunscrapers/djoser.git + +We use `poetry <https://python-poetry.org/>`_ as dependency management and packaging tool. + +.. code-block:: bash + + $ cd djoser + $ poetry install -E test + +This will create a virtualenv with all development dependencies. + +To run the test just type: + +.. code-block:: bash + + $ poetry run py.test testproject + +We also preapred a convenient ``Makefile`` to automate commands above: + +.. code-block:: bash + + $ make init + $ make test + +To activate the virtual environment run + +.. code-block:: bash + + $ poetry shell + +Without poetry +-------------- + +New versions of ``pip`` can use ``pyproject.toml`` to build the package and install its dependencies. + +.. code-block:: bash + + $ pip install .[test] + +.. code-block:: bash + + $ cd testproject + $ ./manage.py test + +Tox +--- + +If you need to run tests against all supported Python and Django versions then invoke: + +.. code-block:: bash + + $ poetry run tox -p all + +Example project +--------------- + +You can also play with test project by running following commands: + +.. code-block:: bash + + $ make migrate + $ make runserver + +Commiting your code +------------------- + +Before sending patches please make sure you have `pre-commit <https://pre-commit.com/>`_ activated in your local git repository: + +.. code-block:: bash + + $ pre-commit install + +This will ensure that your code is cleaned before you commit it. +Some steps (like black) automatically fix issues but the show their status as FAILED. +Just inspect if eveything is OK, git-add the files and retry the commit. +Other tools (like flake8) require you to manually fix the issues. + + +Similar projects +================ + +List of projects related to Django, REST and authentication: + +- `django-rest-framework-simplejwt <https://github.com/davesque/django-rest-framework-simplejwt>`_ +- `django-oauth-toolkit <https://github.com/evonove/django-oauth-toolkit>`_ +- `django-rest-auth <https://github.com/Tivix/django-rest-auth>`_ (not maintained) +- `django-rest-framework-digestauth <https://github.com/juanriaza/django-rest-framework-digestauth>`_ (not maintained) + +Please, keep in mind that while using custom authentication and TokenCreateSerializer +validation, there is a path that **ignores intentional return of None** from authenticate() +and try to find User using parameters. Probably, that will be changed in the future. + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..85046e2041141b86b8c4264873c4decfb0bbeed6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/RECORD @@ -0,0 +1,71 @@ +djoser-2.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +djoser-2.1.0.dist-info/LICENSE,sha256=WMeXpNZy6zo3wE5g31cFFMAC59lpwiw0BR1mBKtVPUA,1083 +djoser-2.1.0.dist-info/METADATA,sha256=5NBWwDHOpSBglvaFq1Brl2KihlkCzz-1pZV0ENAVU3o,6578 +djoser-2.1.0.dist-info/RECORD,, +djoser-2.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +djoser-2.1.0.dist-info/WHEEL,sha256=SrtnPGVTMeYWttls9xnWA01eUhCZ3ufFdJUYb1J3r-U,83 +djoser/.codacy.yml,sha256=jioZpHURXQT7hcYPt2mI9g9qdrogYe6A5249UFb4dS8,50 +djoser/__init__.py,sha256=6bV_nsPP-4FipN-Be3FLg_091mtybitPVgRGMse9eY4,167 +djoser/__pycache__/__init__.cpython-310.pyc,, +djoser/__pycache__/compat.cpython-310.pyc,, +djoser/__pycache__/conf.cpython-310.pyc,, +djoser/__pycache__/constants.cpython-310.pyc,, +djoser/__pycache__/email.cpython-310.pyc,, +djoser/__pycache__/permissions.cpython-310.pyc,, +djoser/__pycache__/serializers.cpython-310.pyc,, +djoser/__pycache__/signals.cpython-310.pyc,, +djoser/__pycache__/utils.cpython-310.pyc,, +djoser/__pycache__/views.cpython-310.pyc,, +djoser/compat.py,sha256=jOtZRG6gQy5GRzN1i6YsyfKkGKoxr9ExnQ81t7K6rEU,267 +djoser/conf.py,sha256=l090dHL3pUhuQVX6AWiM_XkL_V6oY0MqhuAE0tq4Lfk,6549 +djoser/constants.py,sha256=ct-nnHspzPwxYTp0fEkl5JPQoHqezYnNfpngmlMzVT0,728 +djoser/email.py,sha256=g-LrQY8_RPelpDN1FDSgy6zabd2egKGBJ2gXMxIPlwY,1861 +djoser/locale/de/LC_MESSAGES/django.mo,sha256=aIbIwheN4Tu0Zrat2a0ggN0Nw8JtbO-Ck5Tx72di61Q,3170 +djoser/locale/de/LC_MESSAGES/django.po,sha256=mIvoymwbA391Z_gSJbPIDIDvopti5Es2hMy6UUx803M,4769 +djoser/locale/es/LC_MESSAGES/django.mo,sha256=LoV2lAiP46aC60DY6jVMcpBxHAsuZNR2dec-8frH_g8,3633 +djoser/locale/es/LC_MESSAGES/django.po,sha256=JQZ1nvRDSb8LVh8QSz1Fz3ytN4oLLPbgoZxvVswZVHY,6993 +djoser/locale/fr/LC_MESSAGES/django.mo,sha256=5nOjyF9qh_b6RiMzscJ9D9veI3EszaB70ooChqMBKCM,3233 +djoser/locale/fr/LC_MESSAGES/django.po,sha256=Wt-8LeRmM9bkqUuNqT88IcjPgfBQ4AJnkAWhN8QriOc,4867 +djoser/locale/ka/LC_MESSAGES/django.mo,sha256=x8OeN-Ndzn5y02bd30FDYa5MOohETG_l8dJz_3MrKAw,4521 +djoser/locale/ka/LC_MESSAGES/django.po,sha256=QlyljaDE0f6zbbOI4M3GOS0mUCVE-xwL_WTKYZUZMDk,6034 +djoser/locale/pl/LC_MESSAGES/django.mo,sha256=sgHSVdo56mqjAljGayldgXMvJ8vZloj6d4GchLaRtks,3160 +djoser/locale/pl/LC_MESSAGES/django.po,sha256=Y_-sTw4IijDN8Ca63C0FrRywZffcEeHoIetJQK3z0NA,4994 +djoser/locale/pt_BR/LC_MESSAGES/django.mo,sha256=dt70GGU5S7WUls-VN-L6HatywT4tASBuxRa4xSUfAx8,3050 +djoser/locale/pt_BR/LC_MESSAGES/django.po,sha256=T_fxpDQyH_GvPZX0qJrNnV6HcWcDgq2sXJbL1BVysvg,4845 +djoser/locale/ru_RU/LC_MESSAGES/django.mo,sha256=XFTIXY_GZIiHGSYKume1dvp8UDhSWTPrydeIv6Dkp30,4214 +djoser/locale/ru_RU/LC_MESSAGES/django.po,sha256=AcHoSmLOlC5x5Otf5ev1FLcsOFyLTeI32IKifWnteW0,6151 +djoser/permissions.py,sha256=xl4TV7UNb_oKLhAFCB0xqHcIAIn6GsXy6WYrz9YyjQI,574 +djoser/serializers.py,sha256=1Fd6Dt5-cZ8GKL4Auq63ZPc5mV1pL5k8wSNO-zQN1-U,11018 +djoser/signals.py,sha256=UVxojEZf5Of1bkzPbdGkm7_9SBmzcokwrQu4pbEHsTA,200 +djoser/social/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +djoser/social/__pycache__/__init__.cpython-310.pyc,, +djoser/social/__pycache__/serializers.cpython-310.pyc,, +djoser/social/__pycache__/urls.cpython-310.pyc,, +djoser/social/__pycache__/views.cpython-310.pyc,, +djoser/social/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +djoser/social/backends/__pycache__/__init__.cpython-310.pyc,, +djoser/social/backends/__pycache__/facebook.cpython-310.pyc,, +djoser/social/backends/facebook.py,sha256=OCA_jfECjYcn4TpKMlWMGRrtwjTNsasZPcwgfXx7Dm4,132 +djoser/social/serializers.py,sha256=C1WrcrzP0N1Gs6F9xZ-ngw8XrcooJRk7uO2LYvrp2Uw,2014 +djoser/social/token/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +djoser/social/token/__pycache__/__init__.cpython-310.pyc,, +djoser/social/token/__pycache__/jwt.cpython-310.pyc,, +djoser/social/token/jwt.py,sha256=1Sd14Bp9CX8BgqNRBj5fVNrRV7OKr_3IK53dDc0pqAA,362 +djoser/social/urls.py,sha256=dWDxhxN9ir7uoX-NS7CzFKuJ8NkgCu-vDn4qDxhGmVE,210 +djoser/social/views.py,sha256=jByfDVmMzBfSo3QxAS74lNzs2hLtD_vNDWcFq7eU4_M,991 +djoser/templates/email/activation.html,sha256=1XQhz5aU-9n2HsxeC79pYaWaMtelySpmi14-cal71SY,1014 +djoser/templates/email/confirmation.html,sha256=QrjWgxF4XLAgKSfwrkYzKOJmoeXa2LZhPt8s-oJnuiU,616 +djoser/templates/email/password_changed_confirmation.html,sha256=DVAW6kNKrwbGnULeB-3hrpib-sc57OfjaRUSD1Y1l1Q,565 +djoser/templates/email/password_reset.html,sha256=wBcuE1KpNkFFamKHNWZj1FlpQgHoXpWsXbA1IkUhMk0,1201 +djoser/templates/email/username_changed_confirmation.html,sha256=9z96DdWTCdPC-cFhKfsGiYWo1nsg7Foj6MmN2U4Cqw0,565 +djoser/templates/email/username_reset.html,sha256=Wsp-JRZBk-Hz2j364jtkhLseC44ErvwaRuCDM6NKD88,1201 +djoser/urls/__init__.py,sha256=bbRDrYIzpBgsSkVqCdX7-vDTsVx_LFCI7e4VljgbgVc,57 +djoser/urls/__pycache__/__init__.cpython-310.pyc,, +djoser/urls/__pycache__/authtoken.cpython-310.pyc,, +djoser/urls/__pycache__/base.cpython-310.pyc,, +djoser/urls/__pycache__/jwt.cpython-310.pyc,, +djoser/urls/authtoken.py,sha256=emjxlJrqeeVsM-qLiG0p4NJunt-oZWvXgp6qhwgQJRs,240 +djoser/urls/base.py,sha256=p1hfOmDr26GIQNeupl38gpD4ZQuGQkADK3GCcQvPny8,244 +djoser/urls/jwt.py,sha256=XTwn-N5evJYQlSShVuPbqOI2qhWu9Znn61zBOM8SpvE,350 +djoser/utils.py,sha256=caFXezATGAi0ps1JYQfe_Httma8ESvQ4RZvRYLP9lCk,1196 +djoser/views.py,sha256=f2aZKaq0GUncspHPcD6HarGWI47jdDn0EBZ-zguafOM,12718 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/REQUESTED b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/REQUESTED new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..caca394ceabb1bcaa24e6e5e439c9a88ead74707 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser-2.1.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: poetry 1.0.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/.codacy.yml b/Latest_Group_Project/.venv/Lib/site-packages/djoser/.codacy.yml new file mode 100644 index 0000000000000000000000000000000000000000..686da54b77a059c694175f8274e934f75a082cb7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/.codacy.yml @@ -0,0 +1,3 @@ +exclude_paths: + - "docs/**" + - "testproject/**" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8c1f5735f28a141cda1febf38b15bc5f0cdcc477 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__init__.py @@ -0,0 +1,6 @@ +try: + import importlib.metadata as importlib_metadata +except ModuleNotFoundError: + import importlib_metadata + +__version__ = importlib_metadata.version(__name__) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa267ebceefb967d16690ae478d1b9c7729ced3b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54734ad292c6bddf07525d46a778d94d61b8d34a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/conf.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/conf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f90ba6e2130f00b296cd9b8e5541fe534cdf6acc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/conf.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/constants.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/constants.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad53903a55b807395e0d96b2fa05a434f9b57a5d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/constants.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/email.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/email.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e106de0f949eb1231cdca7330848fb6b14be878 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/email.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/permissions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/permissions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f32059841f580069f4abd78f51dbcd9c21c9a58a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/permissions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/serializers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5621f0ce7899c92bf6310f00c3e91a21c562be6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/serializers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/signals.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/signals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4677baa458ff368c223ad5a11969460c4c7fa07 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/signals.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..760582d3938d894bd57acd4b6d4245b7e5b1b6d2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db3a2a6a1d06627f392fdd203b8d5e471cc1e482 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..0c8f32651fa4ce2087ab2a15e44d0f190bff5f93 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/compat.py @@ -0,0 +1,12 @@ +from djoser.conf import settings + +__all__ = ["settings"] + + +def get_user_email(user): + email_field_name = get_user_email_field_name(user) + return getattr(user, email_field_name, None) + + +def get_user_email_field_name(user): + return user.get_email_field_name() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/conf.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..4e5845de45d622f01b05173aa6710add4ab17472 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/conf.py @@ -0,0 +1,153 @@ +from django.apps import apps +from django.conf import settings as django_settings +from django.test.signals import setting_changed +from django.utils.functional import LazyObject +from django.utils.module_loading import import_string + +DJOSER_SETTINGS_NAMESPACE = "DJOSER" + +auth_module, user_model = django_settings.AUTH_USER_MODEL.rsplit(".", 1) + +User = apps.get_model(auth_module, user_model) + + +class ObjDict(dict): + def __getattribute__(self, item): + try: + val = self[item] + if isinstance(val, str): + val = import_string(val) + elif isinstance(val, (list, tuple)): + val = [import_string(v) if isinstance(v, str) else v for v in val] + self[item] = val + except KeyError: + val = super(ObjDict, self).__getattribute__(item) + + return val + + +default_settings = { + "USER_ID_FIELD": User._meta.pk.name, + "LOGIN_FIELD": User.USERNAME_FIELD, + "SEND_ACTIVATION_EMAIL": False, + "SEND_CONFIRMATION_EMAIL": False, + "USER_CREATE_PASSWORD_RETYPE": False, + "SET_PASSWORD_RETYPE": False, + "PASSWORD_RESET_CONFIRM_RETYPE": False, + "SET_USERNAME_RETYPE": False, + "USERNAME_RESET_CONFIRM_RETYPE": False, + "PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND": False, + "USERNAME_RESET_SHOW_EMAIL_NOT_FOUND": False, + "PASSWORD_CHANGED_EMAIL_CONFIRMATION": False, + "USERNAME_CHANGED_EMAIL_CONFIRMATION": False, + "TOKEN_MODEL": "rest_framework.authtoken.models.Token", + "SERIALIZERS": ObjDict( + { + "activation": "djoser.serializers.ActivationSerializer", + "password_reset": "djoser.serializers.SendEmailResetSerializer", + "password_reset_confirm": "djoser.serializers.PasswordResetConfirmSerializer", + "password_reset_confirm_retype": "djoser.serializers.PasswordResetConfirmRetypeSerializer", + "set_password": "djoser.serializers.SetPasswordSerializer", + "set_password_retype": "djoser.serializers.SetPasswordRetypeSerializer", + "set_username": "djoser.serializers.SetUsernameSerializer", + "set_username_retype": "djoser.serializers.SetUsernameRetypeSerializer", + "username_reset": "djoser.serializers.SendEmailResetSerializer", + "username_reset_confirm": "djoser.serializers.UsernameResetConfirmSerializer", + "username_reset_confirm_retype": "djoser.serializers.UsernameResetConfirmRetypeSerializer", + "user_create": "djoser.serializers.UserCreateSerializer", + "user_create_password_retype": "djoser.serializers.UserCreatePasswordRetypeSerializer", + "user_delete": "djoser.serializers.UserDeleteSerializer", + "user": "djoser.serializers.UserSerializer", + "current_user": "djoser.serializers.UserSerializer", + "token": "djoser.serializers.TokenSerializer", + "token_create": "djoser.serializers.TokenCreateSerializer", + } + ), + "EMAIL": ObjDict( + { + "activation": "djoser.email.ActivationEmail", + "confirmation": "djoser.email.ConfirmationEmail", + "password_reset": "djoser.email.PasswordResetEmail", + "password_changed_confirmation": "djoser.email.PasswordChangedConfirmationEmail", + "username_changed_confirmation": "djoser.email.UsernameChangedConfirmationEmail", + "username_reset": "djoser.email.UsernameResetEmail", + } + ), + "CONSTANTS": ObjDict({"messages": "djoser.constants.Messages"}), + "LOGOUT_ON_PASSWORD_CHANGE": False, + "CREATE_SESSION_ON_LOGIN": False, + "SOCIAL_AUTH_TOKEN_STRATEGY": "djoser.social.token.jwt.TokenStrategy", + "SOCIAL_AUTH_ALLOWED_REDIRECT_URIS": [], + "HIDE_USERS": True, + "PERMISSIONS": ObjDict( + { + "activation": ["rest_framework.permissions.AllowAny"], + "password_reset": ["rest_framework.permissions.AllowAny"], + "password_reset_confirm": ["rest_framework.permissions.AllowAny"], + "set_password": ["djoser.permissions.CurrentUserOrAdmin"], + "username_reset": ["rest_framework.permissions.AllowAny"], + "username_reset_confirm": ["rest_framework.permissions.AllowAny"], + "set_username": ["djoser.permissions.CurrentUserOrAdmin"], + "user_create": ["rest_framework.permissions.AllowAny"], + "user_delete": ["djoser.permissions.CurrentUserOrAdmin"], + "user": ["djoser.permissions.CurrentUserOrAdmin"], + "user_list": ["djoser.permissions.CurrentUserOrAdmin"], + "token_create": ["rest_framework.permissions.AllowAny"], + "token_destroy": ["rest_framework.permissions.IsAuthenticated"], + } + ), +} + +SETTINGS_TO_IMPORT = ["TOKEN_MODEL", "SOCIAL_AUTH_TOKEN_STRATEGY"] + + +class Settings: + def __init__(self, default_settings, explicit_overriden_settings: dict = None): + if explicit_overriden_settings is None: + explicit_overriden_settings = {} + + overriden_settings = ( + getattr(django_settings, DJOSER_SETTINGS_NAMESPACE, {}) + or explicit_overriden_settings + ) + + self._load_default_settings() + self._override_settings(overriden_settings) + self._init_settings_to_import() + + def _load_default_settings(self): + for setting_name, setting_value in default_settings.items(): + if setting_name.isupper(): + setattr(self, setting_name, setting_value) + + def _override_settings(self, overriden_settings: dict): + for setting_name, setting_value in overriden_settings.items(): + value = setting_value + if isinstance(setting_value, dict): + value = getattr(self, setting_name, {}) + value.update(ObjDict(setting_value)) + setattr(self, setting_name, value) + + def _init_settings_to_import(self): + for setting_name in SETTINGS_TO_IMPORT: + value = getattr(self, setting_name) + if isinstance(value, str): + setattr(self, setting_name, import_string(value)) + + +class LazySettings(LazyObject): + def _setup(self, explicit_overriden_settings=None): + self._wrapped = Settings(default_settings, explicit_overriden_settings) + + +settings = LazySettings() + + +def reload_djoser_settings(*args, **kwargs): + global settings + setting, value = kwargs["setting"], kwargs["value"] + if setting == DJOSER_SETTINGS_NAMESPACE: + settings._setup(explicit_overriden_settings=value) + + +setting_changed.connect(reload_djoser_settings) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/constants.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..02949e13fd815380adfc12da6a689b839c4bca28 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/constants.py @@ -0,0 +1,14 @@ +from django.utils.translation import gettext_lazy as _ + + +class Messages(object): + INVALID_CREDENTIALS_ERROR = _("Unable to log in with provided credentials.") + INACTIVE_ACCOUNT_ERROR = _("User account is disabled.") + INVALID_TOKEN_ERROR = _("Invalid token for given user.") + INVALID_UID_ERROR = _("Invalid user id or user doesn't exist.") + STALE_TOKEN_ERROR = _("Stale token for given user.") + PASSWORD_MISMATCH_ERROR = _("The two password fields didn't match.") + USERNAME_MISMATCH_ERROR = _("The two {0} fields didn't match.") + INVALID_PASSWORD_ERROR = _("Invalid password.") + EMAIL_NOT_FOUND = _("User with given email does not exist.") + CANNOT_CREATE_USER_ERROR = _("Unable to create account.") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/email.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/email.py new file mode 100644 index 0000000000000000000000000000000000000000..8c01925e0d6a1ebb4efdb9aea95da91ae7816230 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/email.py @@ -0,0 +1,58 @@ +from django.contrib.auth.tokens import default_token_generator +from templated_mail.mail import BaseEmailMessage + +from djoser import utils +from djoser.conf import settings + + +class ActivationEmail(BaseEmailMessage): + template_name = "email/activation.html" + + def get_context_data(self): + # ActivationEmail can be deleted + context = super().get_context_data() + + user = context.get("user") + context["uid"] = utils.encode_uid(user.pk) + context["token"] = default_token_generator.make_token(user) + context["url"] = settings.ACTIVATION_URL.format(**context) + return context + + +class ConfirmationEmail(BaseEmailMessage): + template_name = "email/confirmation.html" + + +class PasswordResetEmail(BaseEmailMessage): + template_name = "email/password_reset.html" + + def get_context_data(self): + # PasswordResetEmail can be deleted + context = super().get_context_data() + + user = context.get("user") + context["uid"] = utils.encode_uid(user.pk) + context["token"] = default_token_generator.make_token(user) + context["url"] = settings.PASSWORD_RESET_CONFIRM_URL.format(**context) + return context + + +class PasswordChangedConfirmationEmail(BaseEmailMessage): + template_name = "email/password_changed_confirmation.html" + + +class UsernameChangedConfirmationEmail(BaseEmailMessage): + template_name = "email/username_changed_confirmation.html" + + +class UsernameResetEmail(BaseEmailMessage): + template_name = "email/username_reset.html" + + def get_context_data(self): + context = super().get_context_data() + + user = context.get("user") + context["uid"] = utils.encode_uid(user.pk) + context["token"] = default_token_generator.make_token(user) + context["url"] = settings.USERNAME_RESET_CONFIRM_URL.format(**context) + return context diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7a0c328fa15fe17416048206eb38e0ebaaa75a71 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..35a01958bba4a7cc93e49b548f10064608de4d7a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,138 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +# Translators: +# Bertram Bühner <github@sheepyhollow.de>, 2020 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: djoser\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-01-13 17:40+0100\n" +"Last-Translator: Bertram Bühner <github@sheepyhollow.de>\n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: constants.py:4 +msgid "Unable to log in with provided credentials." +msgstr "Eine Anmeldung ist mit den angegebenen Daten nicht möglich." + +#: constants.py:5 +msgid "User account is disabled." +msgstr "Dieses Benutzerkonto ist deaktiviert." + +#: constants.py:6 +msgid "Invalid token for given user." +msgstr "Das Token für diesen Benutzer ist ungültig." + +#: constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "Die User-ID ist ungültig oder dieser Benutzer existiert nicht." + +#: constants.py:8 +msgid "Stale token for given user." +msgstr "Das Token für diesen Benutzer ist abgelaufen." + +#: constants.py:9 +msgid "The two password fields didn't match." +msgstr "Die beiden Passwörter stimmen nicht überein." + +#: constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "Die beiden {0}-Felder stimmen nicht überein." + +#: constants.py:11 +msgid "Invalid password." +msgstr "Das Passwort ist ungültig." + +#: constants.py:12 +msgid "User with given email does not exist." +msgstr "Es existiert kein Benutzer mit dieser E-Mailadresse." + +#: constants.py:13 +msgid "Unable to create account." +msgstr "Das Benutzerkonto kann nicht angelegt werden." + +#: constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more " +"details." +msgstr "" +"Das user-model enthält kein E-Mail-Feld. Weitere Details unter " +"http://djoser.readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME " +"." + +#: templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Aktivierung des Benutzerkontos auf %(site_name)s" + +#: templates/email/activation.html:8 templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "" +"Sie erhalten diese E-Mail, da Sie den Aktivierungsprozess auf %(site_name)s." +"abschließen müssen." + +#: templates/email/activation.html:10 templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "Bitte begeben Sie sich auf folgende Seite, um die Aktivierung abzuschließen:" + +#: templates/email/activation.html:13 templates/email/activation.html:25 +#: templates/email/confirmation.html:10 templates/email/confirmation.html:18 +#: templates/email/password_reset.html:14 +#: templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Vielen Dank für die Nutzung unserer Seite!" + +#: templates/email/activation.html:15 templates/email/activation.html:27 +#: templates/email/confirmation.html:12 templates/email/confirmation.html:20 +#: templates/email/password_reset.html:16 +#: templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "Das Team von %(site_name)s" + +#: templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "" +"%(site_name)s - Ihr Benutzerkonto wurde erfolgreich erstellt und aktiviert!" + +#: templates/email/confirmation.html:8 templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Ihr Benutzerkonto wurde erstellt und ist freigeschaltet!" + +#: templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Zurücksetzen des Passworts auf %(site_name)s" + +#: templates/email/password_reset.html:8 templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Sie erhalten diese E-Mail, da Sie das Zurücksetzen Ihres Passworts auf " +"%(site_name)s angefordert haben." + +#: templates/email/password_reset.html:10 +#: templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Bitte geben Sie auf der folgenden Seite ein neues Passwort ein:" + +#: templates/email/password_reset.html:12 +#: templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Ihr Benutzername - falls Sie ihn vergessen haben - lautet:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..68431907b5900a0c77de27b97e74d602738cf381 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..f966ba52f831f3ad2bca193614f87db319e2c81e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,189 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +# Translators: +# Ariel Torti <arieltorti14@gmail.com>, 2020 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: djoser\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-18 20:06-0300\n" +"Last-Translator: Ariel Torti <arieltorti14@gmail.com>\n" +"Language-Team: Spanish\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: djoser/constants.py:5 +msgid "Unable to log in with provided credentials." +msgstr "No es posible iniciar sesion con las credenciales proveídas." + +#: djoser/constants.py:6 +msgid "User account is disabled." +msgstr "Esta cuenta de usuario esta deshabilitada." + +#: djoser/constants.py:7 +msgid "Invalid token for given user." +msgstr "El token del usuario no es valido." + +#: djoser/constants.py:8 +msgid "Invalid user id or user doesn't exist." +msgstr "Id de usuario invalida o usuario inexistente." + +#: djoser/constants.py:9 +msgid "Stale token for given user." +msgstr "El token del usuario ha expirado." + +#: djoser/constants.py:10 +msgid "The two password fields didn't match." +msgstr "El contenido de los dos campos de contraseña no coincide." + +#: djoser/constants.py:11 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "El contenido de los dos campos de {0} no coincide." + +#: djoser/constants.py:12 +msgid "Invalid password." +msgstr "Contraseña invalida." + +#: djoser/constants.py:13 +msgid "User with given email does not exist." +msgstr "No existe un usuario con el email dado." + +#: djoser/constants.py:14 +msgid "Unable to create account." +msgstr "No es posible crear la cuenta de usuario." + +#: djoser/templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Activacion de la cuenta %(site_name)s" + +#: djoser/templates/email/activation.html:8 +#: djoser/templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "" +"Usted ha recibido este email porque necesita finalizar el proceso de activacion en " +"%(site_name)s." + +#: djoser/templates/email/activation.html:10 +#: djoser/templates/email/activation.html:21 +msgid "Please go to the following page to activate account:" +msgstr "Por favor diríjase a la siguiente página para activar su cuenta:" + +#: djoser/templates/email/activation.html:13 +#: djoser/templates/email/activation.html:24 +#: djoser/templates/email/confirmation.html:10 +#: djoser/templates/email/confirmation.html:18 +#: djoser/templates/email/password_changed_confirmation.html:10 +#: djoser/templates/email/password_changed_confirmation.html:18 +#: djoser/templates/email/password_reset.html:14 +#: djoser/templates/email/password_reset.html:26 +#: djoser/templates/email/username_changed_confirmation.html:10 +#: djoser/templates/email/username_changed_confirmation.html:18 +#: djoser/templates/email/username_reset.html:14 +#: djoser/templates/email/username_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Gracias por usar nuestro sitio!" + +#: djoser/templates/email/activation.html:15 +#: djoser/templates/email/activation.html:26 +#: djoser/templates/email/confirmation.html:12 +#: djoser/templates/email/confirmation.html:20 +#: djoser/templates/email/password_changed_confirmation.html:12 +#: djoser/templates/email/password_changed_confirmation.html:20 +#: djoser/templates/email/password_reset.html:16 +#: djoser/templates/email/password_reset.html:28 +#: djoser/templates/email/username_changed_confirmation.html:12 +#: djoser/templates/email/username_changed_confirmation.html:20 +#: djoser/templates/email/username_reset.html:16 +#: djoser/templates/email/username_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "El equipo de %(site_name)s" + +#: djoser/templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "%(site_name)s - Su cuenta ha sido creada y activada con exito!" + +#: djoser/templates/email/confirmation.html:8 +#: djoser/templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Su cuenta fue creada y esta lista para usarse!" + +#: djoser/templates/email/password_changed_confirmation.html:4 +#, python-format +msgid "%(site_name)s - Your password has been successfully changed!" +msgstr "%(site_name)s - Su contraseña ha sido cambiada con exito!" + +#: djoser/templates/email/password_changed_confirmation.html:8 +#: djoser/templates/email/password_changed_confirmation.html:16 +msgid "Your password has been changed!" +msgstr "Su contraseña ha sido cambiada!" + +#: djoser/templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Reseteo de contraseña en %(site_name)s" + +#: djoser/templates/email/password_reset.html:8 +#: djoser/templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Usted ha recibido este email porque solicito un cambio de contraseña para su " +"cuenta en %(site_name)s" + +#: djoser/templates/email/password_reset.html:10 +#: djoser/templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Por favor diríjase a la siguiente página para seleccionar su nueva contraseña:" + +#: djoser/templates/email/password_reset.html:12 +#: djoser/templates/email/password_reset.html:24 +#: djoser/templates/email/username_reset.html:12 +#: djoser/templates/email/username_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Su usuario, en caso que lo haya olvidado:" + +#: djoser/templates/email/username_changed_confirmation.html:4 +#, python-format +msgid "%(site_name)s - Your username has been successfully changed!" +msgstr "%(site_name)s - Su usuario ha sido cambiado con exito!" + +#: djoser/templates/email/username_changed_confirmation.html:8 +#: djoser/templates/email/username_changed_confirmation.html:16 +msgid "Your username has been changed!" +msgstr "Su usuario ha sido cambiado!" + +#: djoser/templates/email/username_reset.html:4 +#, python-format +msgid "Username reset on %(site_name)s" +msgstr "Reseteo de usuario en %(site_name)s" + +#: djoser/templates/email/username_reset.html:8 +#: djoser/templates/email/username_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a username reset for your " +"user account at %(site_name)s." +msgstr "" +"Usted ha recibido este email porque solicito un cambio de usuario para su " +"cuenta en %(site_name)s" + +#: djoser/templates/email/username_reset.html:10 +#: djoser/templates/email/username_reset.html:22 +msgid "Please go to the following page and choose a new username:" +msgstr "Por favor diríjase a la siguiente página para seleccionar su nuevo usuario:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c586c80a65fadcb314356125984abb615e1f03df Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..7e6c4eb4ac795ed3771546a1822f6931791e4a0c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,139 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +# Translators: +# Julie Rymer <chadys@hotmail.fr>, 2019 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: djoser\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-14 18:40+0200\n" +"PO-Revision-Date: 2019-05-14 19:03+0200\n" +"Last-Translator: Julie Rymer <chadys@hotmail.fr>\n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: constants.py:4 +msgid "Unable to log in with provided credentials." +msgstr "Impossible de se connecter avec les identifiants fournis." + +#: constants.py:5 +msgid "User account is disabled." +msgstr "Ce compte utilisateur est désactivé." + +#: constants.py:6 +msgid "Invalid token for given user." +msgstr "Le jeton d'authentification est invalide pour cet utilisateur." + +#: constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "L'id de l'utilisateur est invalide ou cet utilisateur n'existe pas." + +#: constants.py:8 +msgid "Stale token for given user." +msgstr "Le jeton pour cet utilisateur est expiré." + +#: constants.py:9 +msgid "The two password fields didn't match." +msgstr "Le contenu des deux champs mot de passe est différent." + +#: constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "Le contenu des deux champs {0} est différent." + +#: constants.py:11 +msgid "Invalid password." +msgstr "Mot de passe invalide." + +#: constants.py:12 +msgid "User with given email does not exist." +msgstr "Cette adresse email ne correspond à aucun utilisateur enregistré." + +#: constants.py:13 +msgid "Unable to create account." +msgstr "Création de compte impossible." + +#: constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more " +"details." +msgstr "" +"Le modèle User ne contient pas le champ email indiqué. Veuillez consulter " +"http://djoser.readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME " +"pour plus de détails." + +#: templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Activation du compte sur %(site_name)s" + +#: templates/email/activation.html:8 templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "" +"Vous recevez cet email car vous devez finir le processus d'activation de votre " +"compte sur %(site_name)s." + +#: templates/email/activation.html:10 templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "Veuillez cliquer sur le lien suivant pour activer votre compte :" + +#: templates/email/activation.html:13 templates/email/activation.html:25 +#: templates/email/confirmation.html:10 templates/email/confirmation.html:18 +#: templates/email/password_reset.html:14 +#: templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Merci d'avoir utilisé notre site !" + +#: templates/email/activation.html:15 templates/email/activation.html:27 +#: templates/email/confirmation.html:12 templates/email/confirmation.html:20 +#: templates/email/password_reset.html:16 +#: templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "L'équipe %(site_name)s" + +#: templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "" +"%(site_name)s - Votre compte a été créé et activé avec succès !" + +#: templates/email/confirmation.html:8 templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Votre compte a été créé et est prêt a être utilisé !" + +#: templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Réinitialisation du mot de passe sur %(site_name)s" + +#: templates/email/password_reset.html:8 templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Vous recevez cet email car vous avez demandé la réinitialisation du mot de " +"passe de votre compte sur %(site_name)s." + +#: templates/email/password_reset.html:10 +#: templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Merci de cliquer sur le lien suivant pour choisir un nouveau mot de passe :" + +#: templates/email/password_reset.html:12 +#: templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Votre nom d'utilisateur, au cas où vous l'auriez oublié, est le suivant :" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..bec6746161613dc7a8ed7333defabf941f828deb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..a0e20581fb0a91e16ab33152392fcaef7b7eba22 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ka/LC_MESSAGES/django.po @@ -0,0 +1,129 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +msgid "" +msgstr "" +"Project-Id-Version: 1.4.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-25 09:44+0100\n" +"PO-Revision-Date: 2019-01-29 14:25+0100\n" +"Last-Translator: Szymon Pyżalski <s.pyzalski@sunscrapers.com>\n" +"Language-Team: http://sunscrapers.com\n" +"Language: ka_GE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: constants.py:4 +msgid "Unable to login with provided credentials." +msgstr "შესვლა ამ სახელით და პაროლით არ არის შესაძლებელი." + +#: constants.py:5 +msgid "User account is disabled." +msgstr "ანგარიში გამორთულია." + +#: constants.py:6 +msgid "Invalid token for given user." +msgstr "ნიშანი ტოკენი ამ მომხმარებელისთვის" + +#: constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "სახელი არასწორია ან მომხმარებელი არ არსებობს." + +#: constants.py:8 +msgid "Stale token for given user." +msgstr "ნიშანი მოძველებულია." + +#: constants.py:9 +msgid "The two password fields didn't match." +msgstr "პაროლის ორი ველი ერთმანეთს არ ემთხვევა." + +#: constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "ორი {0} ერთმანეთს არ ემთხვევა." + +#: constants.py:11 +msgid "Invalid password." +msgstr "არასწორი პაროლი." + +#: constants.py:12 +msgid "User with given email does not exist." +msgstr "მომხმარებელი ამ იმეილით არ არსებობს." + +#: constants.py:13 +msgid "Unable to create account." +msgstr "ანგარიშის შექმნა შეუძლებულია." + +#: constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more " +"details." +msgstr "მომხმარებელის მოდელი არ შეიცავს მითითებულ იმეილის ველს. ნახე " +"http://djoser.readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME " +"მეტი დეტალებისთვის" + +#: templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "ანგარიშის აკტივაცია საიტზე %(site_name)s" + +#: templates/email/activation.html:8 templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "თქვენ იღებთ ამ იმეილს, რადგან საჭიროა დაამთავროთ აკტივაციი პროცესი საიტზე %(site_name)s." + +#: templates/email/activation.html:10 templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "მიჰყევით ამ ლინკს რათა გაააკტიუროთ ანგარიში:" + +#: templates/email/activation.html:13 templates/email/activation.html:25 +#: templates/email/confirmation.html:10 templates/email/confirmation.html:18 +#: templates/email/password_reset.html:14 +#: templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "მადლობა საითის გამოიყენებას" + +#: templates/email/activation.html:15 templates/email/activation.html:27 +#: templates/email/confirmation.html:12 templates/email/confirmation.html:20 +#: templates/email/password_reset.html:16 +#: templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "საიტის %(site_name)s გუნდი" + +#: templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "%(site_name)s - თქვენი ანგარიში წარმატებით შეიქმნილია და გააკტიურებულია." + +#: templates/email/confirmation.html:8 templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "თქვენი ანგარიში შეიქმნილია და მზად არის გამოყენებისთვის!" + +#: templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "პაროლის აღდგენა საიტზე %(site_name)s." + +#: templates/email/password_reset.html:8 templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "ამ ემაილს იღებთ, რანდან თქვნენ მოთხოვეთ პაროლის აღდგენა თქვენი ანგარიშისთვის " +"%(site_name)s საიტზე." + +#: templates/email/password_reset.html:10 +#: templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "მოჰყევით ამ ლინკს და მიუთითეთ ახალი პაროლი:" + +#: templates/email/password_reset.html:12 +#: templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "თქვენი მომხმარებლის სახელი, იმ შემთხვევისათვის თუ დაგავიწყდათ:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..56e82c7dcbb2a032b8ff8251c2d8fcc8813a89d3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..909a4ccf3c8d601fc50840fd1a471dafd0c3f2b5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,139 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +msgid "" +msgstr "" +"Project-Id-Version: 1.4.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-28 15:21+0100\n" +"PO-Revision-Date: 2019-01-29 14:25+0100\n" +"Last-Translator: Szymon Pyżalski <s.pyzalski@sunscrapers.com>\n" +"Language-Team: http://sunscrapers.com\n" +"Language: pl_PL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" +"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" +"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +#: djoser/constants.py:4 +msgid "Unable to login with provided credentials." +msgstr "Nie udało się zalogować przy pomocy tych danych." + +#: djoser/constants.py:5 +msgid "User account is disabled." +msgstr "Konto wyłączone." + +#: djoser/constants.py:6 +msgid "Invalid token for given user." +msgstr "Błędny token dla tego użytkownika." + +#: djoser/constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "Błędna nazwa użytkownika, lub użytkownik nie istnieje." + +#: djoser/constants.py:8 +msgid "Stale token for given user." +msgstr "Przestarzały token dla tego użytkownika." + +#: djoser/constants.py:9 +msgid "The two password fields didn't match." +msgstr "Pola hasła nie pasują." + +#: djoser/constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "Pola {0} nie pasują." + +#: djoser/constants.py:11 +msgid "Invalid password." +msgstr "Błedne hasło." + +#: djoser/constants.py:12 +msgid "User with given email does not exist." +msgstr "Użytkownik z tym adresem email nie istnieje." + +#: djoser/constants.py:13 +msgid "Unable to create account." +msgstr "Nie udało się stworzyć konta." + +#: djoser/constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more " +"details." +msgstr "Model użytkownika nie zawiera wskazanego pola email. Zobacz " +"http://djoser.readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME " +"by zobaczyć więcej szczegółów" + +#: djoser/templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Aktywacja konta na stronie %(site_name)s" + +#: templates/email/activation.html:8 templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "Otrzymałeś tego emaila, ponieważ potrzeujesz dokończyć proces aktywacji na " +"stronie %(site_name)s." + +#: djoser/templates/email/activation.html:10 +#: djoser/templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "Proszę przejdź na poniższą stronę, by aktywować konto:" + +#: djoser/templates/email/activation.html:13 +#: djoser/templates/email/activation.html:25 +#: djoser/templates/email/confirmation.html:10 +#: djoser/templates/email/confirmation.html:18 +#: djoser/templates/email/password_reset.html:14 +#: djoser/templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Dziękujemy za korzystanie z naszej strony!" + +#: djoser/templates/email/activation.html:15 +#: djoser/templates/email/activation.html:27 +#: djoser/templates/email/confirmation.html:12 +#: djoser/templates/email/confirmation.html:20 +#: djoser/templates/email/password_reset.html:16 +#: djoser/templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "Zespół strony %(site_name)s" + +#: djoser/templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "%(site_name)s - Twoje konto zostało stworzone i aktywowane" + +#: djoser/templates/email/confirmation.html:8 +#: djoser/templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Twoje konto zostało utworzone i jest gotowe do użycia" + +#: djoser/templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Reset hasła na stronie %(site_name)s" + +#: djoser/templates/email/password_reset.html:8 +#: djoser/templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "Otrzymałeś tego emaila, ponieważ prosiłeś o reset hasła do Twojego " +"konta na stronie %(site_name)s." + +#: djoser/templates/email/password_reset.html:10 +#: djoser/templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Przejdź do poniższej strony i wybierz nowe hasło:" + +#: djoser/templates/email/password_reset.html:12 +#: djoser/templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Twoja nazwa użytkownika:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d8136f0d10808a10051f336702c77c841086dc2b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..80d62eb6e3c952fb47a808d0d9d0366dadcae7dd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,140 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +msgid "" +msgstr "" +"Project-Id-Version: djoser commit 298825d on master\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-03-18 21:45-0300\n" +"Last-Translator: Matheus Gomes <gomes0502@gmail.com>\n" +"Language-Team: Brasileiro\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: djoser/constants.py:4 +msgid "Unable to login with provided credentials." +msgstr "Não foi possível fazer login com os dados inseridos." + +#: djoser/constants.py:5 +msgid "User account is disabled." +msgstr "A conta do usuário está desativada." + +#: djoser/constants.py:6 +msgid "Invalid token for given user." +msgstr "Token inválido para o usuário fornecido." + +#: djoser/constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "ID de usuário inválido ou inexistente." + +#: djoser/constants.py:8 +msgid "Stale token for given user." +msgstr "Token expirado para o usuário fornecido." + +#: djoser/constants.py:9 +msgid "The two password fields didn't match." +msgstr "Os campos de senha não estão iguais." + +#: djoser/constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "Os dois campos {0} não estão iguais." + +#: djoser/constants.py:11 +msgid "Invalid password." +msgstr "Senha inválida." + +#: djoser/constants.py:12 +msgid "User with given email does not exist." +msgstr "Não existe um usuário com o email fornecido." + +#: djoser/constants.py:13 +msgid "Unable to create account." +msgstr "Não foi possível criar a conta." + +#: djoser/constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more " +"details." +msgstr "" +"O usuário fornecido não possui campo de email definido. Por favor, confira " +"http://djoser.readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME " +"para mais detalhes." + +#: djoser/templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Ativação de conta em %(site_name)s" + +#: templates/email/activation.html:8 templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "" +"Você está recebendo este email porque você precisa terminar o processo em " +"%(site_name)s." + +#: djoser/templates/email/activation.html:10 +#: djoser/templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "Por favor, visite a seguinte página para ativar sua conta:" + +#: djoser/templates/email/activation.html:13 +#: djoser/templates/email/activation.html:25 +#: djoser/templates/email/confirmation.html:10 +#: djoser/templates/email/confirmation.html:18 +#: djoser/templates/email/password_reset.html:14 +#: djoser/templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Obrigado por usar nosso site!" + +#: djoser/templates/email/activation.html:15 +#: djoser/templates/email/activation.html:27 +#: djoser/templates/email/confirmation.html:12 +#: djoser/templates/email/confirmation.html:20 +#: djoser/templates/email/password_reset.html:16 +#: djoser/templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "Time %(site_name)s" + +#: djoser/templates/email/confirmation.html:4 +#, python-format +msgid "" +"%(site_name)s - Your account has been successfully created and activated!" +msgstr "%(site_name)s - Sua conta foi criada e ativada com sucesso!" + +#: djoser/templates/email/confirmation.html:8 +#: djoser/templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Sua conta foi criada com sucesso e está pronta para uso!" + +#: djoser/templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Redefina sua senha em %(site_name)s" + +#: djoser/templates/email/password_reset.html:8 +#: djoser/templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Você está recebendo este email porque você solicitou a redefinição de senha " +"para sua conta em %(site_name)s." + +#: djoser/templates/email/password_reset.html:10 +#: djoser/templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Por favor, visite a seguinte página para definir uma senha nova:" + +#: djoser/templates/email/password_reset.html:12 +#: djoser/templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Caso tenha esquecido, seu usuário:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..95fbe198782231a28d554d34f5c70bd7ef627838 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..8c9b4bedbb94bd20fbeba207522c15b5c893906f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/locale/ru_RU/LC_MESSAGES/django.po @@ -0,0 +1,141 @@ +# Copyright (C) Sunscrapers +# This file is distributed under the same license as the djoser package. +# +msgid "" +msgstr "" +"Project-Id-Version: 1.4.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-28 15:21+0100\n" +"PO-Revision-Date: 2019-05-14 12:05+0300\n" +"Last-Translator: Sergey Ozeranskiy <sozeranskiy@dreamclass.ru>\n" +"Language-Team: \n" +"Language: ru_RU\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n" +"%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 2.2.1\n" +"X-Poedit-Basepath: ../../../..\n" +"X-Poedit-SearchPath-0: .\n" + +#: djoser/constants.py:4 +msgid "Unable to login with provided credentials." +msgstr "Невозможно войти с предоставленными учетными данными." + +#: djoser/constants.py:5 +msgid "User account is disabled." +msgstr "Учетная запись пользователя не активна." + +#: djoser/constants.py:6 +msgid "Invalid token for given user." +msgstr "Неверный токен для данного пользователя." + +#: djoser/constants.py:7 +msgid "Invalid user id or user doesn't exist." +msgstr "Неверный идентификатор пользователя или пользователь не существует." + +#: djoser/constants.py:8 +msgid "Stale token for given user." +msgstr "Устаревший токен для данного пользователя." + +#: djoser/constants.py:9 +msgid "The two password fields didn't match." +msgstr "Два пароля не совпадают." + +#: djoser/constants.py:10 +#, python-brace-format +msgid "The two {0} fields didn't match." +msgstr "Два значения поля {0} не совпадают." + +#: djoser/constants.py:11 +msgid "Invalid password." +msgstr "Неправильный пароль." + +#: djoser/constants.py:12 +msgid "User with given email does not exist." +msgstr "Пользователь с данным адресом электронной почты не существует." + +#: djoser/constants.py:13 +msgid "Unable to create account." +msgstr "Невозможно создать учетную запись." + +#: djoser/constants.py:15 +msgid "" +"User model does not contain specified email field. Please see http://djoser." +"readthedocs.io/en/latest/settings.html#USER_EMAIL_FIELD_NAME for more details." +msgstr "" +"Модель пользователя не содержит указанное поле для электронной почты. Пожалуйста, " +"посмотрите http://djoser.readthedocs.io/en/latest/settings." +"html#USER_EMAIL_FIELD_NAME для получения дополнительной информации." + +#: djoser/templates/email/activation.html:4 +#, python-format +msgid "Account activation on %(site_name)s" +msgstr "Активация аккаунта на %(site_name)s" + +#: djoser/templates/email/activation.html:8 djoser/templates/email/activation.html:19 +#, python-format +msgid "" +"You're receiving this email because you need to finish activation process on " +"%(site_name)s." +msgstr "" +"Вы получили это письмо, потому что вам нужно завершить процесс активации учетной " +"записи на %(site_name)s." + +#: djoser/templates/email/activation.html:10 djoser/templates/email/activation.html:22 +msgid "Please go to the following page to activate account:" +msgstr "" +"Пожалуйста, перейдите на следующую страницу, чтобы активировать учетную запись:" + +#: djoser/templates/email/activation.html:13 djoser/templates/email/activation.html:25 +#: djoser/templates/email/confirmation.html:10 +#: djoser/templates/email/confirmation.html:18 +#: djoser/templates/email/password_reset.html:14 +#: djoser/templates/email/password_reset.html:26 +msgid "Thanks for using our site!" +msgstr "Спасибо за использование нашего сайта!" + +#: djoser/templates/email/activation.html:15 djoser/templates/email/activation.html:27 +#: djoser/templates/email/confirmation.html:12 +#: djoser/templates/email/confirmation.html:20 +#: djoser/templates/email/password_reset.html:16 +#: djoser/templates/email/password_reset.html:28 +#, python-format +msgid "The %(site_name)s team" +msgstr "Команда %(site_name)s" + +#: djoser/templates/email/confirmation.html:4 +#, python-format +msgid "%(site_name)s - Your account has been successfully created and activated!" +msgstr "%(site_name)s - Ваша учетная запись была успешно создана и активирована!" + +#: djoser/templates/email/confirmation.html:8 +#: djoser/templates/email/confirmation.html:16 +msgid "Your account has been created and is ready to use!" +msgstr "Ваша учетная запись была создана и готова к использованию!" + +#: djoser/templates/email/password_reset.html:4 +#, python-format +msgid "Password reset on %(site_name)s" +msgstr "Сброс пароля на %(site_name)s" + +#: djoser/templates/email/password_reset.html:8 +#: djoser/templates/email/password_reset.html:20 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your user " +"account at %(site_name)s." +msgstr "" +"Вы получили это письмо, потому что вы или кто-то другой запросили сброс пароля для " +"учетной записи пользователя на %(site_name)s." + +#: djoser/templates/email/password_reset.html:10 +#: djoser/templates/email/password_reset.html:22 +msgid "Please go to the following page and choose a new password:" +msgstr "Пожалуйста, перейдите на следующую страницу и создайте новый пароль:" + +#: djoser/templates/email/password_reset.html:12 +#: djoser/templates/email/password_reset.html:24 +msgid "Your username, in case you've forgotten:" +msgstr "Ваше имя пользователя, если вы забыли:" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/permissions.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..a7ac04431e2bb8ef0e73ec747debbec688f10634 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/permissions.py @@ -0,0 +1,16 @@ +from rest_framework import permissions +from rest_framework.permissions import SAFE_METHODS + + +class CurrentUserOrAdmin(permissions.IsAuthenticated): + def has_object_permission(self, request, view, obj): + user = request.user + return user.is_staff or obj.pk == user.pk + + +class CurrentUserOrAdminOrReadOnly(permissions.IsAuthenticated): + def has_object_permission(self, request, view, obj): + user = request.user + if type(obj) == type(user) and obj == user: + return True + return request.method in SAFE_METHODS or user.is_staff diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/serializers.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..9385bed76d9a6cd15abb8db8242f21d7c779b3df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/serializers.py @@ -0,0 +1,339 @@ +from django.contrib.auth import authenticate, get_user_model +from django.contrib.auth.password_validation import validate_password +from django.core import exceptions as django_exceptions +from django.db import IntegrityError, transaction +from rest_framework import exceptions, serializers +from rest_framework.exceptions import ValidationError + +from djoser import utils +from djoser.compat import get_user_email, get_user_email_field_name +from djoser.conf import settings + +User = get_user_model() + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = tuple(User.REQUIRED_FIELDS) + ( + settings.USER_ID_FIELD, + settings.LOGIN_FIELD, + ) + read_only_fields = (settings.LOGIN_FIELD,) + + def update(self, instance, validated_data): + email_field = get_user_email_field_name(User) + if settings.SEND_ACTIVATION_EMAIL and email_field in validated_data: + instance_email = get_user_email(instance) + if instance_email != validated_data[email_field]: + instance.is_active = False + instance.save(update_fields=["is_active"]) + return super().update(instance, validated_data) + + +class UserCreateSerializer(serializers.ModelSerializer): + password = serializers.CharField(style={"input_type": "password"}, write_only=True) + + default_error_messages = { + "cannot_create_user": settings.CONSTANTS.messages.CANNOT_CREATE_USER_ERROR + } + + class Meta: + model = User + fields = tuple(User.REQUIRED_FIELDS) + ( + settings.LOGIN_FIELD, + settings.USER_ID_FIELD, + "password", + ) + + def validate(self, attrs): + user = User(**attrs) + password = attrs.get("password") + + try: + validate_password(password, user) + except django_exceptions.ValidationError as e: + serializer_error = serializers.as_serializer_error(e) + raise serializers.ValidationError( + {"password": serializer_error["non_field_errors"]} + ) + + return attrs + + def create(self, validated_data): + try: + user = self.perform_create(validated_data) + except IntegrityError: + self.fail("cannot_create_user") + + return user + + def perform_create(self, validated_data): + with transaction.atomic(): + user = User.objects.create_user(**validated_data) + if settings.SEND_ACTIVATION_EMAIL: + user.is_active = False + user.save(update_fields=["is_active"]) + return user + + +class UserCreatePasswordRetypeSerializer(UserCreateSerializer): + default_error_messages = { + "password_mismatch": settings.CONSTANTS.messages.PASSWORD_MISMATCH_ERROR + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["re_password"] = serializers.CharField( + style={"input_type": "password"} + ) + + def validate(self, attrs): + self.fields.pop("re_password", None) + re_password = attrs.pop("re_password") + attrs = super().validate(attrs) + if attrs["password"] == re_password: + return attrs + else: + self.fail("password_mismatch") + + +class TokenCreateSerializer(serializers.Serializer): + password = serializers.CharField(required=False, style={"input_type": "password"}) + + default_error_messages = { + "invalid_credentials": settings.CONSTANTS.messages.INVALID_CREDENTIALS_ERROR, + "inactive_account": settings.CONSTANTS.messages.INACTIVE_ACCOUNT_ERROR, + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = None + self.fields[settings.LOGIN_FIELD] = serializers.CharField(required=False) + + def validate(self, attrs): + password = attrs.get("password") + params = {settings.LOGIN_FIELD: attrs.get(settings.LOGIN_FIELD)} + self.user = authenticate( + request=self.context.get("request"), **params, password=password + ) + if not self.user: + self.user = User.objects.filter(**params).first() + if self.user and not self.user.check_password(password): + self.fail("invalid_credentials") + if self.user and self.user.is_active: + return attrs + self.fail("invalid_credentials") + + +class UserFunctionsMixin: + def get_user(self, is_active=True): + try: + user = User._default_manager.get( + is_active=is_active, + **{self.email_field: self.data.get(self.email_field, "")}, + ) + if user.has_usable_password(): + return user + except User.DoesNotExist: + pass + if ( + settings.PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND + or settings.USERNAME_RESET_SHOW_EMAIL_NOT_FOUND + ): + self.fail("email_not_found") + + +class SendEmailResetSerializer(serializers.Serializer, UserFunctionsMixin): + default_error_messages = { + "email_not_found": settings.CONSTANTS.messages.EMAIL_NOT_FOUND + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.email_field = get_user_email_field_name(User) + self.fields[self.email_field] = serializers.EmailField() + + +class UidAndTokenSerializer(serializers.Serializer): + uid = serializers.CharField() + token = serializers.CharField() + + default_error_messages = { + "invalid_token": settings.CONSTANTS.messages.INVALID_TOKEN_ERROR, + "invalid_uid": settings.CONSTANTS.messages.INVALID_UID_ERROR, + } + + def validate(self, attrs): + validated_data = super().validate(attrs) + + # uid validation have to be here, because validate_<field_name> + # doesn't work with modelserializer + try: + uid = utils.decode_uid(self.initial_data.get("uid", "")) + self.user = User.objects.get(pk=uid) + except (User.DoesNotExist, ValueError, TypeError, OverflowError): + key_error = "invalid_uid" + raise ValidationError( + {"uid": [self.error_messages[key_error]]}, code=key_error + ) + + is_token_valid = self.context["view"].token_generator.check_token( + self.user, self.initial_data.get("token", "") + ) + if is_token_valid: + return validated_data + else: + key_error = "invalid_token" + raise ValidationError( + {"token": [self.error_messages[key_error]]}, code=key_error + ) + + +class ActivationSerializer(UidAndTokenSerializer): + default_error_messages = { + "stale_token": settings.CONSTANTS.messages.STALE_TOKEN_ERROR + } + + def validate(self, attrs): + attrs = super().validate(attrs) + if not self.user.is_active: + return attrs + raise exceptions.PermissionDenied(self.error_messages["stale_token"]) + + +class PasswordSerializer(serializers.Serializer): + new_password = serializers.CharField(style={"input_type": "password"}) + + def validate(self, attrs): + user = self.context["request"].user or self.user + # why assert? There are ValidationError / fail everywhere + assert user is not None + + try: + validate_password(attrs["new_password"], user) + except django_exceptions.ValidationError as e: + raise serializers.ValidationError({"new_password": list(e.messages)}) + return super().validate(attrs) + + +class PasswordRetypeSerializer(PasswordSerializer): + re_new_password = serializers.CharField(style={"input_type": "password"}) + + default_error_messages = { + "password_mismatch": settings.CONSTANTS.messages.PASSWORD_MISMATCH_ERROR + } + + def validate(self, attrs): + attrs = super().validate(attrs) + if attrs["new_password"] == attrs["re_new_password"]: + return attrs + else: + self.fail("password_mismatch") + + +class CurrentPasswordSerializer(serializers.Serializer): + current_password = serializers.CharField(style={"input_type": "password"}) + + default_error_messages = { + "invalid_password": settings.CONSTANTS.messages.INVALID_PASSWORD_ERROR + } + + def validate_current_password(self, value): + is_password_valid = self.context["request"].user.check_password(value) + if is_password_valid: + return value + else: + self.fail("invalid_password") + + +class UsernameSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = (settings.LOGIN_FIELD,) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.username_field = settings.LOGIN_FIELD + self._default_username_field = User.USERNAME_FIELD + self.fields["new_{}".format(self.username_field)] = self.fields.pop( + self.username_field + ) + + def save(self, **kwargs): + if self.username_field != self._default_username_field: + kwargs[User.USERNAME_FIELD] = self.validated_data.get( + "new_{}".format(self.username_field) + ) + return super().save(**kwargs) + + +class UsernameRetypeSerializer(UsernameSerializer): + default_error_messages = { + "username_mismatch": settings.CONSTANTS.messages.USERNAME_MISMATCH_ERROR.format( + settings.LOGIN_FIELD + ) + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["re_new_" + settings.LOGIN_FIELD] = serializers.CharField() + + def validate(self, attrs): + attrs = super().validate(attrs) + new_username = attrs[settings.LOGIN_FIELD] + if new_username != attrs["re_new_{}".format(settings.LOGIN_FIELD)]: + self.fail("username_mismatch") + else: + return attrs + + +class TokenSerializer(serializers.ModelSerializer): + auth_token = serializers.CharField(source="key") + + class Meta: + model = settings.TOKEN_MODEL + fields = ("auth_token",) + + +class SetPasswordSerializer(PasswordSerializer, CurrentPasswordSerializer): + pass + + +class SetPasswordRetypeSerializer(PasswordRetypeSerializer, CurrentPasswordSerializer): + pass + + +class PasswordResetConfirmSerializer(UidAndTokenSerializer, PasswordSerializer): + pass + + +class PasswordResetConfirmRetypeSerializer( + UidAndTokenSerializer, PasswordRetypeSerializer +): + pass + + +class UsernameResetConfirmSerializer(UidAndTokenSerializer, UsernameSerializer): + pass + + +class UsernameResetConfirmRetypeSerializer( + UidAndTokenSerializer, UsernameRetypeSerializer +): + pass + + +class UserDeleteSerializer(CurrentPasswordSerializer): + pass + + +class SetUsernameSerializer(UsernameSerializer, CurrentPasswordSerializer): + class Meta: + model = User + fields = (settings.LOGIN_FIELD, "current_password") + + +class SetUsernameRetypeSerializer(SetUsernameSerializer, UsernameRetypeSerializer): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/signals.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/signals.py new file mode 100644 index 0000000000000000000000000000000000000000..556ce44a51ef86d101b7e1acba926d1623a8363a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/signals.py @@ -0,0 +1,7 @@ +from django.dispatch import Signal + +# New user has registered. Args: user, request. +user_registered = Signal() + +# User has activated his or her account. Args: user, request. +user_activated = Signal() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..986d57ae0f015547b74bc0fc2ca4815d85467e63 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/serializers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0ad9b82144011de10881712288978470157eea7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/serializers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/urls.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6fb7c78a186c2d568e93e1c083c7e8dc01b83f7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/urls.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40499ff49a2a84b2b0e11b686f9538b797ef5067 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e760b3528b6d727483cb24ff1ded359e597edb75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/facebook.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/facebook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e2091f1686d2df79355ace6201dd49d714b253b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/__pycache__/facebook.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/facebook.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/facebook.py new file mode 100644 index 0000000000000000000000000000000000000000..e00b205ac429222ab112fca9dcdb2568cda69ca9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/backends/facebook.py @@ -0,0 +1,5 @@ +from social_core.backends.facebook import FacebookOAuth2 + + +class FacebookOAuth2Override(FacebookOAuth2): + REDIRECT_STATE = False diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/serializers.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..d0f3513bed8ae7ddb945e36fad46821a26a68395 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/serializers.py @@ -0,0 +1,56 @@ +from rest_framework import serializers +from social_core import exceptions +from social_django.utils import load_backend, load_strategy + +from djoser.conf import settings + + +class ProviderAuthSerializer(serializers.Serializer): + # GET auth token + access = serializers.CharField(read_only=True) + refresh = serializers.CharField(read_only=True) + user = serializers.CharField(read_only=True) + + def create(self, validated_data): + user = validated_data["user"] + return settings.SOCIAL_AUTH_TOKEN_STRATEGY.obtain(user) + + def validate(self, attrs): + request = self.context["request"] + if "state" in request.GET: + self._validate_state(request.GET["state"]) + + strategy = load_strategy(request) + redirect_uri = strategy.session_get("redirect_uri") + + backend_name = self.context["view"].kwargs["provider"] + backend = load_backend(strategy, backend_name, redirect_uri=redirect_uri) + + try: + user = backend.auth_complete() + except exceptions.AuthException as e: + raise serializers.ValidationError(str(e)) + return {"user": user} + + def _validate_state(self, value): + request = self.context["request"] + strategy = load_strategy(request) + redirect_uri = strategy.session_get("redirect_uri") + + backend_name = self.context["view"].kwargs["provider"] + backend = load_backend(strategy, backend_name, redirect_uri=redirect_uri) + + try: + backend.validate_state() + except exceptions.AuthMissingParameter: + raise serializers.ValidationError( + "State could not be found in request data." + ) + except exceptions.AuthStateMissing: + raise serializers.ValidationError( + "State could not be found in server-side session data." + ) + except exceptions.AuthStateForbidden: + raise serializers.ValidationError("Invalid state has been provided.") + + return value diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4db93ba2484bf33a1e24ad05895d4abe3772635 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/jwt.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/jwt.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d72261132e2558e3d4978d4df5d6193e93c33d0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/__pycache__/jwt.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/jwt.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/jwt.py new file mode 100644 index 0000000000000000000000000000000000000000..cc55c8f8e34c39f2cc1ba0b88af5b06b37b8b5b7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/token/jwt.py @@ -0,0 +1,12 @@ +class TokenStrategy: + @classmethod + def obtain(cls, user): + from rest_framework_simplejwt.tokens import RefreshToken + from six import text_type + + refresh = RefreshToken.for_user(user) + return { + "access": text_type(refresh.access_token), + "refresh": text_type(refresh), + "user": user, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/urls.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..2a3e7929e1aa18248d0e94b031ae204e7f05e79a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/urls.py @@ -0,0 +1,11 @@ +from django.urls import re_path + +from djoser.social import views + +urlpatterns = [ + re_path( + r"^o/(?P<provider>\S+)/$", + views.ProviderAuthView.as_view(), + name="provider-auth", + ) +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/views.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/views.py new file mode 100644 index 0000000000000000000000000000000000000000..5605eb716b2795f27e05acc82e13f2f4de437c8e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/social/views.py @@ -0,0 +1,24 @@ +from rest_framework import generics, permissions, status +from rest_framework.response import Response +from social_django.utils import load_backend, load_strategy + +from djoser.conf import settings +from djoser.social.serializers import ProviderAuthSerializer + + +class ProviderAuthView(generics.CreateAPIView): + permission_classes = [permissions.AllowAny] + serializer_class = ProviderAuthSerializer + + def get(self, request, *args, **kwargs): + redirect_uri = request.GET.get("redirect_uri") + if redirect_uri not in settings.SOCIAL_AUTH_ALLOWED_REDIRECT_URIS: + return Response(status=status.HTTP_400_BAD_REQUEST) + strategy = load_strategy(request) + strategy.session_set("redirect_uri", redirect_uri) + + backend_name = self.kwargs["provider"] + backend = load_backend(strategy, backend_name, redirect_uri=redirect_uri) + + authorization_url = backend.auth_url() + return Response(data={"authorization_url": authorization_url}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/activation.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/activation.html new file mode 100644 index 0000000000000000000000000000000000000000..f36649e8d989a181acc28d7ecbce6bfc791fc3c6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/activation.html @@ -0,0 +1,28 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}Account activation on {{ site_name }}{% endblocktrans %} +{% endblock subject %} + +{% block text_body %} +{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page to activate account:" %} +{{ protocol }}://{{ domain }}/{{ url|safe }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}</p> + +<p>{% trans "Please go to the following page to activate account:" %}</p> +<p><a href="{{ protocol }}://{{ domain }}/{{ url|safe }}">{{ protocol }}://{{ domain }}/{{ url|safe }}</a></p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> + +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/confirmation.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/confirmation.html new file mode 100644 index 0000000000000000000000000000000000000000..1d26efcaf169ba283e412378d07b20c7a5a2601d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/confirmation.html @@ -0,0 +1,21 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}{{ site_name }} - Your account has been successfully created and activated!{% endblocktrans %} +{% endblock %} + +{% block text_body %} +{% trans "Your account has been created and is ready to use!" %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% trans "Your account has been created and is ready to use!" %}</p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_changed_confirmation.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_changed_confirmation.html new file mode 100644 index 0000000000000000000000000000000000000000..fdf665859f5194faa398dcac7d747ff48213ef9e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_changed_confirmation.html @@ -0,0 +1,21 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}{{ site_name }} - Your password has been successfully changed!{% endblocktrans %} +{% endblock %} + +{% block text_body %} +{% trans "Your password has been changed!" %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% trans "Your password has been changed!" %}</p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_reset.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_reset.html new file mode 100644 index 0000000000000000000000000000000000000000..88b1fec90221e3e9ae0d89b007e2a078df021e41 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/password_reset.html @@ -0,0 +1,29 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %} +{% endblock subject %} + +{% block text_body %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{{ protocol }}://{{ domain }}/{{ url }} +{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}</p> + +<p>{% trans "Please go to the following page and choose a new password:" %}</p> +<a href="{{ protocol }}://{{ domain }}/{{ url }}">{{ protocol }}://{{ domain }}/{{ url }}</a> +<p>{% trans "Your username, in case you've forgotten:" %} <b>{{ user.get_username }}</b></p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_changed_confirmation.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_changed_confirmation.html new file mode 100644 index 0000000000000000000000000000000000000000..053ac66621e7a9c2a5b0728c5c586da0dbe3ff81 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_changed_confirmation.html @@ -0,0 +1,21 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}{{ site_name }} - Your username has been successfully changed!{% endblocktrans %} +{% endblock %} + +{% block text_body %} +{% trans "Your username has been changed!" %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% trans "Your username has been changed!" %}</p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_reset.html b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_reset.html new file mode 100644 index 0000000000000000000000000000000000000000..6b437ca80c97df79a92119e318197b4d227c1529 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/templates/email/username_reset.html @@ -0,0 +1,29 @@ +{% load i18n %} + +{% block subject %} +{% blocktrans %}Username reset on {{ site_name }}{% endblocktrans %} +{% endblock subject %} + +{% block text_body %} +{% blocktrans %}You're receiving this email because you requested a username reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new username:" %} +{{ protocol }}://{{ domain }}/{{ url }} +{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +{% endblock text_body %} + +{% block html_body %} +<p>{% blocktrans %}You're receiving this email because you requested a username reset for your user account at {{ site_name }}.{% endblocktrans %}</p> + +<p>{% trans "Please go to the following page and choose a new username:" %}</p> +<a href="{{ protocol }}://{{ domain }}/{{ url }}">{{ protocol }}://{{ domain }}/{{ url }}</a> +<p>{% trans "Your username, in case you've forgotten:" %} <b>{{ user.get_username }}</b></p> + +<p>{% trans "Thanks for using our site!" %}</p> + +<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p> +{% endblock html_body %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d2ad6b9dd481a004839d461277e5882faa5fdcd0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__init__.py @@ -0,0 +1,3 @@ +from .base import urlpatterns + +__all__ = ["urlpatterns"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ef98ce527749b75cbd2aaf392801ab844bbc9c8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/authtoken.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/authtoken.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa223c7ab044bbe2e4e5fef8bbe24617e9fbb811 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/authtoken.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0225067b94f2fb11fdceb7aa839bcfa66d3fda1d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/jwt.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/jwt.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a75438679b58083fe3ac936c73ae83208889a650 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/__pycache__/jwt.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/authtoken.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/authtoken.py new file mode 100644 index 0000000000000000000000000000000000000000..ccfc1d82e1b4f550f84d91fdead1876ce17ff4f4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/authtoken.py @@ -0,0 +1,8 @@ +from django.urls import re_path + +from djoser import views + +urlpatterns = [ + re_path(r"^token/login/?$", views.TokenCreateView.as_view(), name="login"), + re_path(r"^token/logout/?$", views.TokenDestroyView.as_view(), name="logout"), +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/base.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/base.py new file mode 100644 index 0000000000000000000000000000000000000000..44afa38e9e3871325aaf0d3b28029a42ebdcd760 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/base.py @@ -0,0 +1,11 @@ +from django.contrib.auth import get_user_model +from rest_framework.routers import DefaultRouter + +from djoser import views + +router = DefaultRouter() +router.register("users", views.UserViewSet) + +User = get_user_model() + +urlpatterns = router.urls diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/jwt.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/jwt.py new file mode 100644 index 0000000000000000000000000000000000000000..474411f1dd2260a00e5ee27f03a8af27e2fee865 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/urls/jwt.py @@ -0,0 +1,8 @@ +from django.urls import re_path +from rest_framework_simplejwt import views + +urlpatterns = [ + re_path(r"^jwt/create/?", views.TokenObtainPairView.as_view(), name="jwt-create"), + re_path(r"^jwt/refresh/?", views.TokenRefreshView.as_view(), name="jwt-refresh"), + re_path(r"^jwt/verify/?", views.TokenVerifyView.as_view(), name="jwt-verify"), +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..8de2de101c1388eec9a260ecacb84c9c108a0286 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/utils.py @@ -0,0 +1,38 @@ +from django.contrib.auth import login, logout, user_logged_in, user_logged_out +from django.utils.encoding import force_bytes, force_str +from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode + +from djoser.conf import settings + + +def encode_uid(pk): + return force_str(urlsafe_base64_encode(force_bytes(pk))) + + +def decode_uid(pk): + return force_str(urlsafe_base64_decode(pk)) + + +def login_user(request, user): + token, _ = settings.TOKEN_MODEL.objects.get_or_create(user=user) + if settings.CREATE_SESSION_ON_LOGIN: + login(request, user) + user_logged_in.send(sender=user.__class__, request=request, user=user) + return token + + +def logout_user(request): + if settings.TOKEN_MODEL: + settings.TOKEN_MODEL.objects.filter(user=request.user).delete() + user_logged_out.send( + sender=request.user.__class__, request=request, user=request.user + ) + if settings.CREATE_SESSION_ON_LOGIN: + logout(request) + + +class ActionViewMixin(object): + def post(self, request, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + return self._action(serializer) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/djoser/views.py b/Latest_Group_Project/.venv/Lib/site-packages/djoser/views.py new file mode 100644 index 0000000000000000000000000000000000000000..16d2ae4678e45f1e2d9eea14ebe91bcb4a2821ae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/djoser/views.py @@ -0,0 +1,306 @@ +from django.contrib.auth import get_user_model, update_session_auth_hash +from django.contrib.auth.tokens import default_token_generator +from django.utils.timezone import now +from rest_framework import generics, status, views, viewsets +from rest_framework.decorators import action +from rest_framework.exceptions import NotFound +from rest_framework.response import Response + +from djoser import signals, utils +from djoser.compat import get_user_email +from djoser.conf import settings + +User = get_user_model() + + +class TokenCreateView(utils.ActionViewMixin, generics.GenericAPIView): + """ + Use this endpoint to obtain user authentication token. + """ + + serializer_class = settings.SERIALIZERS.token_create + permission_classes = settings.PERMISSIONS.token_create + + def _action(self, serializer): + token = utils.login_user(self.request, serializer.user) + token_serializer_class = settings.SERIALIZERS.token + return Response( + data=token_serializer_class(token).data, status=status.HTTP_200_OK + ) + + +class TokenDestroyView(views.APIView): + """ + Use this endpoint to logout user (remove user authentication token). + """ + + permission_classes = settings.PERMISSIONS.token_destroy + + def post(self, request): + utils.logout_user(request) + return Response(status=status.HTTP_204_NO_CONTENT) + + +class UserViewSet(viewsets.ModelViewSet): + serializer_class = settings.SERIALIZERS.user + queryset = User.objects.all() + permission_classes = settings.PERMISSIONS.user + token_generator = default_token_generator + lookup_field = settings.USER_ID_FIELD + + def permission_denied(self, request, **kwargs): + if ( + settings.HIDE_USERS + and request.user.is_authenticated + and self.action in ["update", "partial_update", "list", "retrieve"] + ): + raise NotFound() + super().permission_denied(request, **kwargs) + + def get_queryset(self): + user = self.request.user + queryset = super().get_queryset() + if settings.HIDE_USERS and self.action == "list" and not user.is_staff: + queryset = queryset.filter(pk=user.pk) + return queryset + + def get_permissions(self): + if self.action == "create": + self.permission_classes = settings.PERMISSIONS.user_create + elif self.action == "activation": + self.permission_classes = settings.PERMISSIONS.activation + elif self.action == "resend_activation": + self.permission_classes = settings.PERMISSIONS.password_reset + elif self.action == "list": + self.permission_classes = settings.PERMISSIONS.user_list + elif self.action == "reset_password": + self.permission_classes = settings.PERMISSIONS.password_reset + elif self.action == "reset_password_confirm": + self.permission_classes = settings.PERMISSIONS.password_reset_confirm + elif self.action == "set_password": + self.permission_classes = settings.PERMISSIONS.set_password + elif self.action == "set_username": + self.permission_classes = settings.PERMISSIONS.set_username + elif self.action == "reset_username": + self.permission_classes = settings.PERMISSIONS.username_reset + elif self.action == "reset_username_confirm": + self.permission_classes = settings.PERMISSIONS.username_reset_confirm + elif self.action == "destroy" or ( + self.action == "me" and self.request and self.request.method == "DELETE" + ): + self.permission_classes = settings.PERMISSIONS.user_delete + return super().get_permissions() + + def get_serializer_class(self): + if self.action == "create": + if settings.USER_CREATE_PASSWORD_RETYPE: + return settings.SERIALIZERS.user_create_password_retype + return settings.SERIALIZERS.user_create + elif self.action == "destroy" or ( + self.action == "me" and self.request and self.request.method == "DELETE" + ): + return settings.SERIALIZERS.user_delete + elif self.action == "activation": + return settings.SERIALIZERS.activation + elif self.action == "resend_activation": + return settings.SERIALIZERS.password_reset + elif self.action == "reset_password": + return settings.SERIALIZERS.password_reset + elif self.action == "reset_password_confirm": + if settings.PASSWORD_RESET_CONFIRM_RETYPE: + return settings.SERIALIZERS.password_reset_confirm_retype + return settings.SERIALIZERS.password_reset_confirm + elif self.action == "set_password": + if settings.SET_PASSWORD_RETYPE: + return settings.SERIALIZERS.set_password_retype + return settings.SERIALIZERS.set_password + elif self.action == "set_username": + if settings.SET_USERNAME_RETYPE: + return settings.SERIALIZERS.set_username_retype + return settings.SERIALIZERS.set_username + elif self.action == "reset_username": + return settings.SERIALIZERS.username_reset + elif self.action == "reset_username_confirm": + if settings.USERNAME_RESET_CONFIRM_RETYPE: + return settings.SERIALIZERS.username_reset_confirm_retype + return settings.SERIALIZERS.username_reset_confirm + elif self.action == "me": + return settings.SERIALIZERS.current_user + + return self.serializer_class + + def get_instance(self): + return self.request.user + + def perform_create(self, serializer): + user = serializer.save() + signals.user_registered.send( + sender=self.__class__, user=user, request=self.request + ) + + context = {"user": user} + to = [get_user_email(user)] + if settings.SEND_ACTIVATION_EMAIL: + settings.EMAIL.activation(self.request, context).send(to) + elif settings.SEND_CONFIRMATION_EMAIL: + settings.EMAIL.confirmation(self.request, context).send(to) + + def perform_update(self, serializer): + super().perform_update(serializer) + user = serializer.instance + # should we send activation email after update? + if settings.SEND_ACTIVATION_EMAIL: + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.activation(self.request, context).send(to) + + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + serializer = self.get_serializer(instance, data=request.data) + serializer.is_valid(raise_exception=True) + + if instance == request.user: + utils.logout_user(self.request) + self.perform_destroy(instance) + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["get", "put", "patch", "delete"], detail=False) + def me(self, request, *args, **kwargs): + self.get_object = self.get_instance + if request.method == "GET": + return self.retrieve(request, *args, **kwargs) + elif request.method == "PUT": + return self.update(request, *args, **kwargs) + elif request.method == "PATCH": + return self.partial_update(request, *args, **kwargs) + elif request.method == "DELETE": + return self.destroy(request, *args, **kwargs) + + @action(["post"], detail=False) + def activation(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.user + user.is_active = True + user.save() + + signals.user_activated.send( + sender=self.__class__, user=user, request=self.request + ) + + if settings.SEND_CONFIRMATION_EMAIL: + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.confirmation(self.request, context).send(to) + + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False) + def resend_activation(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.get_user(is_active=False) + + if not settings.SEND_ACTIVATION_EMAIL or not user: + return Response(status=status.HTTP_400_BAD_REQUEST) + + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.activation(self.request, context).send(to) + + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False) + def set_password(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + + self.request.user.set_password(serializer.data["new_password"]) + self.request.user.save() + + if settings.PASSWORD_CHANGED_EMAIL_CONFIRMATION: + context = {"user": self.request.user} + to = [get_user_email(self.request.user)] + settings.EMAIL.password_changed_confirmation(self.request, context).send(to) + + if settings.LOGOUT_ON_PASSWORD_CHANGE: + utils.logout_user(self.request) + elif settings.CREATE_SESSION_ON_LOGIN: + update_session_auth_hash(self.request, self.request.user) + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False) + def reset_password(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.get_user() + + if user: + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.password_reset(self.request, context).send(to) + + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False) + def reset_password_confirm(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + + serializer.user.set_password(serializer.data["new_password"]) + if hasattr(serializer.user, "last_login"): + serializer.user.last_login = now() + serializer.user.save() + + if settings.PASSWORD_CHANGED_EMAIL_CONFIRMATION: + context = {"user": serializer.user} + to = [get_user_email(serializer.user)] + settings.EMAIL.password_changed_confirmation(self.request, context).send(to) + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False, url_path="set_{}".format(User.USERNAME_FIELD)) + def set_username(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = self.request.user + new_username = serializer.data["new_" + User.USERNAME_FIELD] + + setattr(user, User.USERNAME_FIELD, new_username) + user.save() + if settings.USERNAME_CHANGED_EMAIL_CONFIRMATION: + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.username_changed_confirmation(self.request, context).send(to) + return Response(status=status.HTTP_204_NO_CONTENT) + + @action(["post"], detail=False, url_path="reset_{}".format(User.USERNAME_FIELD)) + def reset_username(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.get_user() + + if user: + context = {"user": user} + to = [get_user_email(user)] + settings.EMAIL.username_reset(self.request, context).send(to) + + return Response(status=status.HTTP_204_NO_CONTENT) + + @action( + ["post"], detail=False, url_path="reset_{}_confirm".format(User.USERNAME_FIELD) + ) + def reset_username_confirm(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + new_username = serializer.data["new_" + User.USERNAME_FIELD] + + setattr(serializer.user, User.USERNAME_FIELD, new_username) + if hasattr(serializer.user, "last_login"): + serializer.user.last_login = now() + serializer.user.save() + + if settings.USERNAME_CHANGED_EMAIL_CONFIRMATION: + context = {"user": serializer.user} + to = [get_user_email(serializer.user)] + settings.EMAIL.username_changed_confirmation(self.request, context).send(to) + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/LICENSE.md b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..e92b342ba5a069be59efade883f858431794ec1a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/LICENSE.md @@ -0,0 +1,29 @@ +# License + +Copyright © 2017-present, Tom Christie. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..59eaa360440ed269a0e851562f04a6d0f65cc8b8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/METADATA @@ -0,0 +1,179 @@ +Metadata-Version: 2.1 +Name: itypes +Version: 1.2.0 +Summary: Simple immutable types for python. +Home-page: http://github.com/PavanTatikonda/itypes +Author: Tom Christie +Author-email: tom@tomchristie.com +License: BSD +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD 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: Topic :: Internet :: WWW/HTTP +Description-Content-Type: text/markdown + +# itypes + +[](https://travis-ci.org/PavanTatikonda/itypes) + +Basic immutable container types for Python. + +A simple implementation that's designed for simplicity over performance. + +Use these in circumstances where it may result in more comprehensible code, +or when you want to create custom types with restricted, immutable interfaces. + +For an alternative implementation designed for performance, +please see [pyrsistent](https://github.com/tobgu/pyrsistent). + +### Installation + +Install using `pip`: + + pip install itypes + +### Instantiating dictionaries and lists. + + >>> import itypes + >>> d = itypes.Dict({'a': 1, 'b': 2, 'c': 3}) + >>> l = itypes.List(['a', 'b', 'c']) + +### On instantiation, nested types are coerced to immutables. + + >>> d = itypes.Dict({'a': 123, 'b': ['a', 'b', 'c']}) + >>> d['b'] + List(['a', 'b', 'c']) + +### Assignments and deletions return new copies. + +Methods: `set(key, value)`, `delete(key)` + + >>> d2 = d.set('c', 456) + >>> d2 + Dict({'a': 123, 'b': ['a', 'b', 'c'], 'c': 456}) + >>> d3 = d2.delete('a') + >>> d3 + Dict({'b': ['a', 'b', 'c'], 'c': 456}) + +### Standard assignments and deletions fail. + + >>> d['z'] = 123 + TypeError: 'Dict' object doesn't support item assignment + >>> del(d['c']) + TypeError: 'Dict' object doesn't support item deletion + +### Nested lookups. + +Method: `get_in(keys, default=None)` + + >>> d['b'][-1] + 'c' + >>> d['b'][5] + IndexError: list index out of range + >>> d.get_in(['b', -1]) + 'c' + >>> d.get_in(['b', 5]) + None + +### Nested assignments and deletions. + +Methods: `set_in(keys, value)`, `delete_in(keys)` + + >>> d2 = d.set_in(['b', 1], 'xxx') + >>> d2 + Dict({'a': 123, 'b': ['a', 'xxx', 'c']}) + >>> d3 = d2.delete_in(['b', 0]) + >>> d3 + Dict({'a': 123, 'b': ['xxx', 'c']}) + +### Equality works against standard types. + + >>> d = itypes.Dict({'a': 1, 'b': 2, 'c': 3}) + >>> d == {'a': 1, 'b': 2, 'c': 3} + True + +### Objects are hashable. + + >>> hash(d) + 277752239 + +### Shortcuts for switching between mutable and immutable types. + +Functions: `to_mutable(instance)`, `to_immutable(value)` + + >>> value = itypes.to_mutable(d) + >>> value + {'a': 123, 'b': ['a', 'b', 'c']} + >>> itypes.to_immutable(value) + Dict({'a': 123, 'b': ['a', 'b', 'c']}) + +### Subclassing. + +Only private attribute names may be set on instances. Use `@property` for attribute access. + +Define a `.clone(self, data)` method if objects have additional state. + +Example: + + class Configuration(itypes.Dict): + def __init__(self, title, *args, **kwargs): + self._title = title + super(Configuration, self).__init__(*args, **kwargs) + + @property + def title(self): + return self._title + + def clone(self, data): + return Configuration(self._title, data) + +Using the custom class: + + >>> config = Configuration('worker-process', {'hostname': 'example.com', 'dynos': 4}) + >>> config.title + 'worker-process' + >>> new = config.set('dynos', 2) + >>> new + Configuration({'dynos': 2, 'hostname': 'example.com'}) + >>> new.title + 'worker-process' + +### Custom immutable objects. + +Subclass `itypes.Object` for an object that prevents setting public attributes. + + >>> class Custom(itypes.Object): + ... pass + +Only private attribute names may be set on instances. Use `@property` for attribute access. + + >>> class Document(itypes.Object): + ... def __init__(self, title, content): + ... self._title = title + ... self._content = title + ... @property + ... def title(self): + ... return self._title + ... @property + ... def content(self): + ... return self._content + +Using immutable objects: + + >>> doc = Document(title='Immutability', content='For simplicity') + >>> doc.title + 'Immutability' + >>> doc.title = 'Changed' + TypeError: 'Document' object doesn't support property assignment. + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..48633e03d8ba24f005ed64af044d6c9c53df93fd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/itypes.cpython-310.pyc,, +itypes-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itypes-1.2.0.dist-info/LICENSE.md,sha256=fzfq6TX37D4-pYuEsMpLGMe2JFQiB8q5t1ao3E1SsTY,1509 +itypes-1.2.0.dist-info/METADATA,sha256=NrnyWwghZ6e5p4it38HxQmyx7AOaliYlxZ9kE9nN1rk,4914 +itypes-1.2.0.dist-info/RECORD,, +itypes-1.2.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +itypes-1.2.0.dist-info/top_level.txt,sha256=oyBU3buGAdsCnA51opQb1MZHSY0vp2fUYPWaHRP9JXE,7 +itypes.py,sha256=PTcw3Wj3RqbTdn0gx3kE0bDBJXn0Jsano83VCGHcZEU,5655 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..ef99c6cf3283b50a273ac4c6d009a0aa85597070 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..ada05e60e68852c176bdcae015780999c709ea21 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes-1.2.0.dist-info/top_level.txt @@ -0,0 +1 @@ +itypes diff --git a/Latest_Group_Project/.venv/Lib/site-packages/itypes.py b/Latest_Group_Project/.venv/Lib/site-packages/itypes.py new file mode 100644 index 0000000000000000000000000000000000000000..e8d3d031dabe02e374653e9cc29d58ac560db1df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/itypes.py @@ -0,0 +1,224 @@ +# coding: utf-8 +try: + from collections.abc import Mapping, Sequence +except ImportError: # support for python 2.x + from collections import Mapping, Sequence + + +__version__ = '1.2.0' + + +def to_mutable(instance): + if isinstance(instance, Dict): + return { + key: to_mutable(value) + for key, value in instance.items() + } + elif isinstance(instance, List): + return [ + to_mutable(value) + for value in instance + ] + return instance + + +def to_immutable(value): + if isinstance(value, dict): + return Dict(value) + elif isinstance(value, list): + return List(value) + return value + + +def _to_hashable(instance): + if isinstance(instance, Dict): + items = sorted(instance.items(), key=lambda item: item[0]) + return ( + (key, _to_hashable(value)) + for key, value in items + ) + elif isinstance(instance, List): + return [ + _to_hashable(value) + for value in instance + ] + return instance + + +def _set_in(node, keys, value): + if not keys: + return value + elif len(keys) == 1: + return node.set(keys[0], value) + + key = keys[0] + child = node[key] + if not isinstance(child, (Dict, List)): + msg = "Expected a container type at key '%s', but got '%s'" + raise KeyError(msg % type(child)) + child = child.set_in(keys[1:], value) + return node.set(key, child) + + +def _delete_in(node, keys): + if not keys: + return + elif len(keys) == 1: + return node.delete(keys[0]) + + key = keys[0] + child = node[key] + if not isinstance(child, (Dict, List)): + msg = "Expected a container type at key '%s', but got '%s'" + raise KeyError(msg % type(child)) + child = child.delete_in(keys[1:]) + return node.set(key, child) + + +def _get_in(node, keys, default=None): + if not keys: + return default + + key = keys[0] + try: + child = node[key] + except (KeyError, IndexError): + return default + + if len(keys) == 1: + return child + return child.get_in(keys[1:], default=default) + + +class Object(object): + def __setattr__(self, key, value): + if key.startswith('_'): + return object.__setattr__(self, key, value) + msg = "'%s' object doesn't support property assignment." + raise TypeError(msg % self.__class__.__name__) + + +class Dict(Mapping): + def __init__(self, *args, **kwargs): + self._data = { + key: to_immutable(value) + for key, value in dict(*args, **kwargs).items() + } + + def __setattr__(self, key, value): + if key.startswith('_'): + return object.__setattr__(self, key, value) + msg = "'%s' object doesn't support property assignment." + raise TypeError(msg % self.__class__.__name__) + + def __getitem__(self, key): + return self._data[key] + + def __iter__(self): + return iter(self._data) + + def __len__(self): + return len(self._data) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self._data == other._data + return self._data == other + + def __hash__(self): + return hash(_to_hashable(self)) + + def __repr__(self): + return "%s(%s)" % ( + self.__class__.__name__, + to_mutable(self) + ) + + def __str__(self): + return str(self._data) + + def set(self, key, value): + data = dict(self._data) + data[key] = value + if hasattr(self, 'clone'): + return self.clone(data) + return type(self)(data) + + def delete(self, key): + data = dict(self._data) + data.pop(key) + if hasattr(self, 'clone'): + return self.clone(data) + return type(self)(data) + + def get_in(self, keys, default=None): + return _get_in(self, keys, default=default) + + def set_in(self, keys, value): + return _set_in(self, keys, value) + + def delete_in(self, keys): + return _delete_in(self, keys) + + +class List(Sequence): + def __init__(self, *args): + self._data = [ + to_immutable(value) + for value in list(*args) + ] + + def __setattr__(self, key, value): + if key == '_data': + return object.__setattr__(self, key, value) + msg = "'%s' object doesn't support property assignment." + raise TypeError(msg % self.__class__.__name__) + + def __getitem__(self, key): + return self._data[key] + + def __iter__(self): + return iter(self._data) + + def __len__(self): + return len(self._data) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self._data == other._data + return self._data == other + + def __hash__(self): + return hash(_to_hashable(self)) + + def __repr__(self): + return "%s(%s)" % ( + self.__class__.__name__, + to_mutable(self) + ) + + def __str__(self): + return str(self._data) + + def set(self, key, value): + data = list(self._data) + data[key] = value + if hasattr(self, 'clone'): + return self.clone(data) + return type(self)(data) + + def delete(self, key): + data = list(self._data) + data.pop(key) + if hasattr(self, 'clone'): + return self.clone(data) + return type(self)(data) + + def get_in(self, keys, default=None): + return _get_in(self, keys, default=default) + + def set_in(self, keys, value): + return _set_in(self, keys, value) + + def delete_in(self, keys): + return _delete_in(self, keys) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e32392679edd18917d0f218bfb316d5256203042 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__init__.py @@ -0,0 +1,37 @@ +"""Jinja is a template engine written in pure Python. It provides a +non-XML syntax that supports inline expressions and an optional +sandboxed environment. +""" +from .bccache import BytecodeCache as BytecodeCache +from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache +from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache +from .environment import Environment as Environment +from .environment import Template as Template +from .exceptions import TemplateAssertionError as TemplateAssertionError +from .exceptions import TemplateError as TemplateError +from .exceptions import TemplateNotFound as TemplateNotFound +from .exceptions import TemplateRuntimeError as TemplateRuntimeError +from .exceptions import TemplatesNotFound as TemplatesNotFound +from .exceptions import TemplateSyntaxError as TemplateSyntaxError +from .exceptions import UndefinedError as UndefinedError +from .loaders import BaseLoader as BaseLoader +from .loaders import ChoiceLoader as ChoiceLoader +from .loaders import DictLoader as DictLoader +from .loaders import FileSystemLoader as FileSystemLoader +from .loaders import FunctionLoader as FunctionLoader +from .loaders import ModuleLoader as ModuleLoader +from .loaders import PackageLoader as PackageLoader +from .loaders import PrefixLoader as PrefixLoader +from .runtime import ChainableUndefined as ChainableUndefined +from .runtime import DebugUndefined as DebugUndefined +from .runtime import make_logging_undefined as make_logging_undefined +from .runtime import StrictUndefined as StrictUndefined +from .runtime import Undefined as Undefined +from .utils import clear_caches as clear_caches +from .utils import is_undefined as is_undefined +from .utils import pass_context as pass_context +from .utils import pass_environment as pass_environment +from .utils import pass_eval_context as pass_eval_context +from .utils import select_autoescape as select_autoescape + +__version__ = "3.1.2" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aff43a80d90d20141e21e3d4ddf0fbedf19a3d84 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03a43dd3c9b8f80e38570a0436db9217533abf8f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a0278eeab65953d24b21babfb62f527ef44d664 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..887d37c26f057af3ef3915190cb0029a43447e9e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0295525a074a9038830d2954bdd003b7d44c7b2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a90b845c042d5007e582e8582fd50faa1d15ac8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46ed2943bea34a5083b69758e7a7a7054d1fb105 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcb349cf5988558ed3c25fa48474520ca31f0f11 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb109fe14b9eeb9962d62558f69c8086ac936adf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29a8f5a96643a5c08ebcbf92978707350788525f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f4ca92e9d1bdb4a0b8348da851fd5bc78c867b2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66392142a2fc7fe9a7d9fbf61170e6c469fcca3c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..133d8250cec8e237ab4ce6eb43d8af23961ce28f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97bb811e0777bd4a1ee74232aa8aeae4fbb3a558 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f47e7573f9d79c19186142efe44888ff05a6b40b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2805d92d7edf8453a55c8378f98dbcb7a9eb5d25 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c592861fbb97625044718af259adf7dff0867d33 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81f4dede94c0dc3762c353bd69daf952d784eaab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7dc0be62bb4720665a2ee83fcbd871c625b805a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dce62d72ccd2b7ff506c67b8a8231cf1ad0a7ec0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ea0855461e860eee1d4795bb6f07e6b9a0fb70a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fff23eb0c48d2401baea806d816b6e0c1697fb9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4afb912cc74a041939d609a3a3208bb3bf127f4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a921959da8097f112d8f393691a6b4f23910a4fb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..830dc194f1ba97ee122ef9814d0795f3cc6dfed7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/_identifier.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/_identifier.py new file mode 100644 index 0000000000000000000000000000000000000000..928c1503c7d414a8a86bbf5a82c68d42cb089bd2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/_identifier.py @@ -0,0 +1,6 @@ +import re + +# generated by scripts/generate_identifier_pattern.py +pattern = re.compile( + r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/async_utils.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/async_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1a4f3892cef1a53632476933f2ce2d86fc31b10a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/async_utils.py @@ -0,0 +1,84 @@ +import inspect +import typing as t +from functools import WRAPPER_ASSIGNMENTS +from functools import wraps + +from .utils import _PassArg +from .utils import pass_eval_context + +V = t.TypeVar("V") + + +def async_variant(normal_func): # type: ignore + def decorator(async_func): # type: ignore + pass_arg = _PassArg.from_obj(normal_func) + need_eval_context = pass_arg is None + + if pass_arg is _PassArg.environment: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].is_async) + + else: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].environment.is_async) + + # Take the doc and annotations from the sync function, but the + # name from the async function. Pallets-Sphinx-Themes + # build_function_directive expects __wrapped__ to point to the + # sync function. + async_func_attrs = ("__module__", "__name__", "__qualname__") + normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) + + @wraps(normal_func, assigned=normal_func_attrs) + @wraps(async_func, assigned=async_func_attrs, updated=()) + def wrapper(*args, **kwargs): # type: ignore + b = is_async(args) + + if need_eval_context: + args = args[1:] + + if b: + return async_func(*args, **kwargs) + + return normal_func(*args, **kwargs) + + if need_eval_context: + wrapper = pass_eval_context(wrapper) + + wrapper.jinja_async_variant = True + return wrapper + + return decorator + + +_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} + + +async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": + # Avoid a costly call to isawaitable + if type(value) in _common_primitives: + return t.cast("V", value) + + if inspect.isawaitable(value): + return await t.cast("t.Awaitable[V]", value) + + return t.cast("V", value) + + +async def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + async for item in t.cast("t.AsyncIterable[V]", iterable): + yield item + else: + for item in t.cast("t.Iterable[V]", iterable): + yield item + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/bccache.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/bccache.py new file mode 100644 index 0000000000000000000000000000000000000000..d0ddf56ef62b03cba6b6c5f9b94d819393f09d38 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/bccache.py @@ -0,0 +1,406 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: + ... + + def set(self, key: str, value: bytes, timeout: t.Optional[int] = None) -> None: + ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib <https://github.com/pallets/cachelib>`_ + - `python-memcached <https://pypi.org/project/python-memcached/>`_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/compiler.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/compiler.py new file mode 100644 index 0000000000000000000000000000000000000000..3458095f54ede1322eb2ab9e34288da87db54ca1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/compiler.py @@ -0,0 +1,1957 @@ +"""Compiles nodes from the parser into Python code.""" +import typing as t +from contextlib import contextmanager +from functools import update_wrapper +from io import StringIO +from itertools import chain +from keyword import iskeyword as is_python_keyword + +from markupsafe import escape +from markupsafe import Markup + +from . import nodes +from .exceptions import TemplateAssertionError +from .idtracking import Symbols +from .idtracking import VAR_LOAD_ALIAS +from .idtracking import VAR_LOAD_PARAMETER +from .idtracking import VAR_LOAD_RESOLVE +from .idtracking import VAR_LOAD_UNDEFINED +from .nodes import EvalContext +from .optimizer import Optimizer +from .utils import _PassArg +from .utils import concat +from .visitor import NodeVisitor + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +operators = { + "eq": "==", + "ne": "!=", + "gt": ">", + "gteq": ">=", + "lt": "<", + "lteq": "<=", + "in": "in", + "notin": "not in", +} + + +def optimizeconst(f: F) -> F: + def new_func( + self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any + ) -> t.Any: + # Only optimize if the frame is not volatile + if self.optimizer is not None and not frame.eval_ctx.volatile: + new_node = self.optimizer.visit(node, frame.eval_ctx) + + if new_node != node: + return self.visit(new_node, frame) + + return f(self, node, frame, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_binops # type: ignore + ): + self.write(f"environment.call_binop(context, {op!r}, ") + self.visit(node.left, frame) + self.write(", ") + self.visit(node.right, frame) + else: + self.write("(") + self.visit(node.left, frame) + self.write(f" {op} ") + self.visit(node.right, frame) + + self.write(")") + + return visitor + + +def _make_unop( + op: str, +) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_unops # type: ignore + ): + self.write(f"environment.call_unop(context, {op!r}, ") + self.visit(node.node, frame) + else: + self.write("(" + op) + self.visit(node.node, frame) + + self.write(")") + + return visitor + + +def generate( + node: nodes.Template, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, +) -> t.Optional[str]: + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError("Can't compile non template nodes") + + generator = environment.code_generator_class( + environment, name, filename, stream, defer_init, optimized + ) + generator.visit(node) + + if stream is None: + return generator.stream.getvalue() # type: ignore + + return None + + +def has_safe_repr(value: t.Any) -> bool: + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + + if type(value) in {bool, int, float, complex, range, str, Markup}: + return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + + return False + + +def find_undeclared( + nodes: t.Iterable[nodes.Node], names: t.Iterable[str] +) -> t.Set[str]: + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class MacroRef: + def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: + self.node = node + self.accesses_caller = False + self.accesses_kwargs = False + self.accesses_varargs = False + + +class Frame: + """Holds compile time information for us.""" + + def __init__( + self, + eval_ctx: EvalContext, + parent: t.Optional["Frame"] = None, + level: t.Optional[int] = None, + ) -> None: + self.eval_ctx = eval_ctx + + # the parent of this frame + self.parent = parent + + if parent is None: + self.symbols = Symbols(level=level) + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = False + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer: t.Optional[str] = None + + # the name of the block we're in, otherwise None. + self.block: t.Optional[str] = None + + else: + self.symbols = Symbols(parent.symbols, level=level) + self.require_output_check = parent.require_output_check + self.buffer = parent.buffer + self.block = parent.block + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # variables set inside of loops and blocks should not affect outer frames, + # but they still needs to be kept track of as part of the active context. + self.loop_frame = False + self.block_frame = False + + # track whether the frame is being used in an if-statement or conditional + # expression as it determines which errors should be raised during runtime + # or compile time. + self.soft_frame = False + + def copy(self) -> "Frame": + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.symbols = self.symbols.copy() + return rv + + def inner(self, isolated: bool = False) -> "Frame": + """Return an inner frame.""" + if isolated: + return Frame(self.eval_ctx, level=self.symbols.level + 1) + return Frame(self.eval_ctx, self) + + def soft(self) -> "Frame": + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + + This is only used to implement if-statements and conditional + expressions. + """ + rv = self.copy() + rv.rootlevel = False + rv.soft_frame = True + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self) -> None: + self.filters: t.Set[str] = set() + self.tests: t.Set[str] = set() + + def visit_Filter(self, node: nodes.Filter) -> None: + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node: nodes.Test) -> None: + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names: t.Iterable[str]) -> None: + self.names = set(names) + self.undeclared: t.Set[str] = set() + + def visit_Name(self, node: nodes.Name) -> None: + if node.ctx == "load" and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting a blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + def __init__( + self, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, + ) -> None: + if stream is None: + stream = StringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + self.optimizer: t.Optional[Optimizer] = None + + if optimized: + self.optimizer = Optimizer(environment) + + # aliases for imports + self.import_aliases: t.Dict[str, str] = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks: t.Dict[str, nodes.Block] = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests: t.Dict[str, str] = {} + self.filters: t.Dict[str, str] = {} + + # the debug information + self.debug_info: t.List[t.Tuple[int, int]] = [] + self._write_debug_info: t.Optional[int] = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # Tracks toplevel assignments + self._assign_stack: t.List[t.Set[str]] = [] + + # Tracks parameter definition blocks + self._param_def_block: t.List[t.Set[str]] = [] + + # Tracks the current context. + self._context_reference_stack = ["context"] + + @property + def optimized(self) -> bool: + return self.optimizer is not None + + # -- Various compilation helpers + + def fail(self, msg: str, lineno: int) -> "te.NoReturn": + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self) -> str: + """Get a new unique identifier.""" + self._last_identifier += 1 + return f"t_{self._last_identifier}" + + def buffer(self, frame: Frame) -> None: + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline(f"{frame.buffer} = []") + + def return_buffer_contents( + self, frame: Frame, force_unescaped: bool = False + ) -> None: + """Return the buffer contents of the frame.""" + if not force_unescaped: + if frame.eval_ctx.volatile: + self.writeline("if context.eval_ctx.autoescape:") + self.indent() + self.writeline(f"return Markup(concat({frame.buffer}))") + self.outdent() + self.writeline("else:") + self.indent() + self.writeline(f"return concat({frame.buffer})") + self.outdent() + return + elif frame.eval_ctx.autoescape: + self.writeline(f"return Markup(concat({frame.buffer}))") + return + self.writeline(f"return concat({frame.buffer})") + + def indent(self) -> None: + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step: int = 1) -> None: + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline("yield ", node) + else: + self.writeline(f"{frame.buffer}.append(", node) + + def end_write(self, frame: Frame) -> None: + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(")") + + def simple_write( + self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None + ) -> None: + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically. + """ + try: + self.writeline("pass") + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x: str) -> None: + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write("\n" * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(" " * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline( + self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 + ) -> None: + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature( + self, + node: t.Union[nodes.Call, nodes.Filter, nodes.Test], + frame: Frame, + extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> None: + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occur. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = any( + is_python_keyword(t.cast(str, k)) + for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) + ) + + for arg in node.args: + self.write(", ") + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(", ") + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f", {key}={value}") + if node.dyn_args: + self.write(", *") + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(", **dict({") + else: + self.write(", **{") + for kwarg in node.kwargs: + self.write(f"{kwarg.key!r}: ") + self.visit(kwarg.value, frame) + self.write(", ") + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f"{key!r}: {value}, ") + if node.dyn_kwargs is not None: + self.write("}, **") + self.visit(node.dyn_kwargs, frame) + self.write(")") + else: + self.write("}") + + elif node.dyn_kwargs is not None: + self.write(", **") + self.visit(node.dyn_kwargs, frame) + + def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: + """Find all filter and test names used in the template and + assign them to variables in the compiled namespace. Checking + that the names are registered with the environment is done when + compiling the Filter and Test nodes. If the node is in an If or + CondExpr node, the check is done at runtime instead. + + .. versionchanged:: 3.0 + Filters and tests in If and CondExpr nodes are checked at + runtime instead of compile time. + """ + visitor = DependencyFinderVisitor() + + for node in nodes: + visitor.visit(node) + + for id_map, names, dependency in (self.filters, visitor.filters, "filters"), ( + self.tests, + visitor.tests, + "tests", + ): + for name in sorted(names): + if name not in id_map: + id_map[name] = self.temporary_identifier() + + # add check during runtime that dependencies used inside of executed + # blocks are defined, as this step may be skipped during compile time + self.writeline("try:") + self.indent() + self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") + self.outdent() + self.writeline("except KeyError:") + self.indent() + self.writeline("@internalcode") + self.writeline(f"def {id_map[name]}(*unused):") + self.indent() + self.writeline( + f'raise TemplateRuntimeError("No {dependency[:-1]}' + f' named {name!r} found.")' + ) + self.outdent() + self.outdent() + + def enter_frame(self, frame: Frame) -> None: + undefs = [] + for target, (action, param) in frame.symbols.loads.items(): + if action == VAR_LOAD_PARAMETER: + pass + elif action == VAR_LOAD_RESOLVE: + self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") + elif action == VAR_LOAD_ALIAS: + self.writeline(f"{target} = {param}") + elif action == VAR_LOAD_UNDEFINED: + undefs.append(target) + else: + raise NotImplementedError("unknown load instruction") + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: + if not with_python_scope: + undefs = [] + for target in frame.symbols.loads: + undefs.append(target) + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: + return async_value if self.environment.is_async else sync_value + + def func(self, name: str) -> str: + return f"{self.choose_async()}def {name}" + + def macro_body( + self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame + ) -> t.Tuple[Frame, MacroRef]: + """Dump the function def of a macro or call block.""" + frame = frame.inner() + frame.symbols.analyze_node(node) + macro_ref = MacroRef(node) + + explicit_caller = None + skip_special_params = set() + args = [] + + for idx, arg in enumerate(node.args): + if arg.name == "caller": + explicit_caller = idx + if arg.name in ("kwargs", "varargs"): + skip_special_params.add(arg.name) + args.append(frame.symbols.ref(arg.name)) + + undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) + + if "caller" in undeclared: + # In older Jinja versions there was a bug that allowed caller + # to retain the special behavior even if it was mentioned in + # the argument list. However thankfully this was only really + # working if it was the last argument. So we are explicitly + # checking this now and error out if it is anywhere else in + # the argument list. + if explicit_caller is not None: + try: + node.defaults[explicit_caller - len(node.args)] + except IndexError: + self.fail( + "When defining macros or call blocks the " + 'special "caller" argument must be omitted ' + "or be given a default.", + node.lineno, + ) + else: + args.append(frame.symbols.declare_parameter("caller")) + macro_ref.accesses_caller = True + if "kwargs" in undeclared and "kwargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("kwargs")) + macro_ref.accesses_kwargs = True + if "varargs" in undeclared and "varargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("varargs")) + macro_ref.accesses_varargs = True + + # macros are delayed, they never require output checks + frame.require_output_check = False + frame.symbols.analyze_node(node) + self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) + self.indent() + + self.buffer(frame) + self.enter_frame(frame) + + self.push_parameter_definitions(frame) + for idx, arg in enumerate(node.args): + ref = frame.symbols.ref(arg.name) + self.writeline(f"if {ref} is missing:") + self.indent() + try: + default = node.defaults[idx - len(node.args)] + except IndexError: + self.writeline( + f'{ref} = undefined("parameter {arg.name!r} was not provided",' + f" name={arg.name!r})" + ) + else: + self.writeline(f"{ref} = ") + self.visit(default, frame) + self.mark_parameter_stored(ref) + self.outdent() + self.pop_parameter_definitions() + + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame, force_unescaped=True) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + return frame, macro_ref + + def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) + name = getattr(macro_ref.node, "name", None) + if len(macro_ref.node.args) == 1: + arg_tuple += "," + self.write( + f"Macro(environment, macro, {name!r}, ({arg_tuple})," + f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," + f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" + ) + + def position(self, node: nodes.Node) -> str: + """Return a human readable position for the node.""" + rv = f"line {node.lineno}" + if self.name is not None: + rv = f"{rv} in {self.name!r}" + return rv + + def dump_local_context(self, frame: Frame) -> str: + items_kv = ", ".join( + f"{name!r}: {target}" + for name, target in frame.symbols.dump_stores().items() + ) + return f"{{{items_kv}}}" + + def write_commons(self) -> None: + """Writes a common preamble that is used by root and block functions. + Primarily this sets up common local helpers and enforces a generator + through a dead branch. + """ + self.writeline("resolve = context.resolve_or_missing") + self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") + # always use the standard Undefined class for the implicit else of + # conditional expressions + self.writeline("cond_expr_undefined = Undefined") + self.writeline("if 0: yield None") + + def push_parameter_definitions(self, frame: Frame) -> None: + """Pushes all parameter targets from the given frame into a local + stack that permits tracking of yet to be assigned parameters. In + particular this enables the optimization from `visit_Name` to skip + undefined expressions for parameters in macros as macros can reference + otherwise unbound parameters. + """ + self._param_def_block.append(frame.symbols.dump_param_targets()) + + def pop_parameter_definitions(self) -> None: + """Pops the current parameter definitions set.""" + self._param_def_block.pop() + + def mark_parameter_stored(self, target: str) -> None: + """Marks a parameter in the current parameter definitions as stored. + This will skip the enforced undefined checks. + """ + if self._param_def_block: + self._param_def_block[-1].discard(target) + + def push_context_reference(self, target: str) -> None: + self._context_reference_stack.append(target) + + def pop_context_reference(self) -> None: + self._context_reference_stack.pop() + + def get_context_ref(self) -> str: + return self._context_reference_stack[-1] + + def get_resolve_func(self) -> str: + target = self._context_reference_stack[-1] + if target == "context": + return "resolve" + return f"{target}.resolve" + + def derive_context(self, frame: Frame) -> str: + return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" + + def parameter_is_undeclared(self, target: str) -> bool: + """Checks if a given target is an undeclared parameter.""" + if not self._param_def_block: + return False + return target in self._param_def_block[-1] + + def push_assign_tracking(self) -> None: + """Pushes a new layer for assignment tracking.""" + self._assign_stack.append(set()) + + def pop_assign_tracking(self, frame: Frame) -> None: + """Pops the topmost level for assignment tracking and updates the + context variables if necessary. + """ + vars = self._assign_stack.pop() + if ( + not frame.block_frame + and not frame.loop_frame + and not frame.toplevel + or not vars + ): + return + public_names = [x for x in vars if x[:1] != "_"] + if len(vars) == 1: + name = next(iter(vars)) + ref = frame.symbols.ref(name) + if frame.loop_frame: + self.writeline(f"_loop_vars[{name!r}] = {ref}") + return + if frame.block_frame: + self.writeline(f"_block_vars[{name!r}] = {ref}") + return + self.writeline(f"context.vars[{name!r}] = {ref}") + else: + if frame.loop_frame: + self.writeline("_loop_vars.update({") + elif frame.block_frame: + self.writeline("_block_vars.update({") + else: + self.writeline("context.vars.update({") + for idx, name in enumerate(vars): + if idx: + self.write(", ") + ref = frame.symbols.ref(name) + self.write(f"{name!r}: {ref}") + self.write("})") + if not frame.block_frame and not frame.loop_frame and public_names: + if len(public_names) == 1: + self.writeline(f"context.exported_vars.add({public_names[0]!r})") + else: + names_str = ", ".join(map(repr, public_names)) + self.writeline(f"context.exported_vars.update(({names_str}))") + + # -- Statement Visitors + + def visit_Template( + self, node: nodes.Template, frame: t.Optional[Frame] = None + ) -> None: + assert frame is None, "no root frame allowed" + eval_ctx = EvalContext(self.environment, self.name) + + from .runtime import exported, async_exported + + if self.environment.is_async: + exported_names = sorted(exported + async_exported) + else: + exported_names = sorted(exported) + + self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = "" if self.defer_init else ", environment=environment" + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail(f"block {block.name!r} defined twice", block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if "." in imp: + module, obj = imp.rsplit(".", 1) + self.writeline(f"from {module} import {obj} as {alias}") + else: + self.writeline(f"import {imp} as {alias}") + + # add the load name + self.writeline(f"name = {self.name!r}") + + # generate the root render function. + self.writeline( + f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 + ) + self.indent() + self.write_commons() + + # process the root + frame = Frame(eval_ctx) + if "self" in find_undeclared(node.body, ("self",)): + ref = frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + frame.symbols.analyze_node(node) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + if have_extends: + self.writeline("parent_template = None") + self.enter_frame(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline("if parent_template is not None:") + self.indent() + if not self.environment.is_async: + self.writeline("yield from parent_template.root_render_func(context)") + else: + self.writeline( + "async for event in parent_template.root_render_func(context):" + ) + self.indent() + self.writeline("yield event") + self.outdent() + self.outdent(1 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in self.blocks.items(): + self.writeline( + f"{self.func('block_' + name)}(context, missing=missing{envenv}):", + block, + 1, + ) + self.indent() + self.write_commons() + # It's important that we do not make this frame a child of the + # toplevel template. This would cause a variety of + # interesting issues with identifier tracking. + block_frame = Frame(eval_ctx) + block_frame.block_frame = True + undeclared = find_undeclared(block.body, ("self", "super")) + if "self" in undeclared: + ref = block_frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + if "super" in undeclared: + ref = block_frame.symbols.declare_parameter("super") + self.writeline(f"{ref} = context.super({name!r}, block_{name})") + block_frame.symbols.analyze_node(block) + block_frame.block = name + self.writeline("_block_vars = {}") + self.enter_frame(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.leave_frame(block_frame, with_python_scope=True) + self.outdent() + + blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) + self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) + debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) + self.writeline(f"debug_info = {debug_kv_str!r}") + + def visit_Block(self, node: nodes.Block, frame: Frame) -> None: + """Call a block and register it for the template.""" + level = 0 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline("if parent_template is None:") + self.indent() + level += 1 + + if node.scoped: + context = self.derive_context(frame) + else: + context = self.get_context_ref() + + if node.required: + self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) + self.indent() + self.writeline( + f'raise TemplateRuntimeError("Required block {node.name!r} not found")', + node, + ) + self.outdent() + + if not self.environment.is_async and frame.buffer is None: + self.writeline( + f"yield from context.blocks[{node.name!r}][0]({context})", node + ) + else: + self.writeline( + f"{self.choose_async()}for event in" + f" context.blocks[{node.name!r}][0]({context}):", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + + self.outdent(level) + + def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: + """Calls the extender.""" + if not frame.toplevel: + self.fail("cannot use extend from a non top-level scope", node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline("if parent_template is not None:") + self.indent() + self.writeline('raise TemplateRuntimeError("extended multiple times")') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline("parent_template = environment.get_template(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + self.writeline("for name, parent_block in parent_template.blocks.items():") + self.indent() + self.writeline("context.blocks.setdefault(name, []).append(parent_block)") + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node: nodes.Include, frame: Frame) -> None: + """Handles includes.""" + if node.ignore_missing: + self.writeline("try:") + self.indent() + + func_name = "get_or_select_template" + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, str): + func_name = "get_template" + elif isinstance(node.template.value, (tuple, list)): + func_name = "select_template" + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = "select_template" + + self.writeline(f"template = environment.{func_name}(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + if node.ignore_missing: + self.outdent() + self.writeline("except TemplateNotFound:") + self.indent() + self.writeline("pass") + self.outdent() + self.writeline("else:") + self.indent() + + skip_event_yield = False + if node.with_context: + self.writeline( + f"{self.choose_async()}for event in template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)})):" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + else: + self.writeline("yield from template._get_default_module()._body_stream") + skip_event_yield = True + + if not skip_event_yield: + self.indent() + self.simple_write("event", frame) + self.outdent() + + if node.ignore_missing: + self.outdent() + + def _import_common( + self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame + ) -> None: + self.write(f"{self.choose_async('await ')}environment.get_template(") + self.visit(node.template, frame) + self.write(f", {self.name!r}).") + + if node.with_context: + f_name = f"make_module{self.choose_async('_async')}" + self.write( + f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" + ) + else: + self.write(f"_get_default_module{self.choose_async('_async')}(context)") + + def visit_Import(self, node: nodes.Import, frame: Frame) -> None: + """Visit regular imports.""" + self.writeline(f"{frame.symbols.ref(node.target)} = ", node) + if frame.toplevel: + self.write(f"context.vars[{node.target!r}] = ") + + self._import_common(node, frame) + + if frame.toplevel and not node.target.startswith("_"): + self.writeline(f"context.exported_vars.discard({node.target!r})") + + def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: + """Visit named imports.""" + self.newline(node) + self.write("included_template = ") + self._import_common(node, frame) + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline( + f"{frame.symbols.ref(alias)} =" + f" getattr(included_template, {name!r}, missing)" + ) + self.writeline(f"if {frame.symbols.ref(alias)} is missing:") + self.indent() + message = ( + "the template {included_template.__name__!r}" + f" (imported on {self.position(node)})" + f" does not export the requested name {name!r}" + ) + self.writeline( + f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" + ) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith("_"): + discarded_names.append(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") + else: + names_kv = ", ".join( + f"{name!r}: {frame.symbols.ref(name)}" for name in var_names + ) + self.writeline(f"context.vars.update({{{names_kv}}})") + if discarded_names: + if len(discarded_names) == 1: + self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") + else: + names_str = ", ".join(map(repr, discarded_names)) + self.writeline( + f"context.exported_vars.difference_update(({names_str}))" + ) + + def visit_For(self, node: nodes.For, frame: Frame) -> None: + loop_frame = frame.inner() + loop_frame.loop_frame = True + test_frame = frame.inner() + else_frame = frame.inner() + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body if the body is a scoped block. + extended_loop = ( + node.recursive + or "loop" + in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) + or any(block.scoped for block in node.find_all(nodes.Block)) + ) + + loop_ref = None + if extended_loop: + loop_ref = loop_frame.symbols.declare_parameter("loop") + + loop_frame.symbols.analyze_node(node, for_branch="body") + if node.else_: + else_frame.symbols.analyze_node(node, for_branch="else") + + if node.test: + loop_filter_func = self.temporary_identifier() + test_frame.symbols.analyze_node(node, for_branch="test") + self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) + self.indent() + self.enter_frame(test_frame) + self.writeline(self.choose_async("async for ", "for ")) + self.visit(node.target, loop_frame) + self.write(" in ") + self.write(self.choose_async("auto_aiter(fiter)", "fiter")) + self.write(":") + self.indent() + self.writeline("if ", node.test) + self.visit(node.test, test_frame) + self.write(":") + self.indent() + self.writeline("yield ") + self.visit(node.target, loop_frame) + self.outdent(3) + self.leave_frame(test_frame, with_python_scope=True) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if node.recursive: + self.writeline( + f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node + ) + self.indent() + self.buffer(loop_frame) + + # Use the same buffer for the else frame + else_frame.buffer = loop_frame.buffer + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline(f"{loop_ref} = missing") + + for name in node.find_all(nodes.Name): + if name.ctx == "store" and name.name == "loop": + self.fail( + "Can't assign to special loop variable in for-loop target", + name.lineno, + ) + + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline(f"{iteration_indicator} = 1") + + self.writeline(self.choose_async("async for ", "for "), node) + self.visit(node.target, loop_frame) + if extended_loop: + self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") + else: + self.write(" in ") + + if node.test: + self.write(f"{loop_filter_func}(") + if node.recursive: + self.write("reciter") + else: + if self.environment.is_async and not extended_loop: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async and not extended_loop: + self.write(")") + if node.test: + self.write(")") + + if node.recursive: + self.write(", undefined, loop_render_func, depth):") + else: + self.write(", undefined):" if extended_loop else ":") + + self.indent() + self.enter_frame(loop_frame) + + self.writeline("_loop_vars = {}") + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline(f"{iteration_indicator} = 0") + self.outdent() + self.leave_frame( + loop_frame, with_python_scope=node.recursive and not node.else_ + ) + + if node.else_: + self.writeline(f"if {iteration_indicator}:") + self.indent() + self.enter_frame(else_frame) + self.blockvisit(node.else_, else_frame) + self.leave_frame(else_frame) + self.outdent() + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write(f"{self.choose_async('await ')}loop(") + if self.environment.is_async: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async: + self.write(")") + self.write(", loop)") + self.end_write(frame) + + # at the end of the iteration, clear any assignments made in the + # loop from the top level + if self._assign_stack: + self._assign_stack[-1].difference_update(loop_frame.symbols.stores) + + def visit_If(self, node: nodes.If, frame: Frame) -> None: + if_frame = frame.soft() + self.writeline("if ", node) + self.visit(node.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + for elif_ in node.elif_: + self.writeline("elif ", elif_) + self.visit(elif_.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(elif_.body, if_frame) + self.outdent() + if node.else_: + self.writeline("else:") + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: + macro_frame, macro_ref = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith("_"): + self.write(f"context.exported_vars.add({node.name!r})") + self.writeline(f"context.vars[{node.name!r}] = ") + self.write(f"{frame.symbols.ref(node.name)} = ") + self.macro_def(macro_ref, macro_frame) + + def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: + call_frame, macro_ref = self.macro_body(node, frame) + self.writeline("caller = ") + self.macro_def(macro_ref, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: + filter_frame = frame.inner() + filter_frame.symbols.analyze_node(node) + self.enter_frame(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.leave_frame(filter_frame) + + def visit_With(self, node: nodes.With, frame: Frame) -> None: + with_frame = frame.inner() + with_frame.symbols.analyze_node(node) + self.enter_frame(with_frame) + for target, expr in zip(node.targets, node.values): + self.newline() + self.visit(target, with_frame) + self.write(" = ") + self.visit(expr, frame) + self.blockvisit(node.body, with_frame) + self.leave_frame(with_frame) + + def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: + self.newline(node) + self.visit(node.node, frame) + + class _FinalizeInfo(t.NamedTuple): + const: t.Optional[t.Callable[..., str]] + src: t.Optional[str] + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + """The default finalize function if the environment isn't + configured with one. Or, if the environment has one, this is + called on that function's output for constants. + """ + return str(value) + + _finalize: t.Optional[_FinalizeInfo] = None + + def _make_finalize(self) -> _FinalizeInfo: + """Build the finalize function to be used on constants and at + runtime. Cached so it's only created once for all output nodes. + + Returns a ``namedtuple`` with the following attributes: + + ``const`` + A function to finalize constant data at compile time. + + ``src`` + Source code to output around nodes to be evaluated at + runtime. + """ + if self._finalize is not None: + return self._finalize + + finalize: t.Optional[t.Callable[..., t.Any]] + finalize = default = self._default_finalize + src = None + + if self.environment.finalize: + src = "environment.finalize(" + env_finalize = self.environment.finalize + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(env_finalize) # type: ignore + ) + finalize = None + + if pass_arg is None: + + def finalize(value: t.Any) -> t.Any: + return default(env_finalize(value)) + + else: + src = f"{src}{pass_arg}, " + + if pass_arg == "environment": + + def finalize(value: t.Any) -> t.Any: + return default(env_finalize(self.environment, value)) + + self._finalize = self._FinalizeInfo(finalize, src) + return self._finalize + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + """Given a group of constant values converted from ``Output`` + child nodes, produce a string to write to the template module + source. + """ + return repr(concat(group)) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> str: + """Try to optimize a child of an ``Output`` node by trying to + convert it to constant, finalized data at compile time. + + If :exc:`Impossible` is raised, the node is not constant and + will be evaluated at runtime. Any other exception will also be + evaluated at runtime for easier debugging. + """ + const = node.as_const(frame.eval_ctx) + + if frame.eval_ctx.autoescape: + const = escape(const) + + # Template data doesn't go through finalize. + if isinstance(node, nodes.TemplateData): + return str(const) + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code before visiting a child of an + ``Output`` node. + """ + if frame.eval_ctx.volatile: + self.write("(escape if context.eval_ctx.autoescape else str)(") + elif frame.eval_ctx.autoescape: + self.write("escape(") + else: + self.write("str(") + + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code after visiting a child of an + ``Output`` node. + """ + self.write(")") + + if finalize.src is not None: + self.write(")") + + def visit_Output(self, node: nodes.Output, frame: Frame) -> None: + # If an extends is active, don't render outside a block. + if frame.require_output_check: + # A top-level extends is known to exist at compile time. + if self.has_known_extends: + return + + self.writeline("if parent_template is None:") + self.indent() + + finalize = self._make_finalize() + body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + + # Evaluate constants at compile time if possible. Each item in + # body will be either a list of static data or a node to be + # evaluated at runtime. + for child in node.nodes: + try: + if not ( + # If the finalize function requires runtime context, + # constants can't be evaluated at compile time. + finalize.const + # Unless it's basic template data that won't be + # finalized anyway. + or isinstance(child, nodes.TemplateData) + ): + raise nodes.Impossible() + + const = self._output_child_to_const(child, frame, finalize) + except (nodes.Impossible, Exception): + # The node was not constant and needs to be evaluated at + # runtime. Or another error was raised, which is easier + # to debug at runtime. + body.append(child) + continue + + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + if frame.buffer is not None: + if len(body) == 1: + self.writeline(f"{frame.buffer}.append(") + else: + self.writeline(f"{frame.buffer}.extend((") + + self.indent() + + for item in body: + if isinstance(item, list): + # A group of constant data to join and output. + val = self._output_const_repr(item) + + if frame.buffer is None: + self.writeline("yield " + val) + else: + self.writeline(val + ",") + else: + if frame.buffer is None: + self.writeline("yield ", item) + else: + self.newline(item) + + # A node to be evaluated at runtime. + self._output_child_pre(item, frame, finalize) + self.visit(item, frame) + self._output_child_post(item, frame, finalize) + + if frame.buffer is not None: + self.write(",") + + if frame.buffer is not None: + self.outdent() + self.writeline(")" if len(body) == 1 else "))") + + if frame.require_output_check: + self.outdent() + + def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: + self.push_assign_tracking() + self.newline(node) + self.visit(node.target, frame) + self.write(" = ") + self.visit(node.node, frame) + self.pop_assign_tracking(frame) + + def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: + self.push_assign_tracking() + block_frame = frame.inner() + # This is a special case. Since a set block always captures we + # will disable output checks. This way one can use set blocks + # toplevel even in extended templates. + block_frame.require_output_check = False + block_frame.symbols.analyze_node(node) + self.enter_frame(block_frame) + self.buffer(block_frame) + self.blockvisit(node.body, block_frame) + self.newline(node) + self.visit(node.target, frame) + self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") + if node.filter is not None: + self.visit_Filter(node.filter, block_frame) + else: + self.write(f"concat({block_frame.buffer})") + self.write(")") + self.pop_assign_tracking(frame) + self.leave_frame(block_frame) + + # -- Expression Visitors + + def visit_Name(self, node: nodes.Name, frame: Frame) -> None: + if node.ctx == "store" and ( + frame.toplevel or frame.loop_frame or frame.block_frame + ): + if self._assign_stack: + self._assign_stack[-1].add(node.name) + ref = frame.symbols.ref(node.name) + + # If we are looking up a variable we might have to deal with the + # case where it's undefined. We can skip that case if the load + # instruction indicates a parameter which are always defined. + if node.ctx == "load": + load = frame.symbols.find_load(ref) + if not ( + load is not None + and load[0] == VAR_LOAD_PARAMETER + and not self.parameter_is_undeclared(ref) + ): + self.write( + f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" + ) + return + + self.write(ref) + + def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: + # NSRefs can only be used to store values; since they use the normal + # `foo.bar` notation they will be parsed as a normal attribute access + # when used anywhere but in a `set` context + ref = frame.symbols.ref(node.name) + self.writeline(f"if not isinstance({ref}, Namespace):") + self.indent() + self.writeline( + "raise TemplateRuntimeError" + '("cannot assign attribute on non-namespace object")' + ) + self.outdent() + self.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/constants.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..41a1c23b0a7fe134b1f662545876eb65b31b071e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/debug.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/debug.py new file mode 100644 index 0000000000000000000000000000000000000000..7ed7e9297e01b87c4e999d19d48a4265b38b574f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "<unknown>", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: "t.Optional[Context]" = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/defaults.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/defaults.py new file mode 100644 index 0000000000000000000000000000000000000000..638cad3d2d8907330bde56e2b76c9b185c523b45 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/environment.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/environment.py new file mode 100644 index 0000000000000000000000000000000000000000..ea04e8b44330fe22909a2c875c6601e33bd1ffc2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/environment.py @@ -0,0 +1,1667 @@ +"""Classes for managing templates and their runtime and compile time +options. +""" +import os +import typing +import typing as t +import weakref +from collections import ChainMap +from functools import lru_cache +from functools import partial +from functools import reduce +from types import CodeType + +from markupsafe import Markup + +from . import nodes +from .compiler import CodeGenerator +from .compiler import generate +from .defaults import BLOCK_END_STRING +from .defaults import BLOCK_START_STRING +from .defaults import COMMENT_END_STRING +from .defaults import COMMENT_START_STRING +from .defaults import DEFAULT_FILTERS +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS +from .defaults import KEEP_TRAILING_NEWLINE +from .defaults import LINE_COMMENT_PREFIX +from .defaults import LINE_STATEMENT_PREFIX +from .defaults import LSTRIP_BLOCKS +from .defaults import NEWLINE_SEQUENCE +from .defaults import TRIM_BLOCKS +from .defaults import VARIABLE_END_STRING +from .defaults import VARIABLE_START_STRING +from .exceptions import TemplateNotFound +from .exceptions import TemplateRuntimeError +from .exceptions import TemplatesNotFound +from .exceptions import TemplateSyntaxError +from .exceptions import UndefinedError +from .lexer import get_lexer +from .lexer import Lexer +from .lexer import TokenStream +from .nodes import EvalContext +from .parser import Parser +from .runtime import Context +from .runtime import new_context +from .runtime import Undefined +from .utils import _PassArg +from .utils import concat +from .utils import consume +from .utils import import_string +from .utils import internalcode +from .utils import LRUCache +from .utils import missing + +if t.TYPE_CHECKING: + import typing_extensions as te + from .bccache import BytecodeCache + from .ext import Extension + from .loaders import BaseLoader + +_env_bound = t.TypeVar("_env_bound", bound="Environment") + + +# for direct template usage we have up to ten living environments +@lru_cache(maxsize=10) +def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: + """Return a new spontaneous environment. A spontaneous environment + is used for templates created directly rather than through an + existing environment. + + :param cls: Environment class to create. + :param args: Positional arguments passed to environment. + """ + env = cls(*args) + env.shared = True + return env + + +def create_cache( + size: int, +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Return the cache class for the given size.""" + if size == 0: + return None + + if size < 0: + return {} + + return LRUCache(size) # type: ignore + + +def copy_cache( + cache: t.Optional[t.MutableMapping], +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: + return {} + + return LRUCache(cache.capacity) # type: ignore + + +def load_extensions( + environment: "Environment", + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], +) -> t.Dict[str, "Extension"]: + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated extensions. + """ + result = {} + + for extension in extensions: + if isinstance(extension, str): + extension = t.cast(t.Type["Extension"], import_string(extension)) + + result[extension.identifier] = extension(environment) + + return result + + +def _environment_config_check(environment: "Environment") -> "Environment": + """Perform a sanity check on the environment.""" + assert issubclass( + environment.undefined, Undefined + ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert ( + environment.block_start_string + != environment.variable_start_string + != environment.comment_start_string + ), "block, variable and comment start strings must be different." + assert environment.newline_sequence in { + "\r", + "\r\n", + "\n", + }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." + return environment + + +class Environment: + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here are the possible initialization parameters: + + `block_start_string` + The string marking the beginning of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the beginning of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the beginning of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation <jinja-extensions>`. + + `optimized` + should the optimizer be enabled? Default is ``True``. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + ``None`` implicitly into an empty string here. + + `autoescape` + If set to ``True`` the XML/HTML autoescaping feature is enabled by + default. For more details about autoescaping see + :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return ``True`` or ``False`` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``400`` which means + that if more than 400 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + .. versionchanged:: 2.8 + The cache size was increased to 400 from a low 50. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + ``auto_reload`` is set to ``True`` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + + `enable_async` + If set to true this enables async template execution which + allows using async functions and generators. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to: t.Optional["Environment"] = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: the class that is used for code generation. See + #: :class:`~jinja2.compiler.CodeGenerator` for more information. + code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + + concat = "".join + + #: the context class that is used for templates. See + #: :class:`~jinja2.runtime.Context` for more information. + context_class: t.Type[Context] = Context + + template_class: t.Type["Template"] + + def __init__( + self, + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + loader: t.Optional["BaseLoader"] = None, + cache_size: int = 400, + auto_reload: bool = True, + bytecode_cache: t.Optional["BytecodeCache"] = None, + enable_async: bool = False, + ): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined: t.Type[Undefined] = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + + # load extensions + self.extensions = load_extensions(self, extensions) + + self.is_async = enable_async + _environment_config_check(self) + + def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes: t.Any) -> None: + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions <writing-extensions>` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.items(): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay( + self, + block_start_string: str = missing, + block_end_string: str = missing, + variable_start_string: str = missing, + variable_end_string: str = missing, + comment_start_string: str = missing, + comment_end_string: str = missing, + line_statement_prefix: t.Optional[str] = missing, + line_comment_prefix: t.Optional[str] = missing, + trim_blocks: bool = missing, + lstrip_blocks: bool = missing, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, + keep_trailing_newline: bool = missing, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + optimized: bool = missing, + undefined: t.Type[Undefined] = missing, + finalize: t.Optional[t.Callable[..., t.Any]] = missing, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, + loader: t.Optional["BaseLoader"] = missing, + cache_size: int = missing, + auto_reload: bool = missing, + bytecode_cache: t.Optional["BytecodeCache"] = missing, + enable_async: bool = False, + ) -> "Environment": + """Create a new overlay environment that shares all the data with the + current environment except for cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + + .. versionchanged:: 3.1.2 + Added the ``newline_sequence``,, ``keep_trailing_newline``, + and ``enable_async`` parameters to match ``__init__``. + """ + args = dict(locals()) + del args["self"], args["cache_size"], args["extensions"], args["enable_async"] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in args.items(): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in self.extensions.items(): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + if enable_async is not missing: + rv.is_async = enable_async + + return _environment_config_check(rv) + + @property + def lexer(self) -> Lexer: + """The lexer for this environment.""" + return get_lexer(self) + + def iter_extensions(self) -> t.Iterator["Extension"]: + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (AttributeError, TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Any: + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a string. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def _filter_test_common( + self, + name: t.Union[str, Undefined], + value: t.Any, + args: t.Optional[t.Sequence[t.Any]], + kwargs: t.Optional[t.Mapping[str, t.Any]], + context: t.Optional[Context], + eval_ctx: t.Optional[EvalContext], + is_filter: bool, + ) -> t.Any: + if is_filter: + env_map = self.filters + type_name = "filter" + else: + env_map = self.tests + type_name = "test" + + func = env_map.get(name) # type: ignore + + if func is None: + msg = f"No {type_name} named {name!r}." + + if isinstance(name, Undefined): + try: + name._fail_with_undefined_error() + except Exception as e: + msg = f"{msg} ({e}; did you forget to quote the callable name?)" + + raise TemplateRuntimeError(msg) + + args = [value, *(args if args is not None else ())] + kwargs = kwargs if kwargs is not None else {} + pass_arg = _PassArg.from_obj(func) + + if pass_arg is _PassArg.context: + if context is None: + raise TemplateRuntimeError( + f"Attempted to invoke a context {type_name} without context." + ) + + args.insert(0, context) + elif pass_arg is _PassArg.eval_context: + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, self) + + return func(*args, **kwargs) + + def call_filter( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a filter on a value the same way the compiler does. + + This might return a coroutine if the filter is running from an + environment in async mode and the filter supports async + execution. It's your responsibility to await this if needed. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, True + ) + + def call_test( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a test on a value the same way the compiler does. + + This might return a coroutine if the test is running from an + environment in async mode and the test supports async execution. + It's your responsibility to await this if needed. + + .. versionchanged:: 3.0 + Tests support ``@pass_context``, etc. decorators. Added + the ``context`` and ``eval_ctx`` parameters. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, False + ) + + @internalcode + def parse( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> nodes.Template: + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja extensions <writing-extensions>` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def _parse( + self, source: str, name: t.Optional[str], filename: t.Optional[str] + ) -> nodes.Template: + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, filename).parse() + + def lex( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development <writing-extensions>` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = str(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def preprocess( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> str: + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce( + lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), + str(source), + ) + + def _tokenize( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) # type: ignore + + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) # type: ignore + + return stream + + def _generate( + self, + source: nodes.Template, + name: t.Optional[str], + filename: t.Optional[str], + defer_init: bool = False, + ) -> str: + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate( # type: ignore + source, + self, + name, + filename, + defer_init=defer_init, + optimized=self.optimized, + ) + + def _compile(self, source: str, filename: str) -> CodeType: + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, "exec") # type: ignore + + @typing.overload + def compile( # type: ignore + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[False]" = False, + defer_init: bool = False, + ) -> CodeType: + ... + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[True]" = ..., + defer_init: bool = False, + ) -> str: + ... + + @internalcode + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: bool = False, + defer_init: bool = False, + ) -> t.Union[str, CodeType]: + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, str): + source_hint = source + source = self._parse(source, name, filename) + source = self._generate(source, name, filename, defer_init=defer_init) + if raw: + return source + if filename is None: + filename = "<template>" + return self._compile(source, filename) + except TemplateSyntaxError: + self.handle_exception(source=source_hint) + + def compile_expression( + self, source: str, undefined_to_none: bool = True + ) -> "TemplateExpression": + """A handy helper method that returns a callable that accepts keyword + arguments that appear as variables in the expression. If called it + returns the result of the expression. + + This is useful if applications want to use the same rules as Jinja + in template "configuration files" or similar situations. + + Example usage: + + >>> env = Environment() + >>> expr = env.compile_expression('foo == 42') + >>> expr(foo=23) + False + >>> expr(foo=42) + True + + Per default the return value is converted to `None` if the + expression returns an undefined value. This can be changed + by setting `undefined_to_none` to `False`. + + >>> env.compile_expression('var')() is None + True + >>> env.compile_expression('var', undefined_to_none=False)() + Undefined + + .. versionadded:: 2.1 + """ + parser = Parser(self, source, state="variable") + try: + expr = parser.parse_expression() + if not parser.stream.eos: + raise TemplateSyntaxError( + "chunk after expression", parser.stream.current.lineno, None, None + ) + expr.set_environment(self) + except TemplateSyntaxError: + self.handle_exception(source=source) + + body = [nodes.Assign(nodes.Name("result", "store"), expr, lineno=1)] + template = self.from_string(nodes.Template(body, lineno=1)) + return TemplateExpression(template, undefined_to_none) + + def compile_templates( + self, + target: t.Union[str, os.PathLike], + extensions: t.Optional[t.Collection[str]] = None, + filter_func: t.Optional[t.Callable[[str], bool]] = None, + zip: t.Optional[str] = "deflated", + log_function: t.Optional[t.Callable[[str], None]] = None, + ignore_errors: bool = True, + ) -> None: + """Finds all the templates the loader can find, compiles them + and stores them in `target`. If `zip` is `None`, instead of in a + zipfile, the templates will be stored in a directory. + By default a deflate zip algorithm is used. To switch to + the stored algorithm, `zip` can be set to ``'stored'``. + + `extensions` and `filter_func` are passed to :meth:`list_templates`. + Each template returned will be compiled to the target folder or + zipfile. + + By default template compilation errors are ignored. In case a + log function is provided, errors are logged. If you want template + syntax errors to abort the compilation you can set `ignore_errors` + to `False` and you will get an exception on syntax errors. + + .. versionadded:: 2.4 + """ + from .loaders import ModuleLoader + + if log_function is None: + + def log_function(x: str) -> None: + pass + + assert log_function is not None + assert self.loader is not None, "No loader configured." + + def write_file(filename: str, data: str) -> None: + if zip: + info = ZipInfo(filename) + info.external_attr = 0o755 << 16 + zip_file.writestr(info, data) + else: + with open(os.path.join(target, filename), "wb") as f: + f.write(data.encode("utf8")) + + if zip is not None: + from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED + + zip_file = ZipFile( + target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip] + ) + log_function(f"Compiling into Zip archive {target!r}") + else: + if not os.path.isdir(target): + os.makedirs(target) + log_function(f"Compiling into folder {target!r}") + + try: + for name in self.list_templates(extensions, filter_func): + source, filename, _ = self.loader.get_source(self, name) + try: + code = self.compile(source, name, filename, True, True) + except TemplateSyntaxError as e: + if not ignore_errors: + raise + log_function(f'Could not compile "{name}": {e}') + continue + + filename = ModuleLoader.get_module_filename(name) + + write_file(filename, code) + log_function(f'Compiled "{name}" as {filename}') + finally: + if zip: + zip_file.close() + + log_function("Finished compiling templates") + + def list_templates( + self, + extensions: t.Optional[t.Collection[str]] = None, + filter_func: t.Optional[t.Callable[[str], bool]] = None, + ) -> t.List[str]: + """Returns a list of templates for this environment. This requires + that the loader supports the loader's + :meth:`~BaseLoader.list_templates` method. + + If there are other files in the template folder besides the + actual templates, the returned list can be filtered. There are two + ways: either `extensions` is set to a list of file extensions for + templates, or a `filter_func` can be provided which is a callable that + is passed a template name and should return `True` if it should end up + in the result list. + + If the loader does not support that, a :exc:`TypeError` is raised. + + .. versionadded:: 2.4 + """ + assert self.loader is not None, "No loader configured." + names = self.loader.list_templates() + + if extensions is not None: + if filter_func is not None: + raise TypeError( + "either extensions or filter_func can be passed, but not both" + ) + + def filter_func(x: str) -> bool: + return "." in x and x.rsplit(".", 1)[1] in extensions # type: ignore + + if filter_func is not None: + names = [name for name in names if filter_func(name)] + + return names + + def handle_exception(self, source: t.Optional[str] = None) -> "te.NoReturn": + """Exception handling helper. This is used internally to either raise + rewritten exceptions or return a rendered traceback for the template. + """ + from .debug import rewrite_traceback_stack + + raise rewrite_traceback_stack(source=source) + + def join_path(self, template: str, parent: str) -> str: + """Join a template with the parent. By default all the lookups are + relative to the loader root so this method returns the `template` + parameter unchanged, but if the paths should be relative to the + parent template, this function can be used to calculate the real + template name. + + Subclasses may override this method and implement template path + joining here. + """ + return template + + @internalcode + def _load_template( + self, name: str, globals: t.Optional[t.MutableMapping[str, t.Any]] + ) -> "Template": + if self.loader is None: + raise TypeError("no loader for this environment specified") + cache_key = (weakref.ref(self.loader), name) + if self.cache is not None: + template = self.cache.get(cache_key) + if template is not None and ( + not self.auto_reload or template.is_up_to_date + ): + # template.globals is a ChainMap, modifying it will only + # affect the template, not the environment globals. + if globals: + template.globals.update(globals) + + return template + + template = self.loader.load(self, name, self.make_globals(globals)) + + if self.cache is not None: + self.cache[cache_key] = template + return template + + @internalcode + def get_template( + self, + name: t.Union[str, "Template"], + parent: t.Optional[str] = None, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + """Load a template by name with :attr:`loader` and return a + :class:`Template`. If the template does not exist a + :exc:`TemplateNotFound` exception is raised. + + :param name: Name of the template to load. When loading + templates from the filesystem, "/" is used as the path + separator, even on Windows. + :param parent: The name of the parent template importing this + template. :meth:`join_path` can be used to implement name + transformations with this. + :param globals: Extend the environment :attr:`globals` with + these extra variables available for all renders of this + template. If the template has already been loaded and + cached, its globals are updated with any new items. + + .. versionchanged:: 3.0 + If a template is loaded from cache, ``globals`` will update + the template's globals instead of ignoring the new values. + + .. versionchanged:: 2.4 + If ``name`` is a :class:`Template` object it is returned + unchanged. + """ + if isinstance(name, Template): + return name + if parent is not None: + name = self.join_path(name, parent) + + return self._load_template(name, globals) + + @internalcode + def select_template( + self, + names: t.Iterable[t.Union[str, "Template"]], + parent: t.Optional[str] = None, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + """Like :meth:`get_template`, but tries loading multiple names. + If none of the names can be loaded a :exc:`TemplatesNotFound` + exception is raised. + + :param names: List of template names to try loading in order. + :param parent: The name of the parent template importing this + template. :meth:`join_path` can be used to implement name + transformations with this. + :param globals: Extend the environment :attr:`globals` with + these extra variables available for all renders of this + template. If the template has already been loaded and + cached, its globals are updated with any new items. + + .. versionchanged:: 3.0 + If a template is loaded from cache, ``globals`` will update + the template's globals instead of ignoring the new values. + + .. versionchanged:: 2.11 + If ``names`` is :class:`Undefined`, an :exc:`UndefinedError` + is raised instead. If no templates were found and ``names`` + contains :class:`Undefined`, the message is more helpful. + + .. versionchanged:: 2.4 + If ``names`` contains a :class:`Template` object it is + returned unchanged. + + .. versionadded:: 2.3 + """ + if isinstance(names, Undefined): + names._fail_with_undefined_error() + + if not names: + raise TemplatesNotFound( + message="Tried to select from an empty list of templates." + ) + + for name in names: + if isinstance(name, Template): + return name + if parent is not None: + name = self.join_path(name, parent) + try: + return self._load_template(name, globals) + except (TemplateNotFound, UndefinedError): + pass + raise TemplatesNotFound(names) # type: ignore + + @internalcode + def get_or_select_template( + self, + template_name_or_list: t.Union[ + str, "Template", t.List[t.Union[str, "Template"]] + ], + parent: t.Optional[str] = None, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + """Use :meth:`select_template` if an iterable of template names + is given, or :meth:`get_template` if one name is given. + + .. versionadded:: 2.3 + """ + if isinstance(template_name_or_list, (str, Undefined)): + return self.get_template(template_name_or_list, parent, globals) + elif isinstance(template_name_or_list, Template): + return template_name_or_list + return self.select_template(template_name_or_list, parent, globals) + + def from_string( + self, + source: t.Union[str, nodes.Template], + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + template_class: t.Optional[t.Type["Template"]] = None, + ) -> "Template": + """Load a template from a source string without using + :attr:`loader`. + + :param source: Jinja source to compile into a template. + :param globals: Extend the environment :attr:`globals` with + these extra variables available for all renders of this + template. If the template has already been loaded and + cached, its globals are updated with any new items. + :param template_class: Return an instance of this + :class:`Template` class. + """ + gs = self.make_globals(globals) + cls = template_class or self.template_class + return cls.from_code(self, self.compile(source), gs, None) + + def make_globals( + self, d: t.Optional[t.MutableMapping[str, t.Any]] + ) -> t.MutableMapping[str, t.Any]: + """Make the globals map for a template. Any given template + globals overlay the environment :attr:`globals`. + + Returns a :class:`collections.ChainMap`. This allows any changes + to a template's globals to only affect that template, while + changes to the environment's globals are still reflected. + However, avoid modifying any globals after a template is loaded. + + :param d: Dict of template-specific globals. + + .. versionchanged:: 3.0 + Use :class:`collections.ChainMap` to always prevent mutating + environment globals. + """ + if d is None: + d = {} + + return ChainMap(d, self.globals) + + +class Template: + """A compiled template that can be rendered. + + Use the methods on :class:`Environment` to create or load templates. + The environment is used to configure how templates are compiled and + behave. + + It is also possible to create a template object directly. This is + not usually recommended. The constructor takes most of the same + arguments as :class:`Environment`. All templates created with the + same environment arguments share the same ephemeral ``Environment`` + instance behind the scenes. + + A template object should be considered immutable. Modifications on + the object are not supported. + """ + + #: Type of environment to create when creating a template directly + #: rather than through an existing environment. + environment_class: t.Type[Environment] = Environment + + environment: Environment + globals: t.MutableMapping[str, t.Any] + name: t.Optional[str] + filename: t.Optional[str] + blocks: t.Dict[str, t.Callable[[Context], t.Iterator[str]]] + root_render_func: t.Callable[[Context], t.Iterator[str]] + _module: t.Optional["TemplateModule"] + _debug_info: str + _uptodate: t.Optional[t.Callable[[], bool]] + + def __new__( + cls, + source: t.Union[str, nodes.Template], + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + enable_async: bool = False, + ) -> t.Any: # it returns a `Template`, but this breaks the sphinx build... + env = get_spontaneous_environment( + cls.environment_class, # type: ignore + block_start_string, + block_end_string, + variable_start_string, + variable_end_string, + comment_start_string, + comment_end_string, + line_statement_prefix, + line_comment_prefix, + trim_blocks, + lstrip_blocks, + newline_sequence, + keep_trailing_newline, + frozenset(extensions), + optimized, + undefined, # type: ignore + finalize, + autoescape, + None, + 0, + False, + None, + enable_async, + ) + return env.from_string(source, template_class=cls) + + @classmethod + def from_code( + cls, + environment: Environment, + code: CodeType, + globals: t.MutableMapping[str, t.Any], + uptodate: t.Optional[t.Callable[[], bool]] = None, + ) -> "Template": + """Creates a template object from compiled code and the globals. This + is used by the loaders and environment to create a template object. + """ + namespace = {"environment": environment, "__file__": code.co_filename} + exec(code, namespace) + rv = cls._from_namespace(environment, namespace, globals) + rv._uptodate = uptodate + return rv + + @classmethod + def from_module_dict( + cls, + environment: Environment, + module_dict: t.MutableMapping[str, t.Any], + globals: t.MutableMapping[str, t.Any], + ) -> "Template": + """Creates a template object from a module. This is used by the + module loader to create a template object. + + .. versionadded:: 2.4 + """ + return cls._from_namespace(environment, module_dict, globals) + + @classmethod + def _from_namespace( + cls, + environment: Environment, + namespace: t.MutableMapping[str, t.Any], + globals: t.MutableMapping[str, t.Any], + ) -> "Template": + t: "Template" = object.__new__(cls) + t.environment = environment + t.globals = globals + t.name = namespace["name"] + t.filename = namespace["__file__"] + t.blocks = namespace["blocks"] + + # render function and module + t.root_render_func = namespace["root"] # type: ignore + t._module = None + + # debug and loader helpers + t._debug_info = namespace["debug_info"] + t._uptodate = None + + # store the reference + namespace["environment"] = environment + namespace["__jinja_template__"] = t + + return t + + def render(self, *args: t.Any, **kwargs: t.Any) -> str: + """This method accepts the same arguments as the `dict` constructor: + A dict, a dict subclass or some keyword arguments. If no arguments + are given the context will be empty. These two calls do the same:: + + template.render(knights='that say nih') + template.render({'knights': 'that say nih'}) + + This will return the rendered template as a string. + """ + if self.environment.is_async: + import asyncio + + close = False + + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + close = True + + try: + return loop.run_until_complete(self.render_async(*args, **kwargs)) + finally: + if close: + loop.close() + + ctx = self.new_context(dict(*args, **kwargs)) + + try: + return self.environment.concat(self.root_render_func(ctx)) # type: ignore + except Exception: + self.environment.handle_exception() + + async def render_async(self, *args: t.Any, **kwargs: t.Any) -> str: + """This works similar to :meth:`render` but returns a coroutine + that when awaited returns the entire rendered template string. This + requires the async feature to be enabled. + + Example usage:: + + await template.render_async(knights='that say nih; asynchronously') + """ + if not self.environment.is_async: + raise RuntimeError( + "The environment was not created with async mode enabled." + ) + + ctx = self.new_context(dict(*args, **kwargs)) + + try: + return self.environment.concat( # type: ignore + [n async for n in self.root_render_func(ctx)] # type: ignore + ) + except Exception: + return self.environment.handle_exception() + + def stream(self, *args: t.Any, **kwargs: t.Any) -> "TemplateStream": + """Works exactly like :meth:`generate` but returns a + :class:`TemplateStream`. + """ + return TemplateStream(self.generate(*args, **kwargs)) + + def generate(self, *args: t.Any, **kwargs: t.Any) -> t.Iterator[str]: + """For very large templates it can be useful to not render the whole + template at once but evaluate each statement after another and yield + piece for piece. This method basically does exactly that and returns + a generator that yields one item after another as strings. + + It accepts the same arguments as :meth:`render`. + """ + if self.environment.is_async: + import asyncio + + async def to_list() -> t.List[str]: + return [x async for x in self.generate_async(*args, **kwargs)] + + yield from asyncio.run(to_list()) + return + + ctx = self.new_context(dict(*args, **kwargs)) + + try: + yield from self.root_render_func(ctx) # type: ignore + except Exception: + yield self.environment.handle_exception() + + async def generate_async( + self, *args: t.Any, **kwargs: t.Any + ) -> t.AsyncIterator[str]: + """An async version of :meth:`generate`. Works very similarly but + returns an async iterator instead. + """ + if not self.environment.is_async: + raise RuntimeError( + "The environment was not created with async mode enabled." + ) + + ctx = self.new_context(dict(*args, **kwargs)) + + try: + async for event in self.root_render_func(ctx): # type: ignore + yield event + except Exception: + yield self.environment.handle_exception() + + def new_context( + self, + vars: t.Optional[t.Dict[str, t.Any]] = None, + shared: bool = False, + locals: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> Context: + """Create a new :class:`Context` for this template. The vars + provided will be passed to the template. Per default the globals + are added to the context. If shared is set to `True` the data + is passed as is to the context without adding the globals. + + `locals` can be a dict of local variables for internal usage. + """ + return new_context( + self.environment, self.name, self.blocks, vars, shared, self.globals, locals + ) + + def make_module( + self, + vars: t.Optional[t.Dict[str, t.Any]] = None, + shared: bool = False, + locals: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> "TemplateModule": + """This method works like the :attr:`module` attribute when called + without arguments but it will evaluate the template on every call + rather than caching it. It's also possible to provide + a dict which is then used as context. The arguments are the same + as for the :meth:`new_context` method. + """ + ctx = self.new_context(vars, shared, locals) + return TemplateModule(self, ctx) + + async def make_module_async( + self, + vars: t.Optional[t.Dict[str, t.Any]] = None, + shared: bool = False, + locals: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> "TemplateModule": + """As template module creation can invoke template code for + asynchronous executions this method must be used instead of the + normal :meth:`make_module` one. Likewise the module attribute + becomes unavailable in async mode. + """ + ctx = self.new_context(vars, shared, locals) + return TemplateModule( + self, ctx, [x async for x in self.root_render_func(ctx)] # type: ignore + ) + + @internalcode + def _get_default_module(self, ctx: t.Optional[Context] = None) -> "TemplateModule": + """If a context is passed in, this means that the template was + imported. Imported templates have access to the current + template's globals by default, but they can only be accessed via + the context during runtime. + + If there are new globals, we need to create a new module because + the cached module is already rendered and will not have access + to globals from the current context. This new module is not + cached because the template can be imported elsewhere, and it + should have access to only the current template's globals. + """ + if self.environment.is_async: + raise RuntimeError("Module is not available in async mode.") + + if ctx is not None: + keys = ctx.globals_keys - self.globals.keys() + + if keys: + return self.make_module({k: ctx.parent[k] for k in keys}) + + if self._module is None: + self._module = self.make_module() + + return self._module + + async def _get_default_module_async( + self, ctx: t.Optional[Context] = None + ) -> "TemplateModule": + if ctx is not None: + keys = ctx.globals_keys - self.globals.keys() + + if keys: + return await self.make_module_async({k: ctx.parent[k] for k in keys}) + + if self._module is None: + self._module = await self.make_module_async() + + return self._module + + @property + def module(self) -> "TemplateModule": + """The template as module. This is used for imports in the + template runtime but is also useful if one wants to access + exported template variables from the Python layer: + + >>> t = Template('{% macro foo() %}42{% endmacro %}23') + >>> str(t.module) + '23' + >>> t.module.foo() == u'42' + True + + This attribute is not available if async mode is enabled. + """ + return self._get_default_module() + + def get_corresponding_lineno(self, lineno: int) -> int: + """Return the source line number of a line number in the + generated bytecode as they are not in sync. + """ + for template_line, code_line in reversed(self.debug_info): + if code_line <= lineno: + return template_line + return 1 + + @property + def is_up_to_date(self) -> bool: + """If this variable is `False` there is a newer version available.""" + if self._uptodate is None: + return True + return self._uptodate() + + @property + def debug_info(self) -> t.List[t.Tuple[int, int]]: + """The debug info mapping.""" + if self._debug_info: + return [ + tuple(map(int, x.split("="))) # type: ignore + for x in self._debug_info.split("&") + ] + + return [] + + def __repr__(self) -> str: + if self.name is None: + name = f"memory:{id(self):x}" + else: + name = repr(self.name) + return f"<{type(self).__name__} {name}>" + + +class TemplateModule: + """Represents an imported template. All the exported names of the + template are available as attributes on this object. Additionally + converting it into a string renders the contents. + """ + + def __init__( + self, + template: Template, + context: Context, + body_stream: t.Optional[t.Iterable[str]] = None, + ) -> None: + if body_stream is None: + if context.environment.is_async: + raise RuntimeError( + "Async mode requires a body stream to be passed to" + " a template module. Use the async methods of the" + " API you are using." + ) + + body_stream = list(template.root_render_func(context)) # type: ignore + + self._body_stream = body_stream + self.__dict__.update(context.get_exported()) + self.__name__ = template.name + + def __html__(self) -> Markup: + return Markup(concat(self._body_stream)) + + def __str__(self) -> str: + return concat(self._body_stream) + + def __repr__(self) -> str: + if self.__name__ is None: + name = f"memory:{id(self):x}" + else: + name = repr(self.__name__) + return f"<{type(self).__name__} {name}>" + + +class TemplateExpression: + """The :meth:`jinja2.Environment.compile_expression` method returns an + instance of this object. It encapsulates the expression-like access + to the template with an expression it wraps. + """ + + def __init__(self, template: Template, undefined_to_none: bool) -> None: + self._template = template + self._undefined_to_none = undefined_to_none + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Optional[t.Any]: + context = self._template.new_context(dict(*args, **kwargs)) + consume(self._template.root_render_func(context)) # type: ignore + rv = context.vars["result"] + if self._undefined_to_none and isinstance(rv, Undefined): + rv = None + return rv + + +class TemplateStream: + """A template stream works pretty much like an ordinary python generator + but it can buffer multiple items to reduce the number of total iterations. + Per default the output is unbuffered which means that for every unbuffered + instruction in the template one string is yielded. + + If buffering is enabled with a buffer size of 5, five items are combined + into a new string. This is mainly useful if you are streaming + big templates to a client via WSGI which flushes after each iteration. + """ + + def __init__(self, gen: t.Iterator[str]) -> None: + self._gen = gen + self.disable_buffering() + + def dump( + self, + fp: t.Union[str, t.IO], + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + ) -> None: + """Dump the complete stream into a file or file-like object. + Per default strings are written, if you want to encode + before writing specify an `encoding`. + + Example usage:: + + Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') + """ + close = False + + if isinstance(fp, str): + if encoding is None: + encoding = "utf-8" + + fp = open(fp, "wb") + close = True + try: + if encoding is not None: + iterable = (x.encode(encoding, errors) for x in self) # type: ignore + else: + iterable = self # type: ignore + + if hasattr(fp, "writelines"): + fp.writelines(iterable) + else: + for item in iterable: + fp.write(item) + finally: + if close: + fp.close() + + def disable_buffering(self) -> None: + """Disable the output buffering.""" + self._next = partial(next, self._gen) + self.buffered = False + + def _buffered_generator(self, size: int) -> t.Iterator[str]: + buf: t.List[str] = [] + c_size = 0 + push = buf.append + + while True: + try: + while c_size < size: + c = next(self._gen) + push(c) + if c: + c_size += 1 + except StopIteration: + if not c_size: + return + yield concat(buf) + del buf[:] + c_size = 0 + + def enable_buffering(self, size: int = 5) -> None: + """Enable buffering. Buffer `size` items before yielding them.""" + if size <= 1: + raise ValueError("buffer size too small") + + self.buffered = True + self._next = partial(next, self._buffered_generator(size)) + + def __iter__(self) -> "TemplateStream": + return self + + def __next__(self) -> str: + return self._next() # type: ignore + + +# hook in default template class. if anyone reads this comment: ignore that +# it's possible to use custom templates ;-) +Environment.template_class = Template diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..082ebe8f221d4e7e980e4d321c0a0c5da033b124 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/exceptions.py @@ -0,0 +1,166 @@ +import typing as t + +if t.TYPE_CHECKING: + from .runtime import Undefined + + +class TemplateError(Exception): + """Baseclass for all template errors.""" + + def __init__(self, message: t.Optional[str] = None) -> None: + super().__init__(message) + + @property + def message(self) -> t.Optional[str]: + return self.args[0] if self.args else None + + +class TemplateNotFound(IOError, LookupError, TemplateError): + """Raised if a template does not exist. + + .. versionchanged:: 2.11 + If the given name is :class:`Undefined` and no message was + provided, an :exc:`UndefinedError` is raised. + """ + + # Silence the Python warning about message being deprecated since + # it's not valid here. + message: t.Optional[str] = None + + def __init__( + self, + name: t.Optional[t.Union[str, "Undefined"]], + message: t.Optional[str] = None, + ) -> None: + IOError.__init__(self, name) + + if message is None: + from .runtime import Undefined + + if isinstance(name, Undefined): + name._fail_with_undefined_error() + + message = name + + self.message = message + self.name = name + self.templates = [name] + + def __str__(self) -> str: + return str(self.message) + + +class TemplatesNotFound(TemplateNotFound): + """Like :class:`TemplateNotFound` but raised if multiple templates + are selected. This is a subclass of :class:`TemplateNotFound` + exception, so just catching the base exception will catch both. + + .. versionchanged:: 2.11 + If a name in the list of names is :class:`Undefined`, a message + about it being undefined is shown rather than the empty string. + + .. versionadded:: 2.2 + """ + + def __init__( + self, + names: t.Sequence[t.Union[str, "Undefined"]] = (), + message: t.Optional[str] = None, + ) -> None: + if message is None: + from .runtime import Undefined + + parts = [] + + for name in names: + if isinstance(name, Undefined): + parts.append(name._undefined_message) + else: + parts.append(name) + + parts_str = ", ".join(map(str, parts)) + message = f"none of the templates given were found: {parts_str}" + + super().__init__(names[-1] if names else None, message) + self.templates = list(names) + + +class TemplateSyntaxError(TemplateError): + """Raised to tell the user that there is a problem with the template.""" + + def __init__( + self, + message: str, + lineno: int, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> None: + super().__init__(message) + self.lineno = lineno + self.name = name + self.filename = filename + self.source: t.Optional[str] = None + + # this is set to True if the debug.translate_syntax_error + # function translated the syntax error into a new traceback + self.translated = False + + def __str__(self) -> str: + # for translated errors we only return the message + if self.translated: + return t.cast(str, self.message) + + # otherwise attach some stuff + location = f"line {self.lineno}" + name = self.filename or self.name + if name: + location = f'File "{name}", {location}' + lines = [t.cast(str, self.message), " " + location] + + # if the source is set, add the line to the output + if self.source is not None: + try: + line = self.source.splitlines()[self.lineno - 1] + except IndexError: + pass + else: + lines.append(" " + line.strip()) + + return "\n".join(lines) + + def __reduce__(self): # type: ignore + # https://bugs.python.org/issue1692335 Exceptions that take + # multiple required arguments have problems with pickling. + # Without this, raises TypeError: __init__() missing 1 required + # positional argument: 'lineno' + return self.__class__, (self.message, self.lineno, self.name, self.filename) + + +class TemplateAssertionError(TemplateSyntaxError): + """Like a template syntax error, but covers cases where something in the + template caused an error at compile time that wasn't necessarily caused + by a syntax error. However it's a direct subclass of + :exc:`TemplateSyntaxError` and has the same attributes. + """ + + +class TemplateRuntimeError(TemplateError): + """A generic runtime error in the template engine. Under some situations + Jinja may raise this exception. + """ + + +class UndefinedError(TemplateRuntimeError): + """Raised if a template tries to operate on :class:`Undefined`.""" + + +class SecurityError(TemplateRuntimeError): + """Raised if a template tries to do something insecure if the + sandbox is enabled. + """ + + +class FilterArgumentError(TemplateRuntimeError): + """This error is raised if a filter was called with inappropriate + arguments + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/ext.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/ext.py new file mode 100644 index 0000000000000000000000000000000000000000..d5550540cda01ea9da32747754d34603a7bbac0a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/ext.py @@ -0,0 +1,859 @@ +"""Extension API for adding custom tags and behavior.""" +import pprint +import re +import typing as t + +from markupsafe import Markup + +from . import defaults +from . import nodes +from .environment import Environment +from .exceptions import TemplateAssertionError +from .exceptions import TemplateSyntaxError +from .runtime import concat # type: ignore +from .runtime import Context +from .runtime import Undefined +from .utils import import_string +from .utils import pass_context + +if t.TYPE_CHECKING: + import typing_extensions as te + from .lexer import Token + from .lexer import TokenStream + from .parser import Parser + + class _TranslationsBasic(te.Protocol): + def gettext(self, message: str) -> str: + ... + + def ngettext(self, singular: str, plural: str, n: int) -> str: + pass + + class _TranslationsContext(_TranslationsBasic): + def pgettext(self, context: str, message: str) -> str: + ... + + def npgettext(self, context: str, singular: str, plural: str, n: int) -> str: + ... + + _SupportedTranslations = t.Union[_TranslationsBasic, _TranslationsContext] + + +# I18N functions available in Jinja templates. If the I18N library +# provides ugettext, it will be assigned to gettext. +GETTEXT_FUNCTIONS: t.Tuple[str, ...] = ( + "_", + "gettext", + "ngettext", + "pgettext", + "npgettext", +) +_ws_re = re.compile(r"\s*\n\s*") + + +class Extension: + """Extensions can be used to add extra functionality to the Jinja template + system at the parser level. Custom extensions are bound to an environment + but may not store environment specific data on `self`. The reason for + this is that an extension can be bound to another environment (for + overlays) by creating a copy and reassigning the `environment` attribute. + + As extensions are created by the environment they cannot accept any + arguments for configuration. One may want to work around that by using + a factory function, but that is not possible as extensions are identified + by their import name. The correct way to configure the extension is + storing the configuration values on the environment. Because this way the + environment ends up acting as central configuration storage the + attributes may clash which is why extensions have to ensure that the names + they choose for configuration are not too generic. ``prefix`` for example + is a terrible name, ``fragment_cache_prefix`` on the other hand is a good + name as includes the name of the extension (fragment cache). + """ + + identifier: t.ClassVar[str] + + def __init_subclass__(cls) -> None: + cls.identifier = f"{cls.__module__}.{cls.__name__}" + + #: if this extension parses this is the list of tags it's listening to. + tags: t.Set[str] = set() + + #: the priority of that extension. This is especially useful for + #: extensions that preprocess values. A lower value means higher + #: priority. + #: + #: .. versionadded:: 2.4 + priority = 100 + + def __init__(self, environment: Environment) -> None: + self.environment = environment + + def bind(self, environment: Environment) -> "Extension": + """Create a copy of this extension bound to another environment.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.environment = environment + return rv + + def preprocess( + self, source: str, name: t.Optional[str], filename: t.Optional[str] = None + ) -> str: + """This method is called before the actual lexing and can be used to + preprocess the source. The `filename` is optional. The return value + must be the preprocessed source. + """ + return source + + def filter_stream( + self, stream: "TokenStream" + ) -> t.Union["TokenStream", t.Iterable["Token"]]: + """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used + to filter tokens returned. This method has to return an iterable of + :class:`~jinja2.lexer.Token`\\s, but it doesn't have to return a + :class:`~jinja2.lexer.TokenStream`. + """ + return stream + + def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]: + """If any of the :attr:`tags` matched this method is called with the + parser as first argument. The token the parser stream is pointing at + is the name token that matched. This method has to return one or a + list of multiple nodes. + """ + raise NotImplementedError() + + def attr( + self, name: str, lineno: t.Optional[int] = None + ) -> nodes.ExtensionAttribute: + """Return an attribute node for the current extension. This is useful + to pass constants on extensions to generated template code. + + :: + + self.attr('_my_attribute', lineno=lineno) + """ + return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno) + + def call_method( + self, + name: str, + args: t.Optional[t.List[nodes.Expr]] = None, + kwargs: t.Optional[t.List[nodes.Keyword]] = None, + dyn_args: t.Optional[nodes.Expr] = None, + dyn_kwargs: t.Optional[nodes.Expr] = None, + lineno: t.Optional[int] = None, + ) -> nodes.Call: + """Call a method of the extension. This is a shortcut for + :meth:`attr` + :class:`jinja2.nodes.Call`. + """ + if args is None: + args = [] + if kwargs is None: + kwargs = [] + return nodes.Call( + self.attr(name, lineno=lineno), + args, + kwargs, + dyn_args, + dyn_kwargs, + lineno=lineno, + ) + + +@pass_context +def _gettext_alias( + __context: Context, *args: t.Any, **kwargs: t.Any +) -> t.Union[t.Any, Undefined]: + return __context.call(__context.resolve("gettext"), *args, **kwargs) + + +def _make_new_gettext(func: t.Callable[[str], str]) -> t.Callable[..., str]: + @pass_context + def gettext(__context: Context, __string: str, **variables: t.Any) -> str: + rv = __context.call(func, __string) + if __context.eval_ctx.autoescape: + rv = Markup(rv) + # Always treat as a format string, even if there are no + # variables. This makes translation strings more consistent + # and predictable. This requires escaping + return rv % variables # type: ignore + + return gettext + + +def _make_new_ngettext(func: t.Callable[[str, str, int], str]) -> t.Callable[..., str]: + @pass_context + def ngettext( + __context: Context, + __singular: str, + __plural: str, + __num: int, + **variables: t.Any, + ) -> str: + variables.setdefault("num", __num) + rv = __context.call(func, __singular, __plural, __num) + if __context.eval_ctx.autoescape: + rv = Markup(rv) + # Always treat as a format string, see gettext comment above. + return rv % variables # type: ignore + + return ngettext + + +def _make_new_pgettext(func: t.Callable[[str, str], str]) -> t.Callable[..., str]: + @pass_context + def pgettext( + __context: Context, __string_ctx: str, __string: str, **variables: t.Any + ) -> str: + variables.setdefault("context", __string_ctx) + rv = __context.call(func, __string_ctx, __string) + + if __context.eval_ctx.autoescape: + rv = Markup(rv) + + # Always treat as a format string, see gettext comment above. + return rv % variables # type: ignore + + return pgettext + + +def _make_new_npgettext( + func: t.Callable[[str, str, str, int], str] +) -> t.Callable[..., str]: + @pass_context + def npgettext( + __context: Context, + __string_ctx: str, + __singular: str, + __plural: str, + __num: int, + **variables: t.Any, + ) -> str: + variables.setdefault("context", __string_ctx) + variables.setdefault("num", __num) + rv = __context.call(func, __string_ctx, __singular, __plural, __num) + + if __context.eval_ctx.autoescape: + rv = Markup(rv) + + # Always treat as a format string, see gettext comment above. + return rv % variables # type: ignore + + return npgettext + + +class InternationalizationExtension(Extension): + """This extension adds gettext support to Jinja.""" + + tags = {"trans"} + + # TODO: the i18n extension is currently reevaluating values in a few + # situations. Take this example: + # {% trans count=something() %}{{ count }} foo{% pluralize + # %}{{ count }} fooss{% endtrans %} + # something is called twice here. One time for the gettext value and + # the other time for the n-parameter of the ngettext function. + + def __init__(self, environment: Environment) -> None: + super().__init__(environment) + environment.globals["_"] = _gettext_alias + environment.extend( + install_gettext_translations=self._install, + install_null_translations=self._install_null, + install_gettext_callables=self._install_callables, + uninstall_gettext_translations=self._uninstall, + extract_translations=self._extract, + newstyle_gettext=False, + ) + + def _install( + self, translations: "_SupportedTranslations", newstyle: t.Optional[bool] = None + ) -> None: + # ugettext and ungettext are preferred in case the I18N library + # is providing compatibility with older Python versions. + gettext = getattr(translations, "ugettext", None) + if gettext is None: + gettext = translations.gettext + ngettext = getattr(translations, "ungettext", None) + if ngettext is None: + ngettext = translations.ngettext + + pgettext = getattr(translations, "pgettext", None) + npgettext = getattr(translations, "npgettext", None) + self._install_callables( + gettext, ngettext, newstyle=newstyle, pgettext=pgettext, npgettext=npgettext + ) + + def _install_null(self, newstyle: t.Optional[bool] = None) -> None: + import gettext + + translations = gettext.NullTranslations() + + if hasattr(translations, "pgettext"): + # Python < 3.8 + pgettext = translations.pgettext # type: ignore + else: + + def pgettext(c: str, s: str) -> str: + return s + + if hasattr(translations, "npgettext"): + npgettext = translations.npgettext # type: ignore + else: + + def npgettext(c: str, s: str, p: str, n: int) -> str: + return s if n == 1 else p + + self._install_callables( + gettext=translations.gettext, + ngettext=translations.ngettext, + newstyle=newstyle, + pgettext=pgettext, + npgettext=npgettext, + ) + + def _install_callables( + self, + gettext: t.Callable[[str], str], + ngettext: t.Callable[[str, str, int], str], + newstyle: t.Optional[bool] = None, + pgettext: t.Optional[t.Callable[[str, str], str]] = None, + npgettext: t.Optional[t.Callable[[str, str, str, int], str]] = None, + ) -> None: + if newstyle is not None: + self.environment.newstyle_gettext = newstyle # type: ignore + if self.environment.newstyle_gettext: # type: ignore + gettext = _make_new_gettext(gettext) + ngettext = _make_new_ngettext(ngettext) + + if pgettext is not None: + pgettext = _make_new_pgettext(pgettext) + + if npgettext is not None: + npgettext = _make_new_npgettext(npgettext) + + self.environment.globals.update( + gettext=gettext, ngettext=ngettext, pgettext=pgettext, npgettext=npgettext + ) + + def _uninstall(self, translations: "_SupportedTranslations") -> None: + for key in ("gettext", "ngettext", "pgettext", "npgettext"): + self.environment.globals.pop(key, None) + + def _extract( + self, + source: t.Union[str, nodes.Template], + gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, + ) -> t.Iterator[ + t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]] + ]: + if isinstance(source, str): + source = self.environment.parse(source) + return extract_from_ast(source, gettext_functions) + + def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]: + """Parse a translatable tag.""" + lineno = next(parser.stream).lineno + + context = None + context_token = parser.stream.next_if("string") + + if context_token is not None: + context = context_token.value + + # find all the variables referenced. Additionally a variable can be + # defined in the body of the trans block too, but this is checked at + # a later state. + plural_expr: t.Optional[nodes.Expr] = None + plural_expr_assignment: t.Optional[nodes.Assign] = None + num_called_num = False + variables: t.Dict[str, nodes.Expr] = {} + trimmed = None + while parser.stream.current.type != "block_end": + if variables: + parser.stream.expect("comma") + + # skip colon for python compatibility + if parser.stream.skip_if("colon"): + break + + token = parser.stream.expect("name") + if token.value in variables: + parser.fail( + f"translatable variable {token.value!r} defined twice.", + token.lineno, + exc=TemplateAssertionError, + ) + + # expressions + if parser.stream.current.type == "assign": + next(parser.stream) + variables[token.value] = var = parser.parse_expression() + elif trimmed is None and token.value in ("trimmed", "notrimmed"): + trimmed = token.value == "trimmed" + continue + else: + variables[token.value] = var = nodes.Name(token.value, "load") + + if plural_expr is None: + if isinstance(var, nodes.Call): + plural_expr = nodes.Name("_trans", "load") + variables[token.value] = plural_expr + plural_expr_assignment = nodes.Assign( + nodes.Name("_trans", "store"), var + ) + else: + plural_expr = var + num_called_num = token.value == "num" + + parser.stream.expect("block_end") + + plural = None + have_plural = False + referenced = set() + + # now parse until endtrans or pluralize + singular_names, singular = self._parse_block(parser, True) + if singular_names: + referenced.update(singular_names) + if plural_expr is None: + plural_expr = nodes.Name(singular_names[0], "load") + num_called_num = singular_names[0] == "num" + + # if we have a pluralize block, we parse that too + if parser.stream.current.test("name:pluralize"): + have_plural = True + next(parser.stream) + if parser.stream.current.type != "block_end": + token = parser.stream.expect("name") + if token.value not in variables: + parser.fail( + f"unknown variable {token.value!r} for pluralization", + token.lineno, + exc=TemplateAssertionError, + ) + plural_expr = variables[token.value] + num_called_num = token.value == "num" + parser.stream.expect("block_end") + plural_names, plural = self._parse_block(parser, False) + next(parser.stream) + referenced.update(plural_names) + else: + next(parser.stream) + + # register free names as simple name expressions + for name in referenced: + if name not in variables: + variables[name] = nodes.Name(name, "load") + + if not have_plural: + plural_expr = None + elif plural_expr is None: + parser.fail("pluralize without variables", lineno) + + if trimmed is None: + trimmed = self.environment.policies["ext.i18n.trimmed"] + if trimmed: + singular = self._trim_whitespace(singular) + if plural: + plural = self._trim_whitespace(plural) + + node = self._make_node( + singular, + plural, + context, + variables, + plural_expr, + bool(referenced), + num_called_num and have_plural, + ) + node.set_lineno(lineno) + if plural_expr_assignment is not None: + return [plural_expr_assignment, node] + else: + return node + + def _trim_whitespace(self, string: str, _ws_re: t.Pattern[str] = _ws_re) -> str: + return _ws_re.sub(" ", string.strip()) + + def _parse_block( + self, parser: "Parser", allow_pluralize: bool + ) -> t.Tuple[t.List[str], str]: + """Parse until the next block tag with a given name.""" + referenced = [] + buf = [] + + while True: + if parser.stream.current.type == "data": + buf.append(parser.stream.current.value.replace("%", "%%")) + next(parser.stream) + elif parser.stream.current.type == "variable_begin": + next(parser.stream) + name = parser.stream.expect("name").value + referenced.append(name) + buf.append(f"%({name})s") + parser.stream.expect("variable_end") + elif parser.stream.current.type == "block_begin": + next(parser.stream) + if parser.stream.current.test("name:endtrans"): + break + elif parser.stream.current.test("name:pluralize"): + if allow_pluralize: + break + parser.fail( + "a translatable section can have only one pluralize section" + ) + parser.fail( + "control structures in translatable sections are not allowed" + ) + elif parser.stream.eos: + parser.fail("unclosed translation block") + else: + raise RuntimeError("internal parser error") + + return referenced, concat(buf) + + def _make_node( + self, + singular: str, + plural: t.Optional[str], + context: t.Optional[str], + variables: t.Dict[str, nodes.Expr], + plural_expr: t.Optional[nodes.Expr], + vars_referenced: bool, + num_called_num: bool, + ) -> nodes.Output: + """Generates a useful node from the data provided.""" + newstyle = self.environment.newstyle_gettext # type: ignore + node: nodes.Expr + + # no variables referenced? no need to escape for old style + # gettext invocations only if there are vars. + if not vars_referenced and not newstyle: + singular = singular.replace("%%", "%") + if plural: + plural = plural.replace("%%", "%") + + func_name = "gettext" + func_args: t.List[nodes.Expr] = [nodes.Const(singular)] + + if context is not None: + func_args.insert(0, nodes.Const(context)) + func_name = f"p{func_name}" + + if plural_expr is not None: + func_name = f"n{func_name}" + func_args.extend((nodes.Const(plural), plural_expr)) + + node = nodes.Call(nodes.Name(func_name, "load"), func_args, [], None, None) + + # in case newstyle gettext is used, the method is powerful + # enough to handle the variable expansion and autoescape + # handling itself + if newstyle: + for key, value in variables.items(): + # the function adds that later anyways in case num was + # called num, so just skip it. + if num_called_num and key == "num": + continue + node.kwargs.append(nodes.Keyword(key, value)) + + # otherwise do that here + else: + # mark the return value as safe if we are in an + # environment with autoescaping turned on + node = nodes.MarkSafeIfAutoescape(node) + if variables: + node = nodes.Mod( + node, + nodes.Dict( + [ + nodes.Pair(nodes.Const(key), value) + for key, value in variables.items() + ] + ), + ) + return nodes.Output([node]) + + +class ExprStmtExtension(Extension): + """Adds a `do` tag to Jinja that works like the print statement just + that it doesn't print the return value. + """ + + tags = {"do"} + + def parse(self, parser: "Parser") -> nodes.ExprStmt: + node = nodes.ExprStmt(lineno=next(parser.stream).lineno) + node.node = parser.parse_tuple() + return node + + +class LoopControlExtension(Extension): + """Adds break and continue to the template engine.""" + + tags = {"break", "continue"} + + def parse(self, parser: "Parser") -> t.Union[nodes.Break, nodes.Continue]: + token = next(parser.stream) + if token.value == "break": + return nodes.Break(lineno=token.lineno) + return nodes.Continue(lineno=token.lineno) + + +class DebugExtension(Extension): + """A ``{% debug %}`` tag that dumps the available variables, + filters, and tests. + + .. code-block:: html+jinja + + <pre>{% debug %}</pre> + + .. code-block:: text + + {'context': {'cycler': <class 'jinja2.utils.Cycler'>, + ..., + 'namespace': <class 'jinja2.utils.Namespace'>}, + 'filters': ['abs', 'attr', 'batch', 'capitalize', 'center', 'count', 'd', + ..., 'urlencode', 'urlize', 'wordcount', 'wordwrap', 'xmlattr'], + 'tests': ['!=', '<', '<=', '==', '>', '>=', 'callable', 'defined', + ..., 'odd', 'sameas', 'sequence', 'string', 'undefined', 'upper']} + + .. versionadded:: 2.11.0 + """ + + tags = {"debug"} + + def parse(self, parser: "Parser") -> nodes.Output: + lineno = parser.stream.expect("name:debug").lineno + context = nodes.ContextReference() + result = self.call_method("_render", [context], lineno=lineno) + return nodes.Output([result], lineno=lineno) + + def _render(self, context: Context) -> str: + result = { + "context": context.get_all(), + "filters": sorted(self.environment.filters.keys()), + "tests": sorted(self.environment.tests.keys()), + } + + # Set the depth since the intent is to show the top few names. + return pprint.pformat(result, depth=3, compact=True) + + +def extract_from_ast( + ast: nodes.Template, + gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, + babel_style: bool = True, +) -> t.Iterator[ + t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]] +]: + """Extract localizable strings from the given template node. Per + default this function returns matches in babel style that means non string + parameters as well as keyword arguments are returned as `None`. This + allows Babel to figure out what you really meant if you are using + gettext functions that allow keyword arguments for placeholder expansion. + If you don't want that behavior set the `babel_style` parameter to `False` + which causes only strings to be returned and parameters are always stored + in tuples. As a consequence invalid gettext calls (calls without a single + string parameter or string parameters after non-string parameters) are + skipped. + + This example explains the behavior: + + >>> from jinja2 import Environment + >>> env = Environment() + >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}') + >>> list(extract_from_ast(node)) + [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))] + >>> list(extract_from_ast(node, babel_style=False)) + [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))] + + For every string found this function yields a ``(lineno, function, + message)`` tuple, where: + + * ``lineno`` is the number of the line on which the string was found, + * ``function`` is the name of the ``gettext`` function used (if the + string was extracted from embedded Python code), and + * ``message`` is the string, or a tuple of strings for functions + with multiple string arguments. + + This extraction function operates on the AST and is because of that unable + to extract any comments. For comment support you have to use the babel + extraction interface or extract comments yourself. + """ + out: t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]] + + for node in ast.find_all(nodes.Call): + if ( + not isinstance(node.node, nodes.Name) + or node.node.name not in gettext_functions + ): + continue + + strings: t.List[t.Optional[str]] = [] + + for arg in node.args: + if isinstance(arg, nodes.Const) and isinstance(arg.value, str): + strings.append(arg.value) + else: + strings.append(None) + + for _ in node.kwargs: + strings.append(None) + if node.dyn_args is not None: + strings.append(None) + if node.dyn_kwargs is not None: + strings.append(None) + + if not babel_style: + out = tuple(x for x in strings if x is not None) + + if not out: + continue + else: + if len(strings) == 1: + out = strings[0] + else: + out = tuple(strings) + + yield node.lineno, node.node.name, out + + +class _CommentFinder: + """Helper class to find comments in a token stream. Can only + find comments for gettext calls forwards. Once the comment + from line 4 is found, a comment for line 1 will not return a + usable value. + """ + + def __init__( + self, tokens: t.Sequence[t.Tuple[int, str, str]], comment_tags: t.Sequence[str] + ) -> None: + self.tokens = tokens + self.comment_tags = comment_tags + self.offset = 0 + self.last_lineno = 0 + + def find_backwards(self, offset: int) -> t.List[str]: + try: + for _, token_type, token_value in reversed( + self.tokens[self.offset : offset] + ): + if token_type in ("comment", "linecomment"): + try: + prefix, comment = token_value.split(None, 1) + except ValueError: + continue + if prefix in self.comment_tags: + return [comment.rstrip()] + return [] + finally: + self.offset = offset + + def find_comments(self, lineno: int) -> t.List[str]: + if not self.comment_tags or self.last_lineno > lineno: + return [] + for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]): + if token_lineno > lineno: + return self.find_backwards(self.offset + idx) + return self.find_backwards(len(self.tokens)) + + +def babel_extract( + fileobj: t.BinaryIO, + keywords: t.Sequence[str], + comment_tags: t.Sequence[str], + options: t.Dict[str, t.Any], +) -> t.Iterator[ + t.Tuple[ + int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]], t.List[str] + ] +]: + """Babel extraction method for Jinja templates. + + .. versionchanged:: 2.3 + Basic support for translation comments was added. If `comment_tags` + is now set to a list of keywords for extraction, the extractor will + try to find the best preceding comment that begins with one of the + keywords. For best results, make sure to not have more than one + gettext call in one line of code and the matching comment in the + same line or the line before. + + .. versionchanged:: 2.5.1 + The `newstyle_gettext` flag can be set to `True` to enable newstyle + gettext calls. + + .. versionchanged:: 2.7 + A `silent` option can now be provided. If set to `False` template + syntax errors are propagated instead of being ignored. + + :param fileobj: the file-like object the messages should be extracted from + :param keywords: a list of keywords (i.e. function names) that should be + recognized as translation functions + :param comment_tags: a list of translator tags to search for and include + in the results. + :param options: a dictionary of additional options (optional) + :return: an iterator over ``(lineno, funcname, message, comments)`` tuples. + (comments will be empty currently) + """ + extensions: t.Dict[t.Type[Extension], None] = {} + + for extension_name in options.get("extensions", "").split(","): + extension_name = extension_name.strip() + + if not extension_name: + continue + + extensions[import_string(extension_name)] = None + + if InternationalizationExtension not in extensions: + extensions[InternationalizationExtension] = None + + def getbool(options: t.Mapping[str, str], key: str, default: bool = False) -> bool: + return options.get(key, str(default)).lower() in {"1", "on", "yes", "true"} + + silent = getbool(options, "silent", True) + environment = Environment( + options.get("block_start_string", defaults.BLOCK_START_STRING), + options.get("block_end_string", defaults.BLOCK_END_STRING), + options.get("variable_start_string", defaults.VARIABLE_START_STRING), + options.get("variable_end_string", defaults.VARIABLE_END_STRING), + options.get("comment_start_string", defaults.COMMENT_START_STRING), + options.get("comment_end_string", defaults.COMMENT_END_STRING), + options.get("line_statement_prefix") or defaults.LINE_STATEMENT_PREFIX, + options.get("line_comment_prefix") or defaults.LINE_COMMENT_PREFIX, + getbool(options, "trim_blocks", defaults.TRIM_BLOCKS), + getbool(options, "lstrip_blocks", defaults.LSTRIP_BLOCKS), + defaults.NEWLINE_SEQUENCE, + getbool(options, "keep_trailing_newline", defaults.KEEP_TRAILING_NEWLINE), + tuple(extensions), + cache_size=0, + auto_reload=False, + ) + + if getbool(options, "trimmed"): + environment.policies["ext.i18n.trimmed"] = True + if getbool(options, "newstyle_gettext"): + environment.newstyle_gettext = True # type: ignore + + source = fileobj.read().decode(options.get("encoding", "utf-8")) + try: + node = environment.parse(source) + tokens = list(environment.lex(environment.preprocess(source))) + except TemplateSyntaxError: + if not silent: + raise + # skip templates with syntax errors + return + + finder = _CommentFinder(tokens, comment_tags) + for lineno, func, message in extract_from_ast(node, keywords): + yield lineno, func, message, finder.find_comments(lineno) + + +#: nicer import names +i18n = InternationalizationExtension +do = ExprStmtExtension +loopcontrols = LoopControlExtension +debug = DebugExtension diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/filters.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/filters.py new file mode 100644 index 0000000000000000000000000000000000000000..ed07c4c0e2ae1b6203b3468cda8a303ecf3d7832 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/filters.py @@ -0,0 +1,1840 @@ +"""Built-in template filters used with the ``|`` operator.""" +import math +import random +import re +import typing +import typing as t +from collections import abc +from itertools import chain +from itertools import groupby + +from markupsafe import escape +from markupsafe import Markup +from markupsafe import soft_str + +from .async_utils import async_variant +from .async_utils import auto_aiter +from .async_utils import auto_await +from .async_utils import auto_to_list +from .exceptions import FilterArgumentError +from .runtime import Undefined +from .utils import htmlsafe_json_dumps +from .utils import pass_context +from .utils import pass_environment +from .utils import pass_eval_context +from .utils import pformat +from .utils import url_quote +from .utils import urlize + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + from .nodes import EvalContext + from .runtime import Context + from .sandbox import SandboxedEnvironment # noqa: F401 + + class HasHTML(te.Protocol): + def __html__(self) -> str: + pass + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +K = t.TypeVar("K") +V = t.TypeVar("V") + + +def ignore_case(value: V) -> V: + """For use as a postprocessor for :func:`make_attrgetter`. Converts strings + to lowercase and returns other types as-is.""" + if isinstance(value, str): + return t.cast(V, value.lower()) + + return value + + +def make_attrgetter( + environment: "Environment", + attribute: t.Optional[t.Union[str, int]], + postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, + default: t.Optional[t.Any] = None, +) -> t.Callable[[t.Any], t.Any]: + """Returns a callable that looks up the given attribute from a + passed object with the rules of the environment. Dots are allowed + to access attributes of attributes. Integer parts in paths are + looked up as integers. + """ + parts = _prepare_attribute_parts(attribute) + + def attrgetter(item: t.Any) -> t.Any: + for part in parts: + item = environment.getitem(item, part) + + if default is not None and isinstance(item, Undefined): + item = default + + if postprocess is not None: + item = postprocess(item) + + return item + + return attrgetter + + +def make_multi_attrgetter( + environment: "Environment", + attribute: t.Optional[t.Union[str, int]], + postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, +) -> t.Callable[[t.Any], t.List[t.Any]]: + """Returns a callable that looks up the given comma separated + attributes from a passed object with the rules of the environment. + Dots are allowed to access attributes of each attribute. Integer + parts in paths are looked up as integers. + + The value returned by the returned callable is a list of extracted + attribute values. + + Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc. + """ + if isinstance(attribute, str): + split: t.Sequence[t.Union[str, int, None]] = attribute.split(",") + else: + split = [attribute] + + parts = [_prepare_attribute_parts(item) for item in split] + + def attrgetter(item: t.Any) -> t.List[t.Any]: + items = [None] * len(parts) + + for i, attribute_part in enumerate(parts): + item_i = item + + for part in attribute_part: + item_i = environment.getitem(item_i, part) + + if postprocess is not None: + item_i = postprocess(item_i) + + items[i] = item_i + + return items + + return attrgetter + + +def _prepare_attribute_parts( + attr: t.Optional[t.Union[str, int]] +) -> t.List[t.Union[str, int]]: + if attr is None: + return [] + + if isinstance(attr, str): + return [int(x) if x.isdigit() else x for x in attr.split(".")] + + return [attr] + + +def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup: + """Enforce HTML escaping. This will probably double escape variables.""" + if hasattr(value, "__html__"): + value = t.cast("HasHTML", value).__html__() + + return escape(str(value)) + + +def do_urlencode( + value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]] +) -> str: + """Quote data for use in a URL path or query using UTF-8. + + Basic wrapper around :func:`urllib.parse.quote` when given a + string, or :func:`urllib.parse.urlencode` for a dict or iterable. + + :param value: Data to quote. A string will be quoted directly. A + dict or iterable of ``(key, value)`` pairs will be joined as a + query string. + + When given a string, "/" is not quoted. HTTP servers treat "/" and + "%2F" equivalently in paths. If you need quoted slashes, use the + ``|replace("/", "%2F")`` filter. + + .. versionadded:: 2.7 + """ + if isinstance(value, str) or not isinstance(value, abc.Iterable): + return url_quote(value) + + if isinstance(value, dict): + items: t.Iterable[t.Tuple[str, t.Any]] = value.items() + else: + items = value # type: ignore + + return "&".join( + f"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k, v in items + ) + + +@pass_eval_context +def do_replace( + eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None +) -> str: + """Return a copy of the value with all occurrences of a substring + replaced with a new one. The first argument is the substring + that should be replaced, the second is the replacement string. + If the optional third argument ``count`` is given, only the first + ``count`` occurrences are replaced: + + .. sourcecode:: jinja + + {{ "Hello World"|replace("Hello", "Goodbye") }} + -> Goodbye World + + {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} + -> d'oh, d'oh, aaargh + """ + if count is None: + count = -1 + + if not eval_ctx.autoescape: + return str(s).replace(str(old), str(new), count) + + if ( + hasattr(old, "__html__") + or hasattr(new, "__html__") + and not hasattr(s, "__html__") + ): + s = escape(s) + else: + s = soft_str(s) + + return s.replace(soft_str(old), soft_str(new), count) + + +def do_upper(s: str) -> str: + """Convert a value to uppercase.""" + return soft_str(s).upper() + + +def do_lower(s: str) -> str: + """Convert a value to lowercase.""" + return soft_str(s).lower() + + +def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]: + """Return an iterator over the ``(key, value)`` items of a mapping. + + ``x|items`` is the same as ``x.items()``, except if ``x`` is + undefined an empty iterator is returned. + + This filter is useful if you expect the template to be rendered with + an implementation of Jinja in another programming language that does + not have a ``.items()`` method on its mapping type. + + .. code-block:: html+jinja + + <dl> + {% for key, value in my_dict|items %} + <dt>{{ key }} + <dd>{{ value }} + {% endfor %} + </dl> + + .. versionadded:: 3.1 + """ + if isinstance(value, Undefined): + return + + if not isinstance(value, abc.Mapping): + raise TypeError("Can only get item pairs from a mapping.") + + yield from value.items() + + +@pass_eval_context +def do_xmlattr( + eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True +) -> str: + """Create an SGML/XML attribute string based on the items in a dict. + All values that are neither `none` nor `undefined` are automatically + escaped: + + .. sourcecode:: html+jinja + + <ul{{ {'class': 'my_list', 'missing': none, + 'id': 'list-%d'|format(variable)}|xmlattr }}> + ... + </ul> + + Results in something like this: + + .. sourcecode:: html + + <ul class="my_list" id="list-42"> + ... + </ul> + + As you can see it automatically prepends a space in front of the item + if the filter returned something unless the second parameter is false. + """ + rv = " ".join( + f'{escape(key)}="{escape(value)}"' + for key, value in d.items() + if value is not None and not isinstance(value, Undefined) + ) + + if autospace and rv: + rv = " " + rv + + if eval_ctx.autoescape: + rv = Markup(rv) + + return rv + + +def do_capitalize(s: str) -> str: + """Capitalize a value. The first character will be uppercase, all others + lowercase. + """ + return soft_str(s).capitalize() + + +_word_beginning_split_re = re.compile(r"([-\s({\[<]+)") + + +def do_title(s: str) -> str: + """Return a titlecased version of the value. I.e. words will start with + uppercase letters, all remaining characters are lowercase. + """ + return "".join( + [ + item[0].upper() + item[1:].lower() + for item in _word_beginning_split_re.split(soft_str(s)) + if item + ] + ) + + +def do_dictsort( + value: t.Mapping[K, V], + case_sensitive: bool = False, + by: 'te.Literal["key", "value"]' = "key", + reverse: bool = False, +) -> t.List[t.Tuple[K, V]]: + """Sort a dict and yield (key, value) pairs. Python dicts may not + be in the order you want to display them in, so sort them first. + + .. sourcecode:: jinja + + {% for key, value in mydict|dictsort %} + sort the dict by key, case insensitive + + {% for key, value in mydict|dictsort(reverse=true) %} + sort the dict by key, case insensitive, reverse order + + {% for key, value in mydict|dictsort(true) %} + sort the dict by key, case sensitive + + {% for key, value in mydict|dictsort(false, 'value') %} + sort the dict by value, case insensitive + """ + if by == "key": + pos = 0 + elif by == "value": + pos = 1 + else: + raise FilterArgumentError('You can only sort by either "key" or "value"') + + def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any: + value = item[pos] + + if not case_sensitive: + value = ignore_case(value) + + return value + + return sorted(value.items(), key=sort_func, reverse=reverse) + + +@pass_environment +def do_sort( + environment: "Environment", + value: "t.Iterable[V]", + reverse: bool = False, + case_sensitive: bool = False, + attribute: t.Optional[t.Union[str, int]] = None, +) -> "t.List[V]": + """Sort an iterable using Python's :func:`sorted`. + + .. sourcecode:: jinja + + {% for city in cities|sort %} + ... + {% endfor %} + + :param reverse: Sort descending instead of ascending. + :param case_sensitive: When sorting strings, sort upper and lower + case separately. + :param attribute: When sorting objects or dicts, an attribute or + key to sort by. Can use dot notation like ``"address.city"``. + Can be a list of attributes like ``"age,name"``. + + The sort is stable, it does not change the relative order of + elements that compare equal. This makes it is possible to chain + sorts on different attributes and ordering. + + .. sourcecode:: jinja + + {% for user in users|sort(attribute="name") + |sort(reverse=true, attribute="age") %} + ... + {% endfor %} + + As a shortcut to chaining when the direction is the same for all + attributes, pass a comma separate list of attributes. + + .. sourcecode:: jinja + + {% for user in users|sort(attribute="age,name") %} + ... + {% endfor %} + + .. versionchanged:: 2.11.0 + The ``attribute`` parameter can be a comma separated list of + attributes, e.g. ``"age,name"``. + + .. versionchanged:: 2.6 + The ``attribute`` parameter was added. + """ + key_func = make_multi_attrgetter( + environment, attribute, postprocess=ignore_case if not case_sensitive else None + ) + return sorted(value, key=key_func, reverse=reverse) + + +@pass_environment +def do_unique( + environment: "Environment", + value: "t.Iterable[V]", + case_sensitive: bool = False, + attribute: t.Optional[t.Union[str, int]] = None, +) -> "t.Iterator[V]": + """Returns a list of unique items from the given iterable. + + .. sourcecode:: jinja + + {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} + -> ['foo', 'bar', 'foobar'] + + The unique items are yielded in the same order as their first occurrence in + the iterable passed to the filter. + + :param case_sensitive: Treat upper and lower case strings as distinct. + :param attribute: Filter objects with unique values for this attribute. + """ + getter = make_attrgetter( + environment, attribute, postprocess=ignore_case if not case_sensitive else None + ) + seen = set() + + for item in value: + key = getter(item) + + if key not in seen: + seen.add(key) + yield item + + +def _min_or_max( + environment: "Environment", + value: "t.Iterable[V]", + func: "t.Callable[..., V]", + case_sensitive: bool, + attribute: t.Optional[t.Union[str, int]], +) -> "t.Union[V, Undefined]": + it = iter(value) + + try: + first = next(it) + except StopIteration: + return environment.undefined("No aggregated item, sequence was empty.") + + key_func = make_attrgetter( + environment, attribute, postprocess=ignore_case if not case_sensitive else None + ) + return func(chain([first], it), key=key_func) + + +@pass_environment +def do_min( + environment: "Environment", + value: "t.Iterable[V]", + case_sensitive: bool = False, + attribute: t.Optional[t.Union[str, int]] = None, +) -> "t.Union[V, Undefined]": + """Return the smallest item from the sequence. + + .. sourcecode:: jinja + + {{ [1, 2, 3]|min }} + -> 1 + + :param case_sensitive: Treat upper and lower case strings as distinct. + :param attribute: Get the object with the min value of this attribute. + """ + return _min_or_max(environment, value, min, case_sensitive, attribute) + + +@pass_environment +def do_max( + environment: "Environment", + value: "t.Iterable[V]", + case_sensitive: bool = False, + attribute: t.Optional[t.Union[str, int]] = None, +) -> "t.Union[V, Undefined]": + """Return the largest item from the sequence. + + .. sourcecode:: jinja + + {{ [1, 2, 3]|max }} + -> 3 + + :param case_sensitive: Treat upper and lower case strings as distinct. + :param attribute: Get the object with the max value of this attribute. + """ + return _min_or_max(environment, value, max, case_sensitive, attribute) + + +def do_default( + value: V, + default_value: V = "", # type: ignore + boolean: bool = False, +) -> V: + """If the value is undefined it will return the passed default value, + otherwise the value of the variable: + + .. sourcecode:: jinja + + {{ my_variable|default('my_variable is not defined') }} + + This will output the value of ``my_variable`` if the variable was + defined, otherwise ``'my_variable is not defined'``. If you want + to use default with variables that evaluate to false you have to + set the second parameter to `true`: + + .. sourcecode:: jinja + + {{ ''|default('the string was empty', true) }} + + .. versionchanged:: 2.11 + It's now possible to configure the :class:`~jinja2.Environment` with + :class:`~jinja2.ChainableUndefined` to make the `default` filter work + on nested elements and attributes that may contain undefined values + in the chain without getting an :exc:`~jinja2.UndefinedError`. + """ + if isinstance(value, Undefined) or (boolean and not value): + return default_value + + return value + + +@pass_eval_context +def sync_do_join( + eval_ctx: "EvalContext", + value: t.Iterable, + d: str = "", + attribute: t.Optional[t.Union[str, int]] = None, +) -> str: + """Return a string which is the concatenation of the strings in the + sequence. The separator between elements is an empty string per + default, you can define it with the optional parameter: + + .. sourcecode:: jinja + + {{ [1, 2, 3]|join('|') }} + -> 1|2|3 + + {{ [1, 2, 3]|join }} + -> 123 + + It is also possible to join certain attributes of an object: + + .. sourcecode:: jinja + + {{ users|join(', ', attribute='username') }} + + .. versionadded:: 2.6 + The `attribute` parameter was added. + """ + if attribute is not None: + value = map(make_attrgetter(eval_ctx.environment, attribute), value) + + # no automatic escaping? joining is a lot easier then + if not eval_ctx.autoescape: + return str(d).join(map(str, value)) + + # if the delimiter doesn't have an html representation we check + # if any of the items has. If yes we do a coercion to Markup + if not hasattr(d, "__html__"): + value = list(value) + do_escape = False + + for idx, item in enumerate(value): + if hasattr(item, "__html__"): + do_escape = True + else: + value[idx] = str(item) + + if do_escape: + d = escape(d) + else: + d = str(d) + + return d.join(value) + + # no html involved, to normal joining + return soft_str(d).join(map(soft_str, value)) + + +@async_variant(sync_do_join) # type: ignore +async def do_join( + eval_ctx: "EvalContext", + value: t.Union[t.AsyncIterable, t.Iterable], + d: str = "", + attribute: t.Optional[t.Union[str, int]] = None, +) -> str: + return sync_do_join(eval_ctx, await auto_to_list(value), d, attribute) + + +def do_center(value: str, width: int = 80) -> str: + """Centers the value in a field of a given width.""" + return soft_str(value).center(width) + + +@pass_environment +def sync_do_first( + environment: "Environment", seq: "t.Iterable[V]" +) -> "t.Union[V, Undefined]": + """Return the first item of a sequence.""" + try: + return next(iter(seq)) + except StopIteration: + return environment.undefined("No first item, sequence was empty.") + + +@async_variant(sync_do_first) # type: ignore +async def do_first( + environment: "Environment", seq: "t.Union[t.AsyncIterable[V], t.Iterable[V]]" +) -> "t.Union[V, Undefined]": + try: + return await auto_aiter(seq).__anext__() + except StopAsyncIteration: + return environment.undefined("No first item, sequence was empty.") + + +@pass_environment +def do_last( + environment: "Environment", seq: "t.Reversible[V]" +) -> "t.Union[V, Undefined]": + """Return the last item of a sequence. + + Note: Does not work with generators. You may want to explicitly + convert it to a list: + + .. sourcecode:: jinja + + {{ data | selectattr('name', '==', 'Jinja') | list | last }} + """ + try: + return next(iter(reversed(seq))) + except StopIteration: + return environment.undefined("No last item, sequence was empty.") + + +# No async do_last, it may not be safe in async mode. + + +@pass_context +def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]": + """Return a random item from the sequence.""" + try: + return random.choice(seq) + except IndexError: + return context.environment.undefined("No random item, sequence was empty.") + + +def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str: + """Format the value like a 'human-readable' file size (i.e. 13 kB, + 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, + Giga, etc.), if the second parameter is set to `True` the binary + prefixes are used (Mebi, Gibi). + """ + bytes = float(value) + base = 1024 if binary else 1000 + prefixes = [ + ("KiB" if binary else "kB"), + ("MiB" if binary else "MB"), + ("GiB" if binary else "GB"), + ("TiB" if binary else "TB"), + ("PiB" if binary else "PB"), + ("EiB" if binary else "EB"), + ("ZiB" if binary else "ZB"), + ("YiB" if binary else "YB"), + ] + + if bytes == 1: + return "1 Byte" + elif bytes < base: + return f"{int(bytes)} Bytes" + else: + for i, prefix in enumerate(prefixes): + unit = base ** (i + 2) + + if bytes < unit: + return f"{base * bytes / unit:.1f} {prefix}" + + return f"{base * bytes / unit:.1f} {prefix}" + + +def do_pprint(value: t.Any) -> str: + """Pretty print a variable. Useful for debugging.""" + return pformat(value) + + +_uri_scheme_re = re.compile(r"^([\w.+-]{2,}:(/){0,2})$") + + +@pass_eval_context +def do_urlize( + eval_ctx: "EvalContext", + value: str, + trim_url_limit: t.Optional[int] = None, + nofollow: bool = False, + target: t.Optional[str] = None, + rel: t.Optional[str] = None, + extra_schemes: t.Optional[t.Iterable[str]] = None, +) -> str: + """Convert URLs in text into clickable links. + + This may not recognize links in some situations. Usually, a more + comprehensive formatter, such as a Markdown library, is a better + choice. + + Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email + addresses. Links with trailing punctuation (periods, commas, closing + parentheses) and leading punctuation (opening parentheses) are + recognized excluding the punctuation. Email addresses that include + header fields are not recognized (for example, + ``mailto:address@example.com?cc=copy@example.com``). + + :param value: Original text containing URLs to link. + :param trim_url_limit: Shorten displayed URL values to this length. + :param nofollow: Add the ``rel=nofollow`` attribute to links. + :param target: Add the ``target`` attribute to links. + :param rel: Add the ``rel`` attribute to links. + :param extra_schemes: Recognize URLs that start with these schemes + in addition to the default behavior. Defaults to + ``env.policies["urlize.extra_schemes"]``, which defaults to no + extra schemes. + + .. versionchanged:: 3.0 + The ``extra_schemes`` parameter was added. + + .. versionchanged:: 3.0 + Generate ``https://`` links for URLs without a scheme. + + .. versionchanged:: 3.0 + The parsing rules were updated. Recognize email addresses with + or without the ``mailto:`` scheme. Validate IP addresses. Ignore + parentheses and brackets in more cases. + + .. versionchanged:: 2.8 + The ``target`` parameter was added. + """ + policies = eval_ctx.environment.policies + rel_parts = set((rel or "").split()) + + if nofollow: + rel_parts.add("nofollow") + + rel_parts.update((policies["urlize.rel"] or "").split()) + rel = " ".join(sorted(rel_parts)) or None + + if target is None: + target = policies["urlize.target"] + + if extra_schemes is None: + extra_schemes = policies["urlize.extra_schemes"] or () + + for scheme in extra_schemes: + if _uri_scheme_re.fullmatch(scheme) is None: + raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.") + + rv = urlize( + value, + trim_url_limit=trim_url_limit, + rel=rel, + target=target, + extra_schemes=extra_schemes, + ) + + if eval_ctx.autoescape: + rv = Markup(rv) + + return rv + + +def do_indent( + s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False +) -> str: + """Return a copy of the string with each line indented by 4 spaces. The + first line and blank lines are not indented by default. + + :param width: Number of spaces, or a string, to indent by. + :param first: Don't skip indenting the first line. + :param blank: Don't skip indenting empty lines. + + .. versionchanged:: 3.0 + ``width`` can be a string. + + .. versionchanged:: 2.10 + Blank lines are not indented by default. + + Rename the ``indentfirst`` argument to ``first``. + """ + if isinstance(width, str): + indention = width + else: + indention = " " * width + + newline = "\n" + + if isinstance(s, Markup): + indention = Markup(indention) + newline = Markup(newline) + + s += newline # this quirk is necessary for splitlines method + + if blank: + rv = (newline + indention).join(s.splitlines()) + else: + lines = s.splitlines() + rv = lines.pop(0) + + if lines: + rv += newline + newline.join( + indention + line if line else line for line in lines + ) + + if first: + rv = indention + rv + + return rv + + +@pass_environment +def do_truncate( + env: "Environment", + s: str, + length: int = 255, + killwords: bool = False, + end: str = "...", + leeway: t.Optional[int] = None, +) -> str: + """Return a truncated copy of the string. The length is specified + with the first parameter which defaults to ``255``. If the second + parameter is ``true`` the filter will cut the text at length. Otherwise + it will discard the last word. If the text was in fact + truncated it will append an ellipsis sign (``"..."``). If you want a + different ellipsis sign than ``"..."`` you can specify it using the + third parameter. Strings that only exceed the length by the tolerance + margin given in the fourth parameter will not be truncated. + + .. sourcecode:: jinja + + {{ "foo bar baz qux"|truncate(9) }} + -> "foo..." + {{ "foo bar baz qux"|truncate(9, True) }} + -> "foo ba..." + {{ "foo bar baz qux"|truncate(11) }} + -> "foo bar baz qux" + {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} + -> "foo bar..." + + The default leeway on newer Jinja versions is 5 and was 0 before but + can be reconfigured globally. + """ + if leeway is None: + leeway = env.policies["truncate.leeway"] + + assert length >= len(end), f"expected length >= {len(end)}, got {length}" + assert leeway >= 0, f"expected leeway >= 0, got {leeway}" + + if len(s) <= length + leeway: + return s + + if killwords: + return s[: length - len(end)] + end + + result = s[: length - len(end)].rsplit(" ", 1)[0] + return result + end + + +@pass_environment +def do_wordwrap( + environment: "Environment", + s: str, + width: int = 79, + break_long_words: bool = True, + wrapstring: t.Optional[str] = None, + break_on_hyphens: bool = True, +) -> str: + """Wrap a string to the given width. Existing newlines are treated + as paragraphs to be wrapped separately. + + :param s: Original text to wrap. + :param width: Maximum length of wrapped lines. + :param break_long_words: If a word is longer than ``width``, break + it across lines. + :param break_on_hyphens: If a word contains hyphens, it may be split + across lines. + :param wrapstring: String to join each wrapped line. Defaults to + :attr:`Environment.newline_sequence`. + + .. versionchanged:: 2.11 + Existing newlines are treated as paragraphs wrapped separately. + + .. versionchanged:: 2.11 + Added the ``break_on_hyphens`` parameter. + + .. versionchanged:: 2.7 + Added the ``wrapstring`` parameter. + """ + import textwrap + + if wrapstring is None: + wrapstring = environment.newline_sequence + + # textwrap.wrap doesn't consider existing newlines when wrapping. + # If the string has a newline before width, wrap will still insert + # a newline at width, resulting in a short line. Instead, split and + # wrap each paragraph individually. + return wrapstring.join( + [ + wrapstring.join( + textwrap.wrap( + line, + width=width, + expand_tabs=False, + replace_whitespace=False, + break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens, + ) + ) + for line in s.splitlines() + ] + ) + + +_word_re = re.compile(r"\w+") + + +def do_wordcount(s: str) -> int: + """Count the words in that string.""" + return len(_word_re.findall(soft_str(s))) + + +def do_int(value: t.Any, default: int = 0, base: int = 10) -> int: + """Convert the value into an integer. If the + conversion doesn't work it will return ``0``. You can + override this default using the first parameter. You + can also override the default base (10) in the second + parameter, which handles input with prefixes such as + 0b, 0o and 0x for bases 2, 8 and 16 respectively. + The base is ignored for decimal numbers and non-string values. + """ + try: + if isinstance(value, str): + return int(value, base) + + return int(value) + except (TypeError, ValueError): + # this quirk is necessary so that "42.23"|int gives 42. + try: + return int(float(value)) + except (TypeError, ValueError): + return default + + +def do_float(value: t.Any, default: float = 0.0) -> float: + """Convert the value into a floating point number. If the + conversion doesn't work it will return ``0.0``. You can + override this default using the first parameter. + """ + try: + return float(value) + except (TypeError, ValueError): + return default + + +def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str: + """Apply the given values to a `printf-style`_ format string, like + ``string % values``. + + .. sourcecode:: jinja + + {{ "%s, %s!"|format(greeting, name) }} + Hello, World! + + In most cases it should be more convenient and efficient to use the + ``%`` operator or :meth:`str.format`. + + .. code-block:: text + + {{ "%s, %s!" % (greeting, name) }} + {{ "{}, {}!".format(greeting, name) }} + + .. _printf-style: https://docs.python.org/library/stdtypes.html + #printf-style-string-formatting + """ + if args and kwargs: + raise FilterArgumentError( + "can't handle positional and keyword arguments at the same time" + ) + + return soft_str(value) % (kwargs or args) + + +def do_trim(value: str, chars: t.Optional[str] = None) -> str: + """Strip leading and trailing characters, by default whitespace.""" + return soft_str(value).strip(chars) + + +def do_striptags(value: "t.Union[str, HasHTML]") -> str: + """Strip SGML/XML tags and replace adjacent whitespace by one space.""" + if hasattr(value, "__html__"): + value = t.cast("HasHTML", value).__html__() + + return Markup(str(value)).striptags() + + +def sync_do_slice( + value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None +) -> "t.Iterator[t.List[V]]": + """Slice an iterator and return a list of lists containing + those items. Useful if you want to create a div containing + three ul tags that represent columns: + + .. sourcecode:: html+jinja + + <div class="columnwrapper"> + {%- for column in items|slice(3) %} + <ul class="column-{{ loop.index }}"> + {%- for item in column %} + <li>{{ item }}</li> + {%- endfor %} + </ul> + {%- endfor %} + </div> + + If you pass it a second argument it's used to fill missing + values on the last iteration. + """ + seq = list(value) + length = len(seq) + items_per_slice = length // slices + slices_with_extra = length % slices + offset = 0 + + for slice_number in range(slices): + start = offset + slice_number * items_per_slice + + if slice_number < slices_with_extra: + offset += 1 + + end = offset + (slice_number + 1) * items_per_slice + tmp = seq[start:end] + + if fill_with is not None and slice_number >= slices_with_extra: + tmp.append(fill_with) + + yield tmp + + +@async_variant(sync_do_slice) # type: ignore +async def do_slice( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + slices: int, + fill_with: t.Optional[t.Any] = None, +) -> "t.Iterator[t.List[V]]": + return sync_do_slice(await auto_to_list(value), slices, fill_with) + + +def do_batch( + value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None +) -> "t.Iterator[t.List[V]]": + """ + A filter that batches items. It works pretty much like `slice` + just the other way round. It returns a list of lists with the + given number of items. If you provide a second parameter this + is used to fill up missing items. See this example: + + .. sourcecode:: html+jinja + + <table> + {%- for row in items|batch(3, ' ') %} + <tr> + {%- for column in row %} + <td>{{ column }}</td> + {%- endfor %} + </tr> + {%- endfor %} + </table> + """ + tmp: "t.List[V]" = [] + + for item in value: + if len(tmp) == linecount: + yield tmp + tmp = [] + + tmp.append(item) + + if tmp: + if fill_with is not None and len(tmp) < linecount: + tmp += [fill_with] * (linecount - len(tmp)) + + yield tmp + + +def do_round( + value: float, + precision: int = 0, + method: 'te.Literal["common", "ceil", "floor"]' = "common", +) -> float: + """Round the number to a given precision. The first + parameter specifies the precision (default is ``0``), the + second the rounding method: + + - ``'common'`` rounds either up or down + - ``'ceil'`` always rounds up + - ``'floor'`` always rounds down + + If you don't specify a method ``'common'`` is used. + + .. sourcecode:: jinja + + {{ 42.55|round }} + -> 43.0 + {{ 42.55|round(1, 'floor') }} + -> 42.5 + + Note that even if rounded to 0 precision, a float is returned. If + you need a real integer, pipe it through `int`: + + .. sourcecode:: jinja + + {{ 42.55|round|int }} + -> 43 + """ + if method not in {"common", "ceil", "floor"}: + raise FilterArgumentError("method must be common, ceil or floor") + + if method == "common": + return round(value, precision) + + func = getattr(math, method) + return t.cast(float, func(value * (10**precision)) / (10**precision)) + + +class _GroupTuple(t.NamedTuple): + grouper: t.Any + list: t.List + + # Use the regular tuple repr to hide this subclass if users print + # out the value during debugging. + def __repr__(self) -> str: + return tuple.__repr__(self) + + def __str__(self) -> str: + return tuple.__str__(self) + + +@pass_environment +def sync_do_groupby( + environment: "Environment", + value: "t.Iterable[V]", + attribute: t.Union[str, int], + default: t.Optional[t.Any] = None, + case_sensitive: bool = False, +) -> "t.List[_GroupTuple]": + """Group a sequence of objects by an attribute using Python's + :func:`itertools.groupby`. The attribute can use dot notation for + nested access, like ``"address.city"``. Unlike Python's ``groupby``, + the values are sorted first so only one group is returned for each + unique value. + + For example, a list of ``User`` objects with a ``city`` attribute + can be rendered in groups. In this example, ``grouper`` refers to + the ``city`` value of the group. + + .. sourcecode:: html+jinja + + <ul>{% for city, items in users|groupby("city") %} + <li>{{ city }} + <ul>{% for user in items %} + <li>{{ user.name }} + {% endfor %}</ul> + </li> + {% endfor %}</ul> + + ``groupby`` yields namedtuples of ``(grouper, list)``, which + can be used instead of the tuple unpacking above. ``grouper`` is the + value of the attribute, and ``list`` is the items with that value. + + .. sourcecode:: html+jinja + + <ul>{% for group in users|groupby("city") %} + <li>{{ group.grouper }}: {{ group.list|join(", ") }} + {% endfor %}</ul> + + You can specify a ``default`` value to use if an object in the list + does not have the given attribute. + + .. sourcecode:: jinja + + <ul>{% for city, items in users|groupby("city", default="NY") %} + <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li> + {% endfor %}</ul> + + Like the :func:`~jinja-filters.sort` filter, sorting and grouping is + case-insensitive by default. The ``key`` for each group will have + the case of the first item in that group of values. For example, if + a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group + will have two values. This can be disabled by passing + ``case_sensitive=True``. + + .. versionchanged:: 3.1 + Added the ``case_sensitive`` parameter. Sorting and grouping is + case-insensitive by default, matching other filters that do + comparisons. + + .. versionchanged:: 3.0 + Added the ``default`` parameter. + + .. versionchanged:: 2.6 + The attribute supports dot notation for nested access. + """ + expr = make_attrgetter( + environment, + attribute, + postprocess=ignore_case if not case_sensitive else None, + default=default, + ) + out = [ + _GroupTuple(key, list(values)) + for key, values in groupby(sorted(value, key=expr), expr) + ] + + if not case_sensitive: + # Return the real key from the first value instead of the lowercase key. + output_expr = make_attrgetter(environment, attribute, default=default) + out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] + + return out + + +@async_variant(sync_do_groupby) # type: ignore +async def do_groupby( + environment: "Environment", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + attribute: t.Union[str, int], + default: t.Optional[t.Any] = None, + case_sensitive: bool = False, +) -> "t.List[_GroupTuple]": + expr = make_attrgetter( + environment, + attribute, + postprocess=ignore_case if not case_sensitive else None, + default=default, + ) + out = [ + _GroupTuple(key, await auto_to_list(values)) + for key, values in groupby(sorted(await auto_to_list(value), key=expr), expr) + ] + + if not case_sensitive: + # Return the real key from the first value instead of the lowercase key. + output_expr = make_attrgetter(environment, attribute, default=default) + out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] + + return out + + +@pass_environment +def sync_do_sum( + environment: "Environment", + iterable: "t.Iterable[V]", + attribute: t.Optional[t.Union[str, int]] = None, + start: V = 0, # type: ignore +) -> V: + """Returns the sum of a sequence of numbers plus the value of parameter + 'start' (which defaults to 0). When the sequence is empty it returns + start. + + It is also possible to sum up only certain attributes: + + .. sourcecode:: jinja + + Total: {{ items|sum(attribute='price') }} + + .. versionchanged:: 2.6 + The ``attribute`` parameter was added to allow summing up over + attributes. Also the ``start`` parameter was moved on to the right. + """ + if attribute is not None: + iterable = map(make_attrgetter(environment, attribute), iterable) + + return sum(iterable, start) # type: ignore[no-any-return, call-overload] + + +@async_variant(sync_do_sum) # type: ignore +async def do_sum( + environment: "Environment", + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + attribute: t.Optional[t.Union[str, int]] = None, + start: V = 0, # type: ignore +) -> V: + rv = start + + if attribute is not None: + func = make_attrgetter(environment, attribute) + else: + + def func(x: V) -> V: + return x + + async for item in auto_aiter(iterable): + rv += func(item) + + return rv + + +def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": + """Convert the value into a list. If it was a string the returned list + will be a list of characters. + """ + return list(value) + + +@async_variant(sync_do_list) # type: ignore +async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]": + return await auto_to_list(value) + + +def do_mark_safe(value: str) -> Markup: + """Mark the value as safe which means that in an environment with automatic + escaping enabled this variable will not be escaped. + """ + return Markup(value) + + +def do_mark_unsafe(value: str) -> str: + """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" + return str(value) + + +@typing.overload +def do_reverse(value: str) -> str: + ... + + +@typing.overload +def do_reverse(value: "t.Iterable[V]") -> "t.Iterable[V]": + ... + + +def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]: + """Reverse the object or return an iterator that iterates over it the other + way round. + """ + if isinstance(value, str): + return value[::-1] + + try: + return reversed(value) # type: ignore + except TypeError: + try: + rv = list(value) + rv.reverse() + return rv + except TypeError as e: + raise FilterArgumentError("argument must be iterable") from e + + +@pass_environment +def do_attr( + environment: "Environment", obj: t.Any, name: str +) -> t.Union[Undefined, t.Any]: + """Get an attribute of an object. ``foo|attr("bar")`` works like + ``foo.bar`` just that always an attribute is returned and items are not + looked up. + + See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. + """ + try: + name = str(name) + except UnicodeError: + pass + else: + try: + value = getattr(obj, name) + except AttributeError: + pass + else: + if environment.sandboxed: + environment = t.cast("SandboxedEnvironment", environment) + + if not environment.is_safe_attribute(obj, name, value): + return environment.unsafe_undefined(obj, name) + + return value + + return environment.undefined(obj=obj, name=name) + + +@typing.overload +def sync_do_map( + context: "Context", value: t.Iterable, name: str, *args: t.Any, **kwargs: t.Any +) -> t.Iterable: + ... + + +@typing.overload +def sync_do_map( + context: "Context", + value: t.Iterable, + *, + attribute: str = ..., + default: t.Optional[t.Any] = None, +) -> t.Iterable: + ... + + +@pass_context +def sync_do_map( + context: "Context", value: t.Iterable, *args: t.Any, **kwargs: t.Any +) -> t.Iterable: + """Applies a filter on a sequence of objects or looks up an attribute. + This is useful when dealing with lists of objects but you are really + only interested in a certain value of it. + + The basic usage is mapping on an attribute. Imagine you have a list + of users but you are only interested in a list of usernames: + + .. sourcecode:: jinja + + Users on this page: {{ users|map(attribute='username')|join(', ') }} + + You can specify a ``default`` value to use if an object in the list + does not have the given attribute. + + .. sourcecode:: jinja + + {{ users|map(attribute="username", default="Anonymous")|join(", ") }} + + Alternatively you can let it invoke a filter by passing the name of the + filter and the arguments afterwards. A good example would be applying a + text conversion filter on a sequence: + + .. sourcecode:: jinja + + Users on this page: {{ titles|map('lower')|join(', ') }} + + Similar to a generator comprehension such as: + + .. code-block:: python + + (u.username for u in users) + (getattr(u, "username", "Anonymous") for u in users) + (do_lower(x) for x in titles) + + .. versionchanged:: 2.11.0 + Added the ``default`` parameter. + + .. versionadded:: 2.7 + """ + if value: + func = prepare_map(context, args, kwargs) + + for item in value: + yield func(item) + + +@typing.overload +def do_map( + context: "Context", + value: t.Union[t.AsyncIterable, t.Iterable], + name: str, + *args: t.Any, + **kwargs: t.Any, +) -> t.Iterable: + ... + + +@typing.overload +def do_map( + context: "Context", + value: t.Union[t.AsyncIterable, t.Iterable], + *, + attribute: str = ..., + default: t.Optional[t.Any] = None, +) -> t.Iterable: + ... + + +@async_variant(sync_do_map) # type: ignore +async def do_map( + context: "Context", + value: t.Union[t.AsyncIterable, t.Iterable], + *args: t.Any, + **kwargs: t.Any, +) -> t.AsyncIterable: + if value: + func = prepare_map(context, args, kwargs) + + async for item in auto_aiter(value): + yield await auto_await(func(item)) + + +@pass_context +def sync_do_select( + context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any +) -> "t.Iterator[V]": + """Filters a sequence of objects by applying a test to each object, + and only selecting the objects with the test succeeding. + + If no test is specified, each object will be evaluated as a boolean. + + Example usage: + + .. sourcecode:: jinja + + {{ numbers|select("odd") }} + {{ numbers|select("odd") }} + {{ numbers|select("divisibleby", 3) }} + {{ numbers|select("lessthan", 42) }} + {{ strings|select("equalto", "mystring") }} + + Similar to a generator comprehension such as: + + .. code-block:: python + + (n for n in numbers if test_odd(n)) + (n for n in numbers if test_divisibleby(n, 3)) + + .. versionadded:: 2.7 + """ + return select_or_reject(context, value, args, kwargs, lambda x: x, False) + + +@async_variant(sync_do_select) # type: ignore +async def do_select( + context: "Context", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + *args: t.Any, + **kwargs: t.Any, +) -> "t.AsyncIterator[V]": + return async_select_or_reject(context, value, args, kwargs, lambda x: x, False) + + +@pass_context +def sync_do_reject( + context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any +) -> "t.Iterator[V]": + """Filters a sequence of objects by applying a test to each object, + and rejecting the objects with the test succeeding. + + If no test is specified, each object will be evaluated as a boolean. + + Example usage: + + .. sourcecode:: jinja + + {{ numbers|reject("odd") }} + + Similar to a generator comprehension such as: + + .. code-block:: python + + (n for n in numbers if not test_odd(n)) + + .. versionadded:: 2.7 + """ + return select_or_reject(context, value, args, kwargs, lambda x: not x, False) + + +@async_variant(sync_do_reject) # type: ignore +async def do_reject( + context: "Context", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + *args: t.Any, + **kwargs: t.Any, +) -> "t.AsyncIterator[V]": + return async_select_or_reject(context, value, args, kwargs, lambda x: not x, False) + + +@pass_context +def sync_do_selectattr( + context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any +) -> "t.Iterator[V]": + """Filters a sequence of objects by applying a test to the specified + attribute of each object, and only selecting the objects with the + test succeeding. + + If no test is specified, the attribute's value will be evaluated as + a boolean. + + Example usage: + + .. sourcecode:: jinja + + {{ users|selectattr("is_active") }} + {{ users|selectattr("email", "none") }} + + Similar to a generator comprehension such as: + + .. code-block:: python + + (u for user in users if user.is_active) + (u for user in users if test_none(user.email)) + + .. versionadded:: 2.7 + """ + return select_or_reject(context, value, args, kwargs, lambda x: x, True) + + +@async_variant(sync_do_selectattr) # type: ignore +async def do_selectattr( + context: "Context", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + *args: t.Any, + **kwargs: t.Any, +) -> "t.AsyncIterator[V]": + return async_select_or_reject(context, value, args, kwargs, lambda x: x, True) + + +@pass_context +def sync_do_rejectattr( + context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any +) -> "t.Iterator[V]": + """Filters a sequence of objects by applying a test to the specified + attribute of each object, and rejecting the objects with the test + succeeding. + + If no test is specified, the attribute's value will be evaluated as + a boolean. + + .. sourcecode:: jinja + + {{ users|rejectattr("is_active") }} + {{ users|rejectattr("email", "none") }} + + Similar to a generator comprehension such as: + + .. code-block:: python + + (u for user in users if not user.is_active) + (u for user in users if not test_none(user.email)) + + .. versionadded:: 2.7 + """ + return select_or_reject(context, value, args, kwargs, lambda x: not x, True) + + +@async_variant(sync_do_rejectattr) # type: ignore +async def do_rejectattr( + context: "Context", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + *args: t.Any, + **kwargs: t.Any, +) -> "t.AsyncIterator[V]": + return async_select_or_reject(context, value, args, kwargs, lambda x: not x, True) + + +@pass_eval_context +def do_tojson( + eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None +) -> Markup: + """Serialize an object to a string of JSON, and mark it safe to + render in HTML. This filter is only for use in HTML documents. + + The returned string is safe to render in HTML documents and + ``<script>`` tags. The exception is in HTML attributes that are + double quoted; either use single quotes or the ``|forceescape`` + filter. + + :param value: The object to serialize to JSON. + :param indent: The ``indent`` parameter passed to ``dumps``, for + pretty-printing the value. + + .. versionadded:: 2.9 + """ + policies = eval_ctx.environment.policies + dumps = policies["json.dumps_function"] + kwargs = policies["json.dumps_kwargs"] + + if indent is not None: + kwargs = kwargs.copy() + kwargs["indent"] = indent + + return htmlsafe_json_dumps(value, dumps=dumps, **kwargs) + + +def prepare_map( + context: "Context", args: t.Tuple, kwargs: t.Dict[str, t.Any] +) -> t.Callable[[t.Any], t.Any]: + if not args and "attribute" in kwargs: + attribute = kwargs.pop("attribute") + default = kwargs.pop("default", None) + + if kwargs: + raise FilterArgumentError( + f"Unexpected keyword argument {next(iter(kwargs))!r}" + ) + + func = make_attrgetter(context.environment, attribute, default=default) + else: + try: + name = args[0] + args = args[1:] + except LookupError: + raise FilterArgumentError("map requires a filter argument") from None + + def func(item: t.Any) -> t.Any: + return context.environment.call_filter( + name, item, args, kwargs, context=context + ) + + return func + + +def prepare_select_or_reject( + context: "Context", + args: t.Tuple, + kwargs: t.Dict[str, t.Any], + modfunc: t.Callable[[t.Any], t.Any], + lookup_attr: bool, +) -> t.Callable[[t.Any], t.Any]: + if lookup_attr: + try: + attr = args[0] + except LookupError: + raise FilterArgumentError("Missing parameter for attribute name") from None + + transfunc = make_attrgetter(context.environment, attr) + off = 1 + else: + off = 0 + + def transfunc(x: V) -> V: + return x + + try: + name = args[off] + args = args[1 + off :] + + def func(item: t.Any) -> t.Any: + return context.environment.call_test(name, item, args, kwargs) + + except LookupError: + func = bool # type: ignore + + return lambda item: modfunc(func(transfunc(item))) + + +def select_or_reject( + context: "Context", + value: "t.Iterable[V]", + args: t.Tuple, + kwargs: t.Dict[str, t.Any], + modfunc: t.Callable[[t.Any], t.Any], + lookup_attr: bool, +) -> "t.Iterator[V]": + if value: + func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) + + for item in value: + if func(item): + yield item + + +async def async_select_or_reject( + context: "Context", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + args: t.Tuple, + kwargs: t.Dict[str, t.Any], + modfunc: t.Callable[[t.Any], t.Any], + lookup_attr: bool, +) -> "t.AsyncIterator[V]": + if value: + func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) + + async for item in auto_aiter(value): + if func(item): + yield item + + +FILTERS = { + "abs": abs, + "attr": do_attr, + "batch": do_batch, + "capitalize": do_capitalize, + "center": do_center, + "count": len, + "d": do_default, + "default": do_default, + "dictsort": do_dictsort, + "e": escape, + "escape": escape, + "filesizeformat": do_filesizeformat, + "first": do_first, + "float": do_float, + "forceescape": do_forceescape, + "format": do_format, + "groupby": do_groupby, + "indent": do_indent, + "int": do_int, + "join": do_join, + "last": do_last, + "length": len, + "list": do_list, + "lower": do_lower, + "items": do_items, + "map": do_map, + "min": do_min, + "max": do_max, + "pprint": do_pprint, + "random": do_random, + "reject": do_reject, + "rejectattr": do_rejectattr, + "replace": do_replace, + "reverse": do_reverse, + "round": do_round, + "safe": do_mark_safe, + "select": do_select, + "selectattr": do_selectattr, + "slice": do_slice, + "sort": do_sort, + "string": soft_str, + "striptags": do_striptags, + "sum": do_sum, + "title": do_title, + "trim": do_trim, + "truncate": do_truncate, + "unique": do_unique, + "upper": do_upper, + "urlencode": do_urlencode, + "urlize": do_urlize, + "wordcount": do_wordcount, + "wordwrap": do_wordwrap, + "xmlattr": do_xmlattr, + "tojson": do_tojson, +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/idtracking.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/idtracking.py new file mode 100644 index 0000000000000000000000000000000000000000..995ebaa0c8178ddb9e0479e0e9f6d30ed863a785 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/idtracking.py @@ -0,0 +1,318 @@ +import typing as t + +from . import nodes +from .visitor import NodeVisitor + +VAR_LOAD_PARAMETER = "param" +VAR_LOAD_RESOLVE = "resolve" +VAR_LOAD_ALIAS = "alias" +VAR_LOAD_UNDEFINED = "undefined" + + +def find_symbols( + nodes: t.Iterable[nodes.Node], parent_symbols: t.Optional["Symbols"] = None +) -> "Symbols": + sym = Symbols(parent=parent_symbols) + visitor = FrameSymbolVisitor(sym) + for node in nodes: + visitor.visit(node) + return sym + + +def symbols_for_node( + node: nodes.Node, parent_symbols: t.Optional["Symbols"] = None +) -> "Symbols": + sym = Symbols(parent=parent_symbols) + sym.analyze_node(node) + return sym + + +class Symbols: + def __init__( + self, parent: t.Optional["Symbols"] = None, level: t.Optional[int] = None + ) -> None: + if level is None: + if parent is None: + level = 0 + else: + level = parent.level + 1 + + self.level: int = level + self.parent = parent + self.refs: t.Dict[str, str] = {} + self.loads: t.Dict[str, t.Any] = {} + self.stores: t.Set[str] = set() + + def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None: + visitor = RootVisitor(self) + visitor.visit(node, **kwargs) + + def _define_ref( + self, name: str, load: t.Optional[t.Tuple[str, t.Optional[str]]] = None + ) -> str: + ident = f"l_{self.level}_{name}" + self.refs[name] = ident + if load is not None: + self.loads[ident] = load + return ident + + def find_load(self, target: str) -> t.Optional[t.Any]: + if target in self.loads: + return self.loads[target] + + if self.parent is not None: + return self.parent.find_load(target) + + return None + + def find_ref(self, name: str) -> t.Optional[str]: + if name in self.refs: + return self.refs[name] + + if self.parent is not None: + return self.parent.find_ref(name) + + return None + + def ref(self, name: str) -> str: + rv = self.find_ref(name) + if rv is None: + raise AssertionError( + "Tried to resolve a name to a reference that was" + f" unknown to the frame ({name!r})" + ) + return rv + + def copy(self) -> "Symbols": + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.refs = self.refs.copy() + rv.loads = self.loads.copy() + rv.stores = self.stores.copy() + return rv + + def store(self, name: str) -> None: + self.stores.add(name) + + # If we have not see the name referenced yet, we need to figure + # out what to set it to. + if name not in self.refs: + # If there is a parent scope we check if the name has a + # reference there. If it does it means we might have to alias + # to a variable there. + if self.parent is not None: + outer_ref = self.parent.find_ref(name) + if outer_ref is not None: + self._define_ref(name, load=(VAR_LOAD_ALIAS, outer_ref)) + return + + # Otherwise we can just set it to undefined. + self._define_ref(name, load=(VAR_LOAD_UNDEFINED, None)) + + def declare_parameter(self, name: str) -> str: + self.stores.add(name) + return self._define_ref(name, load=(VAR_LOAD_PARAMETER, None)) + + def load(self, name: str) -> None: + if self.find_ref(name) is None: + self._define_ref(name, load=(VAR_LOAD_RESOLVE, name)) + + def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None: + stores: t.Dict[str, int] = {} + for branch in branch_symbols: + for target in branch.stores: + if target in self.stores: + continue + stores[target] = stores.get(target, 0) + 1 + + for sym in branch_symbols: + self.refs.update(sym.refs) + self.loads.update(sym.loads) + self.stores.update(sym.stores) + + for name, branch_count in stores.items(): + if branch_count == len(branch_symbols): + continue + + target = self.find_ref(name) # type: ignore + assert target is not None, "should not happen" + + if self.parent is not None: + outer_target = self.parent.find_ref(name) + if outer_target is not None: + self.loads[target] = (VAR_LOAD_ALIAS, outer_target) + continue + self.loads[target] = (VAR_LOAD_RESOLVE, name) + + def dump_stores(self) -> t.Dict[str, str]: + rv: t.Dict[str, str] = {} + node: t.Optional["Symbols"] = self + + while node is not None: + for name in sorted(node.stores): + if name not in rv: + rv[name] = self.find_ref(name) # type: ignore + + node = node.parent + + return rv + + def dump_param_targets(self) -> t.Set[str]: + rv = set() + node: t.Optional["Symbols"] = self + + while node is not None: + for target, (instr, _) in self.loads.items(): + if instr == VAR_LOAD_PARAMETER: + rv.add(target) + + node = node.parent + + return rv + + +class RootVisitor(NodeVisitor): + def __init__(self, symbols: "Symbols") -> None: + self.sym_visitor = FrameSymbolVisitor(symbols) + + def _simple_visit(self, node: nodes.Node, **kwargs: t.Any) -> None: + for child in node.iter_child_nodes(): + self.sym_visitor.visit(child) + + visit_Template = _simple_visit + visit_Block = _simple_visit + visit_Macro = _simple_visit + visit_FilterBlock = _simple_visit + visit_Scope = _simple_visit + visit_If = _simple_visit + visit_ScopedEvalContextModifier = _simple_visit + + def visit_AssignBlock(self, node: nodes.AssignBlock, **kwargs: t.Any) -> None: + for child in node.body: + self.sym_visitor.visit(child) + + def visit_CallBlock(self, node: nodes.CallBlock, **kwargs: t.Any) -> None: + for child in node.iter_child_nodes(exclude=("call",)): + self.sym_visitor.visit(child) + + def visit_OverlayScope(self, node: nodes.OverlayScope, **kwargs: t.Any) -> None: + for child in node.body: + self.sym_visitor.visit(child) + + def visit_For( + self, node: nodes.For, for_branch: str = "body", **kwargs: t.Any + ) -> None: + if for_branch == "body": + self.sym_visitor.visit(node.target, store_as_param=True) + branch = node.body + elif for_branch == "else": + branch = node.else_ + elif for_branch == "test": + self.sym_visitor.visit(node.target, store_as_param=True) + if node.test is not None: + self.sym_visitor.visit(node.test) + return + else: + raise RuntimeError("Unknown for branch") + + if branch: + for item in branch: + self.sym_visitor.visit(item) + + def visit_With(self, node: nodes.With, **kwargs: t.Any) -> None: + for target in node.targets: + self.sym_visitor.visit(target) + for child in node.body: + self.sym_visitor.visit(child) + + def generic_visit(self, node: nodes.Node, *args: t.Any, **kwargs: t.Any) -> None: + raise NotImplementedError(f"Cannot find symbols for {type(node).__name__!r}") + + +class FrameSymbolVisitor(NodeVisitor): + """A visitor for `Frame.inspect`.""" + + def __init__(self, symbols: "Symbols") -> None: + self.symbols = symbols + + def visit_Name( + self, node: nodes.Name, store_as_param: bool = False, **kwargs: t.Any + ) -> None: + """All assignments to names go through this function.""" + if store_as_param or node.ctx == "param": + self.symbols.declare_parameter(node.name) + elif node.ctx == "store": + self.symbols.store(node.name) + elif node.ctx == "load": + self.symbols.load(node.name) + + def visit_NSRef(self, node: nodes.NSRef, **kwargs: t.Any) -> None: + self.symbols.load(node.name) + + def visit_If(self, node: nodes.If, **kwargs: t.Any) -> None: + self.visit(node.test, **kwargs) + original_symbols = self.symbols + + def inner_visit(nodes: t.Iterable[nodes.Node]) -> "Symbols": + self.symbols = rv = original_symbols.copy() + + for subnode in nodes: + self.visit(subnode, **kwargs) + + self.symbols = original_symbols + return rv + + body_symbols = inner_visit(node.body) + elif_symbols = inner_visit(node.elif_) + else_symbols = inner_visit(node.else_ or ()) + self.symbols.branch_update([body_symbols, elif_symbols, else_symbols]) + + def visit_Macro(self, node: nodes.Macro, **kwargs: t.Any) -> None: + self.symbols.store(node.name) + + def visit_Import(self, node: nodes.Import, **kwargs: t.Any) -> None: + self.generic_visit(node, **kwargs) + self.symbols.store(node.target) + + def visit_FromImport(self, node: nodes.FromImport, **kwargs: t.Any) -> None: + self.generic_visit(node, **kwargs) + + for name in node.names: + if isinstance(name, tuple): + self.symbols.store(name[1]) + else: + self.symbols.store(name) + + def visit_Assign(self, node: nodes.Assign, **kwargs: t.Any) -> None: + """Visit assignments in the correct order.""" + self.visit(node.node, **kwargs) + self.visit(node.target, **kwargs) + + def visit_For(self, node: nodes.For, **kwargs: t.Any) -> None: + """Visiting stops at for blocks. However the block sequence + is visited as part of the outer scope. + """ + self.visit(node.iter, **kwargs) + + def visit_CallBlock(self, node: nodes.CallBlock, **kwargs: t.Any) -> None: + self.visit(node.call, **kwargs) + + def visit_FilterBlock(self, node: nodes.FilterBlock, **kwargs: t.Any) -> None: + self.visit(node.filter, **kwargs) + + def visit_With(self, node: nodes.With, **kwargs: t.Any) -> None: + for target in node.values: + self.visit(target) + + def visit_AssignBlock(self, node: nodes.AssignBlock, **kwargs: t.Any) -> None: + """Stop visiting at block assigns.""" + self.visit(node.target, **kwargs) + + def visit_Scope(self, node: nodes.Scope, **kwargs: t.Any) -> None: + """Stop visiting at scopes.""" + + def visit_Block(self, node: nodes.Block, **kwargs: t.Any) -> None: + """Stop visiting at blocks.""" + + def visit_OverlayScope(self, node: nodes.OverlayScope, **kwargs: t.Any) -> None: + """Do not visit into overlay scopes.""" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/lexer.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/lexer.py new file mode 100644 index 0000000000000000000000000000000000000000..aff7e9f993792e1ced39c93fc0d39dcb5bdd5fde --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/lexer.py @@ -0,0 +1,866 @@ +"""Implements a Jinja / Python combination lexer. The ``Lexer`` class +is used to do some preprocessing. It filters out invalid operators like +the bitshift operators we don't allow in templates. It separates +template code and python code in expressions. +""" +import re +import typing as t +from ast import literal_eval +from collections import deque +from sys import intern + +from ._identifier import pattern as name_re +from .exceptions import TemplateSyntaxError +from .utils import LRUCache + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +# cache for the lexers. Exists in order to be able to have multiple +# environments with the same lexer +_lexer_cache: t.MutableMapping[t.Tuple, "Lexer"] = LRUCache(50) # type: ignore + +# static regular expressions +whitespace_re = re.compile(r"\s+") +newline_re = re.compile(r"(\r\n|\r|\n)") +string_re = re.compile( + r"('([^'\\]*(?:\\.[^'\\]*)*)'" r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S +) +integer_re = re.compile( + r""" + ( + 0b(_?[0-1])+ # binary + | + 0o(_?[0-7])+ # octal + | + 0x(_?[\da-f])+ # hex + | + [1-9](_?\d)* # decimal + | + 0(_?0)* # decimal zero + ) + """, + re.IGNORECASE | re.VERBOSE, +) +float_re = re.compile( + r""" + (?<!\.) # doesn't start with a . + (\d+_)*\d+ # digits, possibly _ separated + ( + (\.(\d+_)*\d+)? # optional fractional part + e[+\-]?(\d+_)*\d+ # exponent part + | + \.(\d+_)*\d+ # required fractional part + ) + """, + re.IGNORECASE | re.VERBOSE, +) + +# internal the tokens and keep references to them +TOKEN_ADD = intern("add") +TOKEN_ASSIGN = intern("assign") +TOKEN_COLON = intern("colon") +TOKEN_COMMA = intern("comma") +TOKEN_DIV = intern("div") +TOKEN_DOT = intern("dot") +TOKEN_EQ = intern("eq") +TOKEN_FLOORDIV = intern("floordiv") +TOKEN_GT = intern("gt") +TOKEN_GTEQ = intern("gteq") +TOKEN_LBRACE = intern("lbrace") +TOKEN_LBRACKET = intern("lbracket") +TOKEN_LPAREN = intern("lparen") +TOKEN_LT = intern("lt") +TOKEN_LTEQ = intern("lteq") +TOKEN_MOD = intern("mod") +TOKEN_MUL = intern("mul") +TOKEN_NE = intern("ne") +TOKEN_PIPE = intern("pipe") +TOKEN_POW = intern("pow") +TOKEN_RBRACE = intern("rbrace") +TOKEN_RBRACKET = intern("rbracket") +TOKEN_RPAREN = intern("rparen") +TOKEN_SEMICOLON = intern("semicolon") +TOKEN_SUB = intern("sub") +TOKEN_TILDE = intern("tilde") +TOKEN_WHITESPACE = intern("whitespace") +TOKEN_FLOAT = intern("float") +TOKEN_INTEGER = intern("integer") +TOKEN_NAME = intern("name") +TOKEN_STRING = intern("string") +TOKEN_OPERATOR = intern("operator") +TOKEN_BLOCK_BEGIN = intern("block_begin") +TOKEN_BLOCK_END = intern("block_end") +TOKEN_VARIABLE_BEGIN = intern("variable_begin") +TOKEN_VARIABLE_END = intern("variable_end") +TOKEN_RAW_BEGIN = intern("raw_begin") +TOKEN_RAW_END = intern("raw_end") +TOKEN_COMMENT_BEGIN = intern("comment_begin") +TOKEN_COMMENT_END = intern("comment_end") +TOKEN_COMMENT = intern("comment") +TOKEN_LINESTATEMENT_BEGIN = intern("linestatement_begin") +TOKEN_LINESTATEMENT_END = intern("linestatement_end") +TOKEN_LINECOMMENT_BEGIN = intern("linecomment_begin") +TOKEN_LINECOMMENT_END = intern("linecomment_end") +TOKEN_LINECOMMENT = intern("linecomment") +TOKEN_DATA = intern("data") +TOKEN_INITIAL = intern("initial") +TOKEN_EOF = intern("eof") + +# bind operators to token types +operators = { + "+": TOKEN_ADD, + "-": TOKEN_SUB, + "/": TOKEN_DIV, + "//": TOKEN_FLOORDIV, + "*": TOKEN_MUL, + "%": TOKEN_MOD, + "**": TOKEN_POW, + "~": TOKEN_TILDE, + "[": TOKEN_LBRACKET, + "]": TOKEN_RBRACKET, + "(": TOKEN_LPAREN, + ")": TOKEN_RPAREN, + "{": TOKEN_LBRACE, + "}": TOKEN_RBRACE, + "==": TOKEN_EQ, + "!=": TOKEN_NE, + ">": TOKEN_GT, + ">=": TOKEN_GTEQ, + "<": TOKEN_LT, + "<=": TOKEN_LTEQ, + "=": TOKEN_ASSIGN, + ".": TOKEN_DOT, + ":": TOKEN_COLON, + "|": TOKEN_PIPE, + ",": TOKEN_COMMA, + ";": TOKEN_SEMICOLON, +} + +reverse_operators = {v: k for k, v in operators.items()} +assert len(operators) == len(reverse_operators), "operators dropped" +operator_re = re.compile( + f"({'|'.join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))})" +) + +ignored_tokens = frozenset( + [ + TOKEN_COMMENT_BEGIN, + TOKEN_COMMENT, + TOKEN_COMMENT_END, + TOKEN_WHITESPACE, + TOKEN_LINECOMMENT_BEGIN, + TOKEN_LINECOMMENT_END, + TOKEN_LINECOMMENT, + ] +) +ignore_if_empty = frozenset( + [TOKEN_WHITESPACE, TOKEN_DATA, TOKEN_COMMENT, TOKEN_LINECOMMENT] +) + + +def _describe_token_type(token_type: str) -> str: + if token_type in reverse_operators: + return reverse_operators[token_type] + + return { + TOKEN_COMMENT_BEGIN: "begin of comment", + TOKEN_COMMENT_END: "end of comment", + TOKEN_COMMENT: "comment", + TOKEN_LINECOMMENT: "comment", + TOKEN_BLOCK_BEGIN: "begin of statement block", + TOKEN_BLOCK_END: "end of statement block", + TOKEN_VARIABLE_BEGIN: "begin of print statement", + TOKEN_VARIABLE_END: "end of print statement", + TOKEN_LINESTATEMENT_BEGIN: "begin of line statement", + TOKEN_LINESTATEMENT_END: "end of line statement", + TOKEN_DATA: "template data / text", + TOKEN_EOF: "end of template", + }.get(token_type, token_type) + + +def describe_token(token: "Token") -> str: + """Returns a description of the token.""" + if token.type == TOKEN_NAME: + return token.value + + return _describe_token_type(token.type) + + +def describe_token_expr(expr: str) -> str: + """Like `describe_token` but for token expressions.""" + if ":" in expr: + type, value = expr.split(":", 1) + + if type == TOKEN_NAME: + return value + else: + type = expr + + return _describe_token_type(type) + + +def count_newlines(value: str) -> int: + """Count the number of newline characters in the string. This is + useful for extensions that filter a stream. + """ + return len(newline_re.findall(value)) + + +def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]: + """Compiles all the rules from the environment into a list of rules.""" + e = re.escape + rules = [ + ( + len(environment.comment_start_string), + TOKEN_COMMENT_BEGIN, + e(environment.comment_start_string), + ), + ( + len(environment.block_start_string), + TOKEN_BLOCK_BEGIN, + e(environment.block_start_string), + ), + ( + len(environment.variable_start_string), + TOKEN_VARIABLE_BEGIN, + e(environment.variable_start_string), + ), + ] + + if environment.line_statement_prefix is not None: + rules.append( + ( + len(environment.line_statement_prefix), + TOKEN_LINESTATEMENT_BEGIN, + r"^[ \t\v]*" + e(environment.line_statement_prefix), + ) + ) + if environment.line_comment_prefix is not None: + rules.append( + ( + len(environment.line_comment_prefix), + TOKEN_LINECOMMENT_BEGIN, + r"(?:^|(?<=\S))[^\S\r\n]*" + e(environment.line_comment_prefix), + ) + ) + + return [x[1:] for x in sorted(rules, reverse=True)] + + +class Failure: + """Class that raises a `TemplateSyntaxError` if called. + Used by the `Lexer` to specify known errors. + """ + + def __init__( + self, message: str, cls: t.Type[TemplateSyntaxError] = TemplateSyntaxError + ) -> None: + self.message = message + self.error_class = cls + + def __call__(self, lineno: int, filename: str) -> "te.NoReturn": + raise self.error_class(self.message, lineno, filename) + + +class Token(t.NamedTuple): + lineno: int + type: str + value: str + + def __str__(self) -> str: + return describe_token(self) + + def test(self, expr: str) -> bool: + """Test a token against a token expression. This can either be a + token type or ``'token_type:token_value'``. This can only test + against string values and types. + """ + # here we do a regular string equality check as test_any is usually + # passed an iterable of not interned strings. + if self.type == expr: + return True + + if ":" in expr: + return expr.split(":", 1) == [self.type, self.value] + + return False + + def test_any(self, *iterable: str) -> bool: + """Test against multiple token expressions.""" + return any(self.test(expr) for expr in iterable) + + +class TokenStreamIterator: + """The iterator for tokenstreams. Iterate over the stream + until the eof token is reached. + """ + + def __init__(self, stream: "TokenStream") -> None: + self.stream = stream + + def __iter__(self) -> "TokenStreamIterator": + return self + + def __next__(self) -> Token: + token = self.stream.current + + if token.type is TOKEN_EOF: + self.stream.close() + raise StopIteration + + next(self.stream) + return token + + +class TokenStream: + """A token stream is an iterable that yields :class:`Token`\\s. The + parser however does not iterate over it but calls :meth:`next` to go + one token ahead. The current active token is stored as :attr:`current`. + """ + + def __init__( + self, + generator: t.Iterable[Token], + name: t.Optional[str], + filename: t.Optional[str], + ): + self._iter = iter(generator) + self._pushed: "te.Deque[Token]" = deque() + self.name = name + self.filename = filename + self.closed = False + self.current = Token(1, TOKEN_INITIAL, "") + next(self) + + def __iter__(self) -> TokenStreamIterator: + return TokenStreamIterator(self) + + def __bool__(self) -> bool: + return bool(self._pushed) or self.current.type is not TOKEN_EOF + + @property + def eos(self) -> bool: + """Are we at the end of the stream?""" + return not self + + def push(self, token: Token) -> None: + """Push a token back to the stream.""" + self._pushed.append(token) + + def look(self) -> Token: + """Look at the next token.""" + old_token = next(self) + result = self.current + self.push(result) + self.current = old_token + return result + + def skip(self, n: int = 1) -> None: + """Got n tokens ahead.""" + for _ in range(n): + next(self) + + def next_if(self, expr: str) -> t.Optional[Token]: + """Perform the token test and return the token if it matched. + Otherwise the return value is `None`. + """ + if self.current.test(expr): + return next(self) + + return None + + def skip_if(self, expr: str) -> bool: + """Like :meth:`next_if` but only returns `True` or `False`.""" + return self.next_if(expr) is not None + + def __next__(self) -> Token: + """Go one token ahead and return the old one. + + Use the built-in :func:`next` instead of calling this directly. + """ + rv = self.current + + if self._pushed: + self.current = self._pushed.popleft() + elif self.current.type is not TOKEN_EOF: + try: + self.current = next(self._iter) + except StopIteration: + self.close() + + return rv + + def close(self) -> None: + """Close the stream.""" + self.current = Token(self.current.lineno, TOKEN_EOF, "") + self._iter = iter(()) + self.closed = True + + def expect(self, expr: str) -> Token: + """Expect a given token type and return it. This accepts the same + argument as :meth:`jinja2.lexer.Token.test`. + """ + if not self.current.test(expr): + expr = describe_token_expr(expr) + + if self.current.type is TOKEN_EOF: + raise TemplateSyntaxError( + f"unexpected end of template, expected {expr!r}.", + self.current.lineno, + self.name, + self.filename, + ) + + raise TemplateSyntaxError( + f"expected token {expr!r}, got {describe_token(self.current)!r}", + self.current.lineno, + self.name, + self.filename, + ) + + return next(self) + + +def get_lexer(environment: "Environment") -> "Lexer": + """Return a lexer which is probably cached.""" + key = ( + environment.block_start_string, + environment.block_end_string, + environment.variable_start_string, + environment.variable_end_string, + environment.comment_start_string, + environment.comment_end_string, + environment.line_statement_prefix, + environment.line_comment_prefix, + environment.trim_blocks, + environment.lstrip_blocks, + environment.newline_sequence, + environment.keep_trailing_newline, + ) + lexer = _lexer_cache.get(key) + + if lexer is None: + _lexer_cache[key] = lexer = Lexer(environment) + + return lexer + + +class OptionalLStrip(tuple): + """A special tuple for marking a point in the state that can have + lstrip applied. + """ + + __slots__ = () + + # Even though it looks like a no-op, creating instances fails + # without this. + def __new__(cls, *members, **kwargs): # type: ignore + return super().__new__(cls, members) + + +class _Rule(t.NamedTuple): + pattern: t.Pattern[str] + tokens: t.Union[str, t.Tuple[str, ...], t.Tuple[Failure]] + command: t.Optional[str] + + +class Lexer: + """Class that implements a lexer for a given environment. Automatically + created by the environment class, usually you don't have to do that. + + Note that the lexer is not automatically bound to an environment. + Multiple environments can share the same lexer. + """ + + def __init__(self, environment: "Environment") -> None: + # shortcuts + e = re.escape + + def c(x: str) -> t.Pattern[str]: + return re.compile(x, re.M | re.S) + + # lexing rules for tags + tag_rules: t.List[_Rule] = [ + _Rule(whitespace_re, TOKEN_WHITESPACE, None), + _Rule(float_re, TOKEN_FLOAT, None), + _Rule(integer_re, TOKEN_INTEGER, None), + _Rule(name_re, TOKEN_NAME, None), + _Rule(string_re, TOKEN_STRING, None), + _Rule(operator_re, TOKEN_OPERATOR, None), + ] + + # assemble the root lexing rule. because "|" is ungreedy + # we have to sort by length so that the lexer continues working + # as expected when we have parsing rules like <% for block and + # <%= for variables. (if someone wants asp like syntax) + # variables are just part of the rules if variable processing + # is required. + root_tag_rules = compile_rules(environment) + + block_start_re = e(environment.block_start_string) + block_end_re = e(environment.block_end_string) + comment_end_re = e(environment.comment_end_string) + variable_end_re = e(environment.variable_end_string) + + # block suffix if trimming is enabled + block_suffix_re = "\\n?" if environment.trim_blocks else "" + + self.lstrip_blocks = environment.lstrip_blocks + + self.newline_sequence = environment.newline_sequence + self.keep_trailing_newline = environment.keep_trailing_newline + + root_raw_re = ( + rf"(?P<raw_begin>{block_start_re}(\-|\+|)\s*raw\s*" + rf"(?:\-{block_end_re}\s*|{block_end_re}))" + ) + root_parts_re = "|".join( + [root_raw_re] + [rf"(?P<{n}>{r}(\-|\+|))" for n, r in root_tag_rules] + ) + + # global lexing rules + self.rules: t.Dict[str, t.List[_Rule]] = { + "root": [ + # directives + _Rule( + c(rf"(.*?)(?:{root_parts_re})"), + OptionalLStrip(TOKEN_DATA, "#bygroup"), # type: ignore + "#bygroup", + ), + # data + _Rule(c(".+"), TOKEN_DATA, None), + ], + # comments + TOKEN_COMMENT_BEGIN: [ + _Rule( + c( + rf"(.*?)((?:\+{comment_end_re}|\-{comment_end_re}\s*" + rf"|{comment_end_re}{block_suffix_re}))" + ), + (TOKEN_COMMENT, TOKEN_COMMENT_END), + "#pop", + ), + _Rule(c(r"(.)"), (Failure("Missing end of comment tag"),), None), + ], + # blocks + TOKEN_BLOCK_BEGIN: [ + _Rule( + c( + rf"(?:\+{block_end_re}|\-{block_end_re}\s*" + rf"|{block_end_re}{block_suffix_re})" + ), + TOKEN_BLOCK_END, + "#pop", + ), + ] + + tag_rules, + # variables + TOKEN_VARIABLE_BEGIN: [ + _Rule( + c(rf"\-{variable_end_re}\s*|{variable_end_re}"), + TOKEN_VARIABLE_END, + "#pop", + ) + ] + + tag_rules, + # raw block + TOKEN_RAW_BEGIN: [ + _Rule( + c( + rf"(.*?)((?:{block_start_re}(\-|\+|))\s*endraw\s*" + rf"(?:\+{block_end_re}|\-{block_end_re}\s*" + rf"|{block_end_re}{block_suffix_re}))" + ), + OptionalLStrip(TOKEN_DATA, TOKEN_RAW_END), # type: ignore + "#pop", + ), + _Rule(c(r"(.)"), (Failure("Missing end of raw directive"),), None), + ], + # line statements + TOKEN_LINESTATEMENT_BEGIN: [ + _Rule(c(r"\s*(\n|$)"), TOKEN_LINESTATEMENT_END, "#pop") + ] + + tag_rules, + # line comments + TOKEN_LINECOMMENT_BEGIN: [ + _Rule( + c(r"(.*?)()(?=\n|$)"), + (TOKEN_LINECOMMENT, TOKEN_LINECOMMENT_END), + "#pop", + ) + ], + } + + def _normalize_newlines(self, value: str) -> str: + """Replace all newlines with the configured sequence in strings + and template data. + """ + return newline_re.sub(self.newline_sequence, value) + + def tokenize( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Calls tokeniter + tokenize and wraps it in a token stream.""" + stream = self.tokeniter(source, name, filename, state) + return TokenStream(self.wrap(stream, name, filename), name, filename) + + def wrap( + self, + stream: t.Iterable[t.Tuple[int, str, str]], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[Token]: + """This is called with the stream as returned by `tokenize` and wraps + every token in a :class:`Token` and converts the value. + """ + for lineno, token, value_str in stream: + if token in ignored_tokens: + continue + + value: t.Any = value_str + + if token == TOKEN_LINESTATEMENT_BEGIN: + token = TOKEN_BLOCK_BEGIN + elif token == TOKEN_LINESTATEMENT_END: + token = TOKEN_BLOCK_END + # we are not interested in those tokens in the parser + elif token in (TOKEN_RAW_BEGIN, TOKEN_RAW_END): + continue + elif token == TOKEN_DATA: + value = self._normalize_newlines(value_str) + elif token == "keyword": + token = value_str + elif token == TOKEN_NAME: + value = value_str + + if not value.isidentifier(): + raise TemplateSyntaxError( + "Invalid character in identifier", lineno, name, filename + ) + elif token == TOKEN_STRING: + # try to unescape string + try: + value = ( + self._normalize_newlines(value_str[1:-1]) + .encode("ascii", "backslashreplace") + .decode("unicode-escape") + ) + except Exception as e: + msg = str(e).split(":")[-1].strip() + raise TemplateSyntaxError(msg, lineno, name, filename) from e + elif token == TOKEN_INTEGER: + value = int(value_str.replace("_", ""), 0) + elif token == TOKEN_FLOAT: + # remove all "_" first to support more Python versions + value = literal_eval(value_str.replace("_", "")) + elif token == TOKEN_OPERATOR: + token = operators[value_str] + + yield Token(lineno, token, value) + + def tokeniter( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """This method tokenizes the text and returns the tokens in a + generator. Use this method if you just want to tokenize a template. + + .. versionchanged:: 3.0 + Only ``\\n``, ``\\r\\n`` and ``\\r`` are treated as line + breaks. + """ + lines = newline_re.split(source)[::2] + + if not self.keep_trailing_newline and lines[-1] == "": + del lines[-1] + + source = "\n".join(lines) + pos = 0 + lineno = 1 + stack = ["root"] + + if state is not None and state != "root": + assert state in ("variable", "block"), "invalid state" + stack.append(state + "_begin") + + statetokens = self.rules[stack[-1]] + source_length = len(source) + balancing_stack: t.List[str] = [] + newlines_stripped = 0 + line_starting = True + + while True: + # tokenizer loop + for regex, tokens, new_state in statetokens: + m = regex.match(source, pos) + + # if no match we try again with the next rule + if m is None: + continue + + # we only match blocks and variables if braces / parentheses + # are balanced. continue parsing with the lower rule which + # is the operator rule. do this only if the end tags look + # like operators + if balancing_stack and tokens in ( + TOKEN_VARIABLE_END, + TOKEN_BLOCK_END, + TOKEN_LINESTATEMENT_END, + ): + continue + + # tuples support more options + if isinstance(tokens, tuple): + groups: t.Sequence[str] = m.groups() + + if isinstance(tokens, OptionalLStrip): + # Rule supports lstrip. Match will look like + # text, block type, whitespace control, type, control, ... + text = groups[0] + # Skipping the text and first type, every other group is the + # whitespace control for each type. One of the groups will be + # -, +, or empty string instead of None. + strip_sign = next(g for g in groups[2::2] if g is not None) + + if strip_sign == "-": + # Strip all whitespace between the text and the tag. + stripped = text.rstrip() + newlines_stripped = text[len(stripped) :].count("\n") + groups = [stripped, *groups[1:]] + elif ( + # Not marked for preserving whitespace. + strip_sign != "+" + # lstrip is enabled. + and self.lstrip_blocks + # Not a variable expression. + and not m.groupdict().get(TOKEN_VARIABLE_BEGIN) + ): + # The start of text between the last newline and the tag. + l_pos = text.rfind("\n") + 1 + + if l_pos > 0 or line_starting: + # If there's only whitespace between the newline and the + # tag, strip it. + if whitespace_re.fullmatch(text, l_pos): + groups = [text[:l_pos], *groups[1:]] + + for idx, token in enumerate(tokens): + # failure group + if token.__class__ is Failure: + raise token(lineno, filename) + # bygroup is a bit more complex, in that case we + # yield for the current token the first named + # group that matched + elif token == "#bygroup": + for key, value in m.groupdict().items(): + if value is not None: + yield lineno, key, value + lineno += value.count("\n") + break + else: + raise RuntimeError( + f"{regex!r} wanted to resolve the token dynamically" + " but no group matched" + ) + # normal group + else: + data = groups[idx] + + if data or token not in ignore_if_empty: + yield lineno, token, data + + lineno += data.count("\n") + newlines_stripped + newlines_stripped = 0 + + # strings as token just are yielded as it. + else: + data = m.group() + + # update brace/parentheses balance + if tokens == TOKEN_OPERATOR: + if data == "{": + balancing_stack.append("}") + elif data == "(": + balancing_stack.append(")") + elif data == "[": + balancing_stack.append("]") + elif data in ("}", ")", "]"): + if not balancing_stack: + raise TemplateSyntaxError( + f"unexpected '{data}'", lineno, name, filename + ) + + expected_op = balancing_stack.pop() + + if expected_op != data: + raise TemplateSyntaxError( + f"unexpected '{data}', expected '{expected_op}'", + lineno, + name, + filename, + ) + + # yield items + if data or tokens not in ignore_if_empty: + yield lineno, tokens, data + + lineno += data.count("\n") + + line_starting = m.group()[-1:] == "\n" + # fetch new position into new variable so that we can check + # if there is a internal parsing error which would result + # in an infinite loop + pos2 = m.end() + + # handle state changes + if new_state is not None: + # remove the uppermost state + if new_state == "#pop": + stack.pop() + # resolve the new state by group checking + elif new_state == "#bygroup": + for key, value in m.groupdict().items(): + if value is not None: + stack.append(key) + break + else: + raise RuntimeError( + f"{regex!r} wanted to resolve the new state dynamically" + f" but no group matched" + ) + # direct state name given + else: + stack.append(new_state) + + statetokens = self.rules[stack[-1]] + # we are still at the same position and no stack change. + # this means a loop without break condition, avoid that and + # raise error + elif pos2 == pos: + raise RuntimeError( + f"{regex!r} yielded empty string without stack change" + ) + + # publish new function and start again + pos = pos2 + break + # if loop terminated without break we haven't found a single match + # either we are at the end of the file or we have a problem + else: + # end of text + if pos >= source_length: + return + + # something went wrong + raise TemplateSyntaxError( + f"unexpected char {source[pos]!r} at {pos}", lineno, name, filename + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/loaders.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/loaders.py new file mode 100644 index 0000000000000000000000000000000000000000..d2f98093cde425fad2c4bbf2a07e383fce5e4a38 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/loaders.py @@ -0,0 +1,661 @@ +"""API and implementations for loading templates from different data +sources. +""" +import importlib.util +import os +import posixpath +import sys +import typing as t +import weakref +import zipimport +from collections import abc +from hashlib import sha1 +from importlib import import_module +from types import ModuleType + +from .exceptions import TemplateNotFound +from .utils import internalcode +from .utils import open_if_exists + +if t.TYPE_CHECKING: + from .environment import Environment + from .environment import Template + + +def split_template_path(template: str) -> t.List[str]: + """Split a path into segments and perform a sanity check. If it detects + '..' in the path it will raise a `TemplateNotFound` error. + """ + pieces = [] + for piece in template.split("/"): + if ( + os.path.sep in piece + or (os.path.altsep and os.path.altsep in piece) + or piece == os.path.pardir + ): + raise TemplateNotFound(template) + elif piece and piece != ".": + pieces.append(piece) + return pieces + + +class BaseLoader: + """Baseclass for all loaders. Subclass this and override `get_source` to + implement a custom loading mechanism. The environment provides a + `get_template` method that calls the loader's `load` method to get the + :class:`Template` object. + + A very basic example for a loader that looks up templates on the file + system could look like this:: + + from jinja2 import BaseLoader, TemplateNotFound + from os.path import join, exists, getmtime + + class MyLoader(BaseLoader): + + def __init__(self, path): + self.path = path + + def get_source(self, environment, template): + path = join(self.path, template) + if not exists(path): + raise TemplateNotFound(template) + mtime = getmtime(path) + with open(path) as f: + source = f.read() + return source, path, lambda: mtime == getmtime(path) + """ + + #: if set to `False` it indicates that the loader cannot provide access + #: to the source of templates. + #: + #: .. versionadded:: 2.4 + has_source_access = True + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + """Get the template source, filename and reload helper for a template. + It's passed the environment and template name and has to return a + tuple in the form ``(source, filename, uptodate)`` or raise a + `TemplateNotFound` error if it can't locate the template. + + The source part of the returned tuple must be the source of the + template as a string. The filename should be the name of the + file on the filesystem if it was loaded from there, otherwise + ``None``. The filename is used by Python for the tracebacks + if no loader extension is used. + + The last item in the tuple is the `uptodate` function. If auto + reloading is enabled it's always called to check if the template + changed. No arguments are passed so the function must store the + old state somewhere (for example in a closure). If it returns `False` + the template will be reloaded. + """ + if not self.has_source_access: + raise RuntimeError( + f"{type(self).__name__} cannot provide access to the source" + ) + raise TemplateNotFound(template) + + def list_templates(self) -> t.List[str]: + """Iterates over all templates. If the loader does not support that + it should raise a :exc:`TypeError` which is the default behavior. + """ + raise TypeError("this loader cannot iterate over all templates") + + @internalcode + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + """Loads a template. This method looks up the template in the cache + or loads one by calling :meth:`get_source`. Subclasses should not + override this method as loaders working on collections of other + loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`) + will not call this method but `get_source` directly. + """ + code = None + if globals is None: + globals = {} + + # first we try to get the source for this template together + # with the filename and the uptodate function. + source, filename, uptodate = self.get_source(environment, name) + + # try to load the code from the bytecode cache if there is a + # bytecode cache configured. + bcc = environment.bytecode_cache + if bcc is not None: + bucket = bcc.get_bucket(environment, name, filename, source) + code = bucket.code + + # if we don't have code so far (not cached, no longer up to + # date) etc. we compile the template + if code is None: + code = environment.compile(source, name, filename) + + # if the bytecode cache is available and the bucket doesn't + # have a code so far, we give the bucket the new code and put + # it back to the bytecode cache. + if bcc is not None and bucket.code is None: + bucket.code = code + bcc.set_bucket(bucket) + + return environment.template_class.from_code( + environment, code, globals, uptodate + ) + + +class FileSystemLoader(BaseLoader): + """Load templates from a directory in the file system. + + The path can be relative or absolute. Relative paths are relative to + the current working directory. + + .. code-block:: python + + loader = FileSystemLoader("templates") + + A list of paths can be given. The directories will be searched in + order, stopping at the first matching template. + + .. code-block:: python + + loader = FileSystemLoader(["/override/templates", "/default/templates"]) + + :param searchpath: A path, or list of paths, to the directory that + contains the templates. + :param encoding: Use this encoding to read the text from template + files. + :param followlinks: Follow symbolic links in the path. + + .. versionchanged:: 2.8 + Added the ``followlinks`` parameter. + """ + + def __init__( + self, + searchpath: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]], + encoding: str = "utf-8", + followlinks: bool = False, + ) -> None: + if not isinstance(searchpath, abc.Iterable) or isinstance(searchpath, str): + searchpath = [searchpath] + + self.searchpath = [os.fspath(p) for p in searchpath] + self.encoding = encoding + self.followlinks = followlinks + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, str, t.Callable[[], bool]]: + pieces = split_template_path(template) + for searchpath in self.searchpath: + # Use posixpath even on Windows to avoid "drive:" or UNC + # segments breaking out of the search directory. + filename = posixpath.join(searchpath, *pieces) + f = open_if_exists(filename) + if f is None: + continue + try: + contents = f.read().decode(self.encoding) + finally: + f.close() + + mtime = os.path.getmtime(filename) + + def uptodate() -> bool: + try: + return os.path.getmtime(filename) == mtime + except OSError: + return False + + # Use normpath to convert Windows altsep to sep. + return contents, os.path.normpath(filename), uptodate + raise TemplateNotFound(template) + + def list_templates(self) -> t.List[str]: + found = set() + for searchpath in self.searchpath: + walk_dir = os.walk(searchpath, followlinks=self.followlinks) + for dirpath, _, filenames in walk_dir: + for filename in filenames: + template = ( + os.path.join(dirpath, filename)[len(searchpath) :] + .strip(os.path.sep) + .replace(os.path.sep, "/") + ) + if template[:2] == "./": + template = template[2:] + if template not in found: + found.add(template) + return sorted(found) + + +class PackageLoader(BaseLoader): + """Load templates from a directory in a Python package. + + :param package_name: Import name of the package that contains the + template directory. + :param package_path: Directory within the imported package that + contains the templates. + :param encoding: Encoding of template files. + + The following example looks up templates in the ``pages`` directory + within the ``project.ui`` package. + + .. code-block:: python + + loader = PackageLoader("project.ui", "pages") + + Only packages installed as directories (standard pip behavior) or + zip/egg files (less common) are supported. The Python API for + introspecting data in packages is too limited to support other + installation methods the way this loader requires. + + There is limited support for :pep:`420` namespace packages. The + template directory is assumed to only be in one namespace + contributor. Zip files contributing to a namespace are not + supported. + + .. versionchanged:: 3.0 + No longer uses ``setuptools`` as a dependency. + + .. versionchanged:: 3.0 + Limited PEP 420 namespace package support. + """ + + def __init__( + self, + package_name: str, + package_path: "str" = "templates", + encoding: str = "utf-8", + ) -> None: + package_path = os.path.normpath(package_path).rstrip(os.path.sep) + + # normpath preserves ".", which isn't valid in zip paths. + if package_path == os.path.curdir: + package_path = "" + elif package_path[:2] == os.path.curdir + os.path.sep: + package_path = package_path[2:] + + self.package_path = package_path + self.package_name = package_name + self.encoding = encoding + + # Make sure the package exists. This also makes namespace + # packages work, otherwise get_loader returns None. + import_module(package_name) + spec = importlib.util.find_spec(package_name) + assert spec is not None, "An import spec was not found for the package." + loader = spec.loader + assert loader is not None, "A loader was not found for the package." + self._loader = loader + self._archive = None + template_root = None + + if isinstance(loader, zipimport.zipimporter): + self._archive = loader.archive + pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore + template_root = os.path.join(pkgdir, package_path).rstrip(os.path.sep) + else: + roots: t.List[str] = [] + + # One element for regular packages, multiple for namespace + # packages, or None for single module file. + if spec.submodule_search_locations: + roots.extend(spec.submodule_search_locations) + # A single module file, use the parent directory instead. + elif spec.origin is not None: + roots.append(os.path.dirname(spec.origin)) + + for root in roots: + root = os.path.join(root, package_path) + + if os.path.isdir(root): + template_root = root + break + + if template_root is None: + raise ValueError( + f"The {package_name!r} package was not installed in a" + " way that PackageLoader understands." + ) + + self._template_root = template_root + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]: + # Use posixpath even on Windows to avoid "drive:" or UNC + # segments breaking out of the search directory. Use normpath to + # convert Windows altsep to sep. + p = os.path.normpath( + posixpath.join(self._template_root, *split_template_path(template)) + ) + up_to_date: t.Optional[t.Callable[[], bool]] + + if self._archive is None: + # Package is a directory. + if not os.path.isfile(p): + raise TemplateNotFound(template) + + with open(p, "rb") as f: + source = f.read() + + mtime = os.path.getmtime(p) + + def up_to_date() -> bool: + return os.path.isfile(p) and os.path.getmtime(p) == mtime + + else: + # Package is a zip file. + try: + source = self._loader.get_data(p) # type: ignore + except OSError as e: + raise TemplateNotFound(template) from e + + # Could use the zip's mtime for all template mtimes, but + # would need to safely reload the module if it's out of + # date, so just report it as always current. + up_to_date = None + + return source.decode(self.encoding), p, up_to_date + + def list_templates(self) -> t.List[str]: + results: t.List[str] = [] + + if self._archive is None: + # Package is a directory. + offset = len(self._template_root) + + for dirpath, _, filenames in os.walk(self._template_root): + dirpath = dirpath[offset:].lstrip(os.path.sep) + results.extend( + os.path.join(dirpath, name).replace(os.path.sep, "/") + for name in filenames + ) + else: + if not hasattr(self._loader, "_files"): + raise TypeError( + "This zip import does not have the required" + " metadata to list templates." + ) + + # Package is a zip file. + prefix = ( + self._template_root[len(self._archive) :].lstrip(os.path.sep) + + os.path.sep + ) + offset = len(prefix) + + for name in self._loader._files.keys(): # type: ignore + # Find names under the templates directory that aren't directories. + if name.startswith(prefix) and name[-1] != os.path.sep: + results.append(name[offset:].replace(os.path.sep, "/")) + + results.sort() + return results + + +class DictLoader(BaseLoader): + """Loads a template from a Python dict mapping template names to + template source. This loader is useful for unittesting: + + >>> loader = DictLoader({'index.html': 'source here'}) + + Because auto reloading is rarely useful this is disabled per default. + """ + + def __init__(self, mapping: t.Mapping[str, str]) -> None: + self.mapping = mapping + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, None, t.Callable[[], bool]]: + if template in self.mapping: + source = self.mapping[template] + return source, None, lambda: source == self.mapping.get(template) + raise TemplateNotFound(template) + + def list_templates(self) -> t.List[str]: + return sorted(self.mapping) + + +class FunctionLoader(BaseLoader): + """A loader that is passed a function which does the loading. The + function receives the name of the template and has to return either + a string with the template source, a tuple in the form ``(source, + filename, uptodatefunc)`` or `None` if the template does not exist. + + >>> def load_template(name): + ... if name == 'index.html': + ... return '...' + ... + >>> loader = FunctionLoader(load_template) + + The `uptodatefunc` is a function that is called if autoreload is enabled + and has to return `True` if the template is still up to date. For more + details have a look at :meth:`BaseLoader.get_source` which has the same + return value. + """ + + def __init__( + self, + load_func: t.Callable[ + [str], + t.Optional[ + t.Union[ + str, t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]] + ] + ], + ], + ) -> None: + self.load_func = load_func + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + rv = self.load_func(template) + + if rv is None: + raise TemplateNotFound(template) + + if isinstance(rv, str): + return rv, None, None + + return rv + + +class PrefixLoader(BaseLoader): + """A loader that is passed a dict of loaders where each loader is bound + to a prefix. The prefix is delimited from the template by a slash per + default, which can be changed by setting the `delimiter` argument to + something else:: + + loader = PrefixLoader({ + 'app1': PackageLoader('mypackage.app1'), + 'app2': PackageLoader('mypackage.app2') + }) + + By loading ``'app1/index.html'`` the file from the app1 package is loaded, + by loading ``'app2/index.html'`` the file from the second. + """ + + def __init__( + self, mapping: t.Mapping[str, BaseLoader], delimiter: str = "/" + ) -> None: + self.mapping = mapping + self.delimiter = delimiter + + def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]: + try: + prefix, name = template.split(self.delimiter, 1) + loader = self.mapping[prefix] + except (ValueError, KeyError) as e: + raise TemplateNotFound(template) from e + return loader, name + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + loader, name = self.get_loader(template) + try: + return loader.get_source(environment, name) + except TemplateNotFound as e: + # re-raise the exception with the correct filename here. + # (the one that includes the prefix) + raise TemplateNotFound(template) from e + + @internalcode + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + loader, local_name = self.get_loader(name) + try: + return loader.load(environment, local_name, globals) + except TemplateNotFound as e: + # re-raise the exception with the correct filename here. + # (the one that includes the prefix) + raise TemplateNotFound(name) from e + + def list_templates(self) -> t.List[str]: + result = [] + for prefix, loader in self.mapping.items(): + for template in loader.list_templates(): + result.append(prefix + self.delimiter + template) + return result + + +class ChoiceLoader(BaseLoader): + """This loader works like the `PrefixLoader` just that no prefix is + specified. If a template could not be found by one loader the next one + is tried. + + >>> loader = ChoiceLoader([ + ... FileSystemLoader('/path/to/user/templates'), + ... FileSystemLoader('/path/to/system/templates') + ... ]) + + This is useful if you want to allow users to override builtin templates + from a different location. + """ + + def __init__(self, loaders: t.Sequence[BaseLoader]) -> None: + self.loaders = loaders + + def get_source( + self, environment: "Environment", template: str + ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + for loader in self.loaders: + try: + return loader.get_source(environment, template) + except TemplateNotFound: + pass + raise TemplateNotFound(template) + + @internalcode + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + for loader in self.loaders: + try: + return loader.load(environment, name, globals) + except TemplateNotFound: + pass + raise TemplateNotFound(name) + + def list_templates(self) -> t.List[str]: + found = set() + for loader in self.loaders: + found.update(loader.list_templates()) + return sorted(found) + + +class _TemplateModule(ModuleType): + """Like a normal module but with support for weak references""" + + +class ModuleLoader(BaseLoader): + """This loader loads templates from precompiled templates. + + Example usage: + + >>> loader = ChoiceLoader([ + ... ModuleLoader('/path/to/compiled/templates'), + ... FileSystemLoader('/path/to/templates') + ... ]) + + Templates can be precompiled with :meth:`Environment.compile_templates`. + """ + + has_source_access = False + + def __init__( + self, path: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]] + ) -> None: + package_name = f"_jinja2_module_templates_{id(self):x}" + + # create a fake module that looks for the templates in the + # path given. + mod = _TemplateModule(package_name) + + if not isinstance(path, abc.Iterable) or isinstance(path, str): + path = [path] + + mod.__path__ = [os.fspath(p) for p in path] + + sys.modules[package_name] = weakref.proxy( + mod, lambda x: sys.modules.pop(package_name, None) + ) + + # the only strong reference, the sys.modules entry is weak + # so that the garbage collector can remove it once the + # loader that created it goes out of business. + self.module = mod + self.package_name = package_name + + @staticmethod + def get_template_key(name: str) -> str: + return "tmpl_" + sha1(name.encode("utf-8")).hexdigest() + + @staticmethod + def get_module_filename(name: str) -> str: + return ModuleLoader.get_template_key(name) + ".py" + + @internalcode + def load( + self, + environment: "Environment", + name: str, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> "Template": + key = self.get_template_key(name) + module = f"{self.package_name}.{key}" + mod = getattr(self.module, module, None) + + if mod is None: + try: + mod = __import__(module, None, None, ["root"]) + except ImportError as e: + raise TemplateNotFound(name) from e + + # remove the entry from sys.modules, we only want the attribute + # on the module object we have stored on the loader. + sys.modules.pop(module, None) + + if globals is None: + globals = {} + + return environment.template_class.from_module_dict( + environment, mod.__dict__, globals + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/meta.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/meta.py new file mode 100644 index 0000000000000000000000000000000000000000..0057d6eabade5e964e6ef0e3ac8ed2dd67494b03 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/meta.py @@ -0,0 +1,111 @@ +"""Functions that expose information about templates that might be +interesting for introspection. +""" +import typing as t + +from . import nodes +from .compiler import CodeGenerator +from .compiler import Frame + +if t.TYPE_CHECKING: + from .environment import Environment + + +class TrackingCodeGenerator(CodeGenerator): + """We abuse the code generator for introspection.""" + + def __init__(self, environment: "Environment") -> None: + super().__init__(environment, "<introspection>", "<introspection>") + self.undeclared_identifiers: t.Set[str] = set() + + def write(self, x: str) -> None: + """Don't write.""" + + def enter_frame(self, frame: Frame) -> None: + """Remember all undeclared identifiers.""" + super().enter_frame(frame) + + for _, (action, param) in frame.symbols.loads.items(): + if action == "resolve" and param not in self.environment.globals: + self.undeclared_identifiers.add(param) + + +def find_undeclared_variables(ast: nodes.Template) -> t.Set[str]: + """Returns a set of all variables in the AST that will be looked up from + the context at runtime. Because at compile time it's not known which + variables will be used depending on the path the execution takes at + runtime, all variables are returned. + + >>> from jinja2 import Environment, meta + >>> env = Environment() + >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}') + >>> meta.find_undeclared_variables(ast) == {'bar'} + True + + .. admonition:: Implementation + + Internally the code generator is used for finding undeclared variables. + This is good to know because the code generator might raise a + :exc:`TemplateAssertionError` during compilation and as a matter of + fact this function can currently raise that exception as well. + """ + codegen = TrackingCodeGenerator(ast.environment) # type: ignore + codegen.visit(ast) + return codegen.undeclared_identifiers + + +_ref_types = (nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include) +_RefType = t.Union[nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include] + + +def find_referenced_templates(ast: nodes.Template) -> t.Iterator[t.Optional[str]]: + """Finds all the referenced templates from the AST. This will return an + iterator over all the hardcoded template extensions, inclusions and + imports. If dynamic inheritance or inclusion is used, `None` will be + yielded. + + >>> from jinja2 import Environment, meta + >>> env = Environment() + >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}') + >>> list(meta.find_referenced_templates(ast)) + ['layout.html', None] + + This function is useful for dependency tracking. For example if you want + to rebuild parts of the website after a layout template has changed. + """ + template_name: t.Any + + for node in ast.find_all(_ref_types): + template: nodes.Expr = node.template # type: ignore + + if not isinstance(template, nodes.Const): + # a tuple with some non consts in there + if isinstance(template, (nodes.Tuple, nodes.List)): + for template_name in template.items: + # something const, only yield the strings and ignore + # non-string consts that really just make no sense + if isinstance(template_name, nodes.Const): + if isinstance(template_name.value, str): + yield template_name.value + # something dynamic in there + else: + yield None + # something dynamic we don't know about here + else: + yield None + continue + # constant is a basestring, direct template name + if isinstance(template.value, str): + yield template.value + # a tuple or list (latter *should* not happen) made of consts, + # yield the consts that are strings. We could warn here for + # non string values + elif isinstance(node, nodes.Include) and isinstance( + template.value, (tuple, list) + ): + for template_name in template.value: + if isinstance(template_name, str): + yield template_name + # something else we don't care about, we could warn here + else: + yield None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nativetypes.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nativetypes.py new file mode 100644 index 0000000000000000000000000000000000000000..ac0861034821772a50e53bfc3d3ff72e7aad5b1b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nativetypes.py @@ -0,0 +1,130 @@ +import typing as t +from ast import literal_eval +from ast import parse +from itertools import chain +from itertools import islice +from types import GeneratorType + +from . import nodes +from .compiler import CodeGenerator +from .compiler import Frame +from .compiler import has_safe_repr +from .environment import Environment +from .environment import Template + + +def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]: + """Return a native Python type from the list of compiled nodes. If + the result is a single node, its value is returned. Otherwise, the + nodes are concatenated as strings. If the result can be parsed with + :func:`ast.literal_eval`, the parsed value is returned. Otherwise, + the string is returned. + + :param values: Iterable of outputs to concatenate. + """ + head = list(islice(values, 2)) + + if not head: + return None + + if len(head) == 1: + raw = head[0] + if not isinstance(raw, str): + return raw + else: + if isinstance(values, GeneratorType): + values = chain(head, values) + raw = "".join([str(v) for v in values]) + + try: + return literal_eval( + # In Python 3.10+ ast.literal_eval removes leading spaces/tabs + # from the given string. For backwards compatibility we need to + # parse the string ourselves without removing leading spaces/tabs. + parse(raw, mode="eval") + ) + except (ValueError, SyntaxError, MemoryError): + return raw + + +class NativeCodeGenerator(CodeGenerator): + """A code generator which renders Python types by not adding + ``str()`` around output nodes. + """ + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + return value + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + return repr("".join([str(v) for v in group])) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo + ) -> t.Any: + const = node.as_const(frame.eval_ctx) + + if not has_safe_repr(const): + raise nodes.Impossible() + + if isinstance(node, nodes.TemplateData): + return const + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo + ) -> None: + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo + ) -> None: + if finalize.src is not None: + self.write(")") + + +class NativeEnvironment(Environment): + """An environment that renders templates to native Python types.""" + + code_generator_class = NativeCodeGenerator + concat = staticmethod(native_concat) # type: ignore + + +class NativeTemplate(Template): + environment_class = NativeEnvironment + + def render(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Render the template to produce a native Python type. If the + result is a single node, its value is returned. Otherwise, the + nodes are concatenated as strings. If the result can be parsed + with :func:`ast.literal_eval`, the parsed value is returned. + Otherwise, the string is returned. + """ + ctx = self.new_context(dict(*args, **kwargs)) + + try: + return self.environment_class.concat( # type: ignore + self.root_render_func(ctx) # type: ignore + ) + except Exception: + return self.environment.handle_exception() + + async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + if not self.environment.is_async: + raise RuntimeError( + "The environment was not created with async mode enabled." + ) + + ctx = self.new_context(dict(*args, **kwargs)) + + try: + return self.environment_class.concat( # type: ignore + [n async for n in self.root_render_func(ctx)] # type: ignore + ) + except Exception: + return self.environment.handle_exception() + + +NativeEnvironment.template_class = NativeTemplate diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nodes.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..b2f88d9d9c19a2cb5d03b0158c743c6b947a29ea --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/nodes.py @@ -0,0 +1,1204 @@ +"""AST nodes generated by the parser for the compiler. Also provides +some node tree helper functions used by the parser and compiler in order +to normalize nodes. +""" +import inspect +import operator +import typing as t +from collections import deque + +from markupsafe import Markup + +from .utils import _PassArg + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +_NodeBound = t.TypeVar("_NodeBound", bound="Node") + +_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { + "*": operator.mul, + "/": operator.truediv, + "//": operator.floordiv, + "**": operator.pow, + "%": operator.mod, + "+": operator.add, + "-": operator.sub, +} + +_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = { + "not": operator.not_, + "+": operator.pos, + "-": operator.neg, +} + +_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { + "eq": operator.eq, + "ne": operator.ne, + "gt": operator.gt, + "gteq": operator.ge, + "lt": operator.lt, + "lteq": operator.le, + "in": lambda a, b: a in b, + "notin": lambda a, b: a not in b, +} + + +class Impossible(Exception): + """Raised if the node could not perform a requested action.""" + + +class NodeType(type): + """A metaclass for nodes that handles the field and attribute + inheritance. fields and attributes from the parent class are + automatically forwarded to the child.""" + + def __new__(mcs, name, bases, d): # type: ignore + for attr in "fields", "attributes": + storage = [] + storage.extend(getattr(bases[0] if bases else object, attr, ())) + storage.extend(d.get(attr, ())) + assert len(bases) <= 1, "multiple inheritance not allowed" + assert len(storage) == len(set(storage)), "layout conflict" + d[attr] = tuple(storage) + d.setdefault("abstract", False) + return type.__new__(mcs, name, bases, d) + + +class EvalContext: + """Holds evaluation time information. Custom attributes can be attached + to it in extensions. + """ + + def __init__( + self, environment: "Environment", template_name: t.Optional[str] = None + ) -> None: + self.environment = environment + if callable(environment.autoescape): + self.autoescape = environment.autoescape(template_name) + else: + self.autoescape = environment.autoescape + self.volatile = False + + def save(self) -> t.Mapping[str, t.Any]: + return self.__dict__.copy() + + def revert(self, old: t.Mapping[str, t.Any]) -> None: + self.__dict__.clear() + self.__dict__.update(old) + + +def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext: + if ctx is None: + if node.environment is None: + raise RuntimeError( + "if no eval context is passed, the node must have an" + " attached environment." + ) + return EvalContext(node.environment) + return ctx + + +class Node(metaclass=NodeType): + """Baseclass for all Jinja nodes. There are a number of nodes available + of different types. There are four major types: + + - :class:`Stmt`: statements + - :class:`Expr`: expressions + - :class:`Helper`: helper nodes + - :class:`Template`: the outermost wrapper node + + All nodes have fields and attributes. Fields may be other nodes, lists, + or arbitrary values. Fields are passed to the constructor as regular + positional arguments, attributes as keyword arguments. Each node has + two attributes: `lineno` (the line number of the node) and `environment`. + The `environment` attribute is set at the end of the parsing process for + all nodes automatically. + """ + + fields: t.Tuple[str, ...] = () + attributes: t.Tuple[str, ...] = ("lineno", "environment") + abstract = True + + lineno: int + environment: t.Optional["Environment"] + + def __init__(self, *fields: t.Any, **attributes: t.Any) -> None: + if self.abstract: + raise TypeError("abstract nodes are not instantiable") + if fields: + if len(fields) != len(self.fields): + if not self.fields: + raise TypeError(f"{type(self).__name__!r} takes 0 arguments") + raise TypeError( + f"{type(self).__name__!r} takes 0 or {len(self.fields)}" + f" argument{'s' if len(self.fields) != 1 else ''}" + ) + for name, arg in zip(self.fields, fields): + setattr(self, name, arg) + for attr in self.attributes: + setattr(self, attr, attributes.pop(attr, None)) + if attributes: + raise TypeError(f"unknown attribute {next(iter(attributes))!r}") + + def iter_fields( + self, + exclude: t.Optional[t.Container[str]] = None, + only: t.Optional[t.Container[str]] = None, + ) -> t.Iterator[t.Tuple[str, t.Any]]: + """This method iterates over all fields that are defined and yields + ``(key, value)`` tuples. Per default all fields are returned, but + it's possible to limit that to some fields by providing the `only` + parameter or to exclude some using the `exclude` parameter. Both + should be sets or tuples of field names. + """ + for name in self.fields: + if ( + (exclude is None and only is None) + or (exclude is not None and name not in exclude) + or (only is not None and name in only) + ): + try: + yield name, getattr(self, name) + except AttributeError: + pass + + def iter_child_nodes( + self, + exclude: t.Optional[t.Container[str]] = None, + only: t.Optional[t.Container[str]] = None, + ) -> t.Iterator["Node"]: + """Iterates over all direct child nodes of the node. This iterates + over all fields and yields the values of they are nodes. If the value + of a field is a list all the nodes in that list are returned. + """ + for _, item in self.iter_fields(exclude, only): + if isinstance(item, list): + for n in item: + if isinstance(n, Node): + yield n + elif isinstance(item, Node): + yield item + + def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]: + """Find the first node of a given type. If no such node exists the + return value is `None`. + """ + for result in self.find_all(node_type): + return result + + return None + + def find_all( + self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]] + ) -> t.Iterator[_NodeBound]: + """Find all the nodes of a given type. If the type is a tuple, + the check is performed for any of the tuple items. + """ + for child in self.iter_child_nodes(): + if isinstance(child, node_type): + yield child # type: ignore + yield from child.find_all(node_type) + + def set_ctx(self, ctx: str) -> "Node": + """Reset the context of a node and all child nodes. Per default the + parser will all generate nodes that have a 'load' context as it's the + most common one. This method is used in the parser to set assignment + targets and other nodes to a store context. + """ + todo = deque([self]) + while todo: + node = todo.popleft() + if "ctx" in node.fields: + node.ctx = ctx # type: ignore + todo.extend(node.iter_child_nodes()) + return self + + def set_lineno(self, lineno: int, override: bool = False) -> "Node": + """Set the line numbers of the node and children.""" + todo = deque([self]) + while todo: + node = todo.popleft() + if "lineno" in node.attributes: + if node.lineno is None or override: + node.lineno = lineno + todo.extend(node.iter_child_nodes()) + return self + + def set_environment(self, environment: "Environment") -> "Node": + """Set the environment for all nodes.""" + todo = deque([self]) + while todo: + node = todo.popleft() + node.environment = environment + todo.extend(node.iter_child_nodes()) + return self + + def __eq__(self, other: t.Any) -> bool: + if type(self) is not type(other): + return NotImplemented + + return tuple(self.iter_fields()) == tuple(other.iter_fields()) + + __hash__ = object.__hash__ + + def __repr__(self) -> str: + args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields) + return f"{type(self).__name__}({args_str})" + + def dump(self) -> str: + def _dump(node: t.Union[Node, t.Any]) -> None: + if not isinstance(node, Node): + buf.append(repr(node)) + return + + buf.append(f"nodes.{type(node).__name__}(") + if not node.fields: + buf.append(")") + return + for idx, field in enumerate(node.fields): + if idx: + buf.append(", ") + value = getattr(node, field) + if isinstance(value, list): + buf.append("[") + for idx, item in enumerate(value): + if idx: + buf.append(", ") + _dump(item) + buf.append("]") + else: + _dump(value) + buf.append(")") + + buf: t.List[str] = [] + _dump(self) + return "".join(buf) + + +class Stmt(Node): + """Base node for all statements.""" + + abstract = True + + +class Helper(Node): + """Nodes that exist in a specific context only.""" + + abstract = True + + +class Template(Node): + """Node that represents a template. This must be the outermost node that + is passed to the compiler. + """ + + fields = ("body",) + body: t.List[Node] + + +class Output(Stmt): + """A node that holds multiple expressions which are then printed out. + This is used both for the `print` statement and the regular template data. + """ + + fields = ("nodes",) + nodes: t.List["Expr"] + + +class Extends(Stmt): + """Represents an extends statement.""" + + fields = ("template",) + template: "Expr" + + +class For(Stmt): + """The for loop. `target` is the target for the iteration (usually a + :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list + of nodes that are used as loop-body, and `else_` a list of nodes for the + `else` block. If no else node exists it has to be an empty list. + + For filtered nodes an expression can be stored as `test`, otherwise `None`. + """ + + fields = ("target", "iter", "body", "else_", "test", "recursive") + target: Node + iter: Node + body: t.List[Node] + else_: t.List[Node] + test: t.Optional[Node] + recursive: bool + + +class If(Stmt): + """If `test` is true, `body` is rendered, else `else_`.""" + + fields = ("test", "body", "elif_", "else_") + test: Node + body: t.List[Node] + elif_: t.List["If"] + else_: t.List[Node] + + +class Macro(Stmt): + """A macro definition. `name` is the name of the macro, `args` a list of + arguments and `defaults` a list of defaults if there are any. `body` is + a list of nodes for the macro body. + """ + + fields = ("name", "args", "defaults", "body") + name: str + args: t.List["Name"] + defaults: t.List["Expr"] + body: t.List[Node] + + +class CallBlock(Stmt): + """Like a macro without a name but a call instead. `call` is called with + the unnamed macro as `caller` argument this node holds. + """ + + fields = ("call", "args", "defaults", "body") + call: "Call" + args: t.List["Name"] + defaults: t.List["Expr"] + body: t.List[Node] + + +class FilterBlock(Stmt): + """Node for filter sections.""" + + fields = ("body", "filter") + body: t.List[Node] + filter: "Filter" + + +class With(Stmt): + """Specific node for with statements. In older versions of Jinja the + with statement was implemented on the base of the `Scope` node instead. + + .. versionadded:: 2.9.3 + """ + + fields = ("targets", "values", "body") + targets: t.List["Expr"] + values: t.List["Expr"] + body: t.List[Node] + + +class Block(Stmt): + """A node that represents a block. + + .. versionchanged:: 3.0.0 + the `required` field was added. + """ + + fields = ("name", "body", "scoped", "required") + name: str + body: t.List[Node] + scoped: bool + required: bool + + +class Include(Stmt): + """A node that represents the include tag.""" + + fields = ("template", "with_context", "ignore_missing") + template: "Expr" + with_context: bool + ignore_missing: bool + + +class Import(Stmt): + """A node that represents the import tag.""" + + fields = ("template", "target", "with_context") + template: "Expr" + target: str + with_context: bool + + +class FromImport(Stmt): + """A node that represents the from import tag. It's important to not + pass unsafe names to the name attribute. The compiler translates the + attribute lookups directly into getattr calls and does *not* use the + subscript callback of the interface. As exported variables may not + start with double underscores (which the parser asserts) this is not a + problem for regular Jinja code, but if this node is used in an extension + extra care must be taken. + + The list of names may contain tuples if aliases are wanted. + """ + + fields = ("template", "names", "with_context") + template: "Expr" + names: t.List[t.Union[str, t.Tuple[str, str]]] + with_context: bool + + +class ExprStmt(Stmt): + """A statement that evaluates an expression and discards the result.""" + + fields = ("node",) + node: Node + + +class Assign(Stmt): + """Assigns an expression to a target.""" + + fields = ("target", "node") + target: "Expr" + node: Node + + +class AssignBlock(Stmt): + """Assigns a block to a target.""" + + fields = ("target", "filter", "body") + target: "Expr" + filter: t.Optional["Filter"] + body: t.List[Node] + + +class Expr(Node): + """Baseclass for all expressions.""" + + abstract = True + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + """Return the value of the expression as constant or raise + :exc:`Impossible` if this was not possible. + + An :class:`EvalContext` can be provided, if none is given + a default context is created which requires the nodes to have + an attached environment. + + .. versionchanged:: 2.4 + the `eval_ctx` parameter was added. + """ + raise Impossible() + + def can_assign(self) -> bool: + """Check if it's possible to assign something to this node.""" + return False + + +class BinExpr(Expr): + """Baseclass for all binary expressions.""" + + fields = ("left", "right") + left: Expr + right: Expr + operator: str + abstract = True + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + + # intercepted operators cannot be folded at compile time + if ( + eval_ctx.environment.sandboxed + and self.operator in eval_ctx.environment.intercepted_binops # type: ignore + ): + raise Impossible() + f = _binop_to_func[self.operator] + try: + return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx)) + except Exception as e: + raise Impossible() from e + + +class UnaryExpr(Expr): + """Baseclass for all unary expressions.""" + + fields = ("node",) + node: Expr + operator: str + abstract = True + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + + # intercepted operators cannot be folded at compile time + if ( + eval_ctx.environment.sandboxed + and self.operator in eval_ctx.environment.intercepted_unops # type: ignore + ): + raise Impossible() + f = _uaop_to_func[self.operator] + try: + return f(self.node.as_const(eval_ctx)) + except Exception as e: + raise Impossible() from e + + +class Name(Expr): + """Looks up a name or stores a value in a name. + The `ctx` of the node can be one of the following values: + + - `store`: store a value in the name + - `load`: load that name + - `param`: like `store` but if the name was defined as function parameter. + """ + + fields = ("name", "ctx") + name: str + ctx: str + + def can_assign(self) -> bool: + return self.name not in {"true", "false", "none", "True", "False", "None"} + + +class NSRef(Expr): + """Reference to a namespace value assignment""" + + fields = ("name", "attr") + name: str + attr: str + + def can_assign(self) -> bool: + # We don't need any special checks here; NSRef assignments have a + # runtime check to ensure the target is a namespace object which will + # have been checked already as it is created using a normal assignment + # which goes through a `Name` node. + return True + + +class Literal(Expr): + """Baseclass for literals.""" + + abstract = True + + +class Const(Literal): + """All constant values. The parser will return this node for simple + constants such as ``42`` or ``"foo"`` but it can be used to store more + complex values such as lists too. Only constants with a safe + representation (objects where ``eval(repr(x)) == x`` is true). + """ + + fields = ("value",) + value: t.Any + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + return self.value + + @classmethod + def from_untrusted( + cls, + value: t.Any, + lineno: t.Optional[int] = None, + environment: "t.Optional[Environment]" = None, + ) -> "Const": + """Return a const object if the value is representable as + constant value in the generated code, otherwise it will raise + an `Impossible` exception. + """ + from .compiler import has_safe_repr + + if not has_safe_repr(value): + raise Impossible() + return cls(value, lineno=lineno, environment=environment) + + +class TemplateData(Literal): + """A constant template string.""" + + fields = ("data",) + data: str + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: + eval_ctx = get_eval_context(self, eval_ctx) + if eval_ctx.volatile: + raise Impossible() + if eval_ctx.autoescape: + return Markup(self.data) + return self.data + + +class Tuple(Literal): + """For loop unpacking and some other things like multiple arguments + for subscripts. Like for :class:`Name` `ctx` specifies if the tuple + is used for loading the names or storing. + """ + + fields = ("items", "ctx") + items: t.List[Expr] + ctx: str + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]: + eval_ctx = get_eval_context(self, eval_ctx) + return tuple(x.as_const(eval_ctx) for x in self.items) + + def can_assign(self) -> bool: + for item in self.items: + if not item.can_assign(): + return False + return True + + +class List(Literal): + """Any list literal such as ``[1, 2, 3]``""" + + fields = ("items",) + items: t.List[Expr] + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]: + eval_ctx = get_eval_context(self, eval_ctx) + return [x.as_const(eval_ctx) for x in self.items] + + +class Dict(Literal): + """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of + :class:`Pair` nodes. + """ + + fields = ("items",) + items: t.List["Pair"] + + def as_const( + self, eval_ctx: t.Optional[EvalContext] = None + ) -> t.Dict[t.Any, t.Any]: + eval_ctx = get_eval_context(self, eval_ctx) + return dict(x.as_const(eval_ctx) for x in self.items) + + +class Pair(Helper): + """A key, value pair for dicts.""" + + fields = ("key", "value") + key: Expr + value: Expr + + def as_const( + self, eval_ctx: t.Optional[EvalContext] = None + ) -> t.Tuple[t.Any, t.Any]: + eval_ctx = get_eval_context(self, eval_ctx) + return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx) + + +class Keyword(Helper): + """A key, value pair for keyword arguments where key is a string.""" + + fields = ("key", "value") + key: str + value: Expr + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]: + eval_ctx = get_eval_context(self, eval_ctx) + return self.key, self.value.as_const(eval_ctx) + + +class CondExpr(Expr): + """A conditional expression (inline if expression). (``{{ + foo if bar else baz }}``) + """ + + fields = ("test", "expr1", "expr2") + test: Expr + expr1: Expr + expr2: t.Optional[Expr] + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + if self.test.as_const(eval_ctx): + return self.expr1.as_const(eval_ctx) + + # if we evaluate to an undefined object, we better do that at runtime + if self.expr2 is None: + raise Impossible() + + return self.expr2.as_const(eval_ctx) + + +def args_as_const( + node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext] +) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]: + args = [x.as_const(eval_ctx) for x in node.args] + kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs) + + if node.dyn_args is not None: + try: + args.extend(node.dyn_args.as_const(eval_ctx)) + except Exception as e: + raise Impossible() from e + + if node.dyn_kwargs is not None: + try: + kwargs.update(node.dyn_kwargs.as_const(eval_ctx)) + except Exception as e: + raise Impossible() from e + + return args, kwargs + + +class _FilterTestCommon(Expr): + fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs") + node: Expr + name: str + args: t.List[Expr] + kwargs: t.List[Pair] + dyn_args: t.Optional[Expr] + dyn_kwargs: t.Optional[Expr] + abstract = True + _is_filter = True + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + + if eval_ctx.volatile: + raise Impossible() + + if self._is_filter: + env_map = eval_ctx.environment.filters + else: + env_map = eval_ctx.environment.tests + + func = env_map.get(self.name) + pass_arg = _PassArg.from_obj(func) # type: ignore + + if func is None or pass_arg is _PassArg.context: + raise Impossible() + + if eval_ctx.environment.is_async and ( + getattr(func, "jinja_async_variant", False) is True + or inspect.iscoroutinefunction(func) + ): + raise Impossible() + + args, kwargs = args_as_const(self, eval_ctx) + args.insert(0, self.node.as_const(eval_ctx)) + + if pass_arg is _PassArg.eval_context: + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, eval_ctx.environment) + + try: + return func(*args, **kwargs) + except Exception as e: + raise Impossible() from e + + +class Filter(_FilterTestCommon): + """Apply a filter to an expression. ``name`` is the name of the + filter, the other fields are the same as :class:`Call`. + + If ``node`` is ``None``, the filter is being used in a filter block + and is applied to the content of the block. + """ + + node: t.Optional[Expr] # type: ignore + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + if self.node is None: + raise Impossible() + + return super().as_const(eval_ctx=eval_ctx) + + +class Test(_FilterTestCommon): + """Apply a test to an expression. ``name`` is the name of the test, + the other field are the same as :class:`Call`. + + .. versionchanged:: 3.0 + ``as_const`` shares the same logic for filters and tests. Tests + check for volatile, async, and ``@pass_context`` etc. + decorators. + """ + + _is_filter = False + + +class Call(Expr): + """Calls an expression. `args` is a list of arguments, `kwargs` a list + of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args` + and `dyn_kwargs` has to be either `None` or a node that is used as + node for dynamic positional (``*args``) or keyword (``**kwargs``) + arguments. + """ + + fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs") + node: Expr + args: t.List[Expr] + kwargs: t.List[Keyword] + dyn_args: t.Optional[Expr] + dyn_kwargs: t.Optional[Expr] + + +class Getitem(Expr): + """Get an attribute or item from an expression and prefer the item.""" + + fields = ("node", "arg", "ctx") + node: Expr + arg: Expr + ctx: str + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + if self.ctx != "load": + raise Impossible() + + eval_ctx = get_eval_context(self, eval_ctx) + + try: + return eval_ctx.environment.getitem( + self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx) + ) + except Exception as e: + raise Impossible() from e + + +class Getattr(Expr): + """Get an attribute or item from an expression that is a ascii-only + bytestring and prefer the attribute. + """ + + fields = ("node", "attr", "ctx") + node: Expr + attr: str + ctx: str + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + if self.ctx != "load": + raise Impossible() + + eval_ctx = get_eval_context(self, eval_ctx) + + try: + return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr) + except Exception as e: + raise Impossible() from e + + +class Slice(Expr): + """Represents a slice object. This must only be used as argument for + :class:`Subscript`. + """ + + fields = ("start", "stop", "step") + start: t.Optional[Expr] + stop: t.Optional[Expr] + step: t.Optional[Expr] + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice: + eval_ctx = get_eval_context(self, eval_ctx) + + def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]: + if obj is None: + return None + return obj.as_const(eval_ctx) + + return slice(const(self.start), const(self.stop), const(self.step)) + + +class Concat(Expr): + """Concatenates the list of expressions provided after converting + them to strings. + """ + + fields = ("nodes",) + nodes: t.List[Expr] + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: + eval_ctx = get_eval_context(self, eval_ctx) + return "".join(str(x.as_const(eval_ctx)) for x in self.nodes) + + +class Compare(Expr): + """Compares an expression with some other expressions. `ops` must be a + list of :class:`Operand`\\s. + """ + + fields = ("expr", "ops") + expr: Expr + ops: t.List["Operand"] + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + result = value = self.expr.as_const(eval_ctx) + + try: + for op in self.ops: + new_value = op.expr.as_const(eval_ctx) + result = _cmpop_to_func[op.op](value, new_value) + + if not result: + return False + + value = new_value + except Exception as e: + raise Impossible() from e + + return result + + +class Operand(Helper): + """Holds an operator and an expression.""" + + fields = ("op", "expr") + op: str + expr: Expr + + +class Mul(BinExpr): + """Multiplies the left with the right node.""" + + operator = "*" + + +class Div(BinExpr): + """Divides the left by the right node.""" + + operator = "/" + + +class FloorDiv(BinExpr): + """Divides the left by the right node and converts the + result into an integer by truncating. + """ + + operator = "//" + + +class Add(BinExpr): + """Add the left to the right node.""" + + operator = "+" + + +class Sub(BinExpr): + """Subtract the right from the left node.""" + + operator = "-" + + +class Mod(BinExpr): + """Left modulo right.""" + + operator = "%" + + +class Pow(BinExpr): + """Left to the power of right.""" + + operator = "**" + + +class And(BinExpr): + """Short circuited AND.""" + + operator = "and" + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx) + + +class Or(BinExpr): + """Short circuited OR.""" + + operator = "or" + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: + eval_ctx = get_eval_context(self, eval_ctx) + return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx) + + +class Not(UnaryExpr): + """Negate the expression.""" + + operator = "not" + + +class Neg(UnaryExpr): + """Make the expression negative.""" + + operator = "-" + + +class Pos(UnaryExpr): + """Make the expression positive (noop for most expressions)""" + + operator = "+" + + +# Helpers for extensions + + +class EnvironmentAttribute(Expr): + """Loads an attribute from the environment object. This is useful for + extensions that want to call a callback stored on the environment. + """ + + fields = ("name",) + name: str + + +class ExtensionAttribute(Expr): + """Returns the attribute of an extension bound to the environment. + The identifier is the identifier of the :class:`Extension`. + + This node is usually constructed by calling the + :meth:`~jinja2.ext.Extension.attr` method on an extension. + """ + + fields = ("identifier", "name") + identifier: str + name: str + + +class ImportedName(Expr): + """If created with an import name the import name is returned on node + access. For example ``ImportedName('cgi.escape')`` returns the `escape` + function from the cgi module on evaluation. Imports are optimized by the + compiler so there is no need to assign them to local variables. + """ + + fields = ("importname",) + importname: str + + +class InternalName(Expr): + """An internal name in the compiler. You cannot create these nodes + yourself but the parser provides a + :meth:`~jinja2.parser.Parser.free_identifier` method that creates + a new identifier for you. This identifier is not available from the + template and is not treated specially by the compiler. + """ + + fields = ("name",) + name: str + + def __init__(self) -> None: + raise TypeError( + "Can't create internal names. Use the " + "`free_identifier` method on a parser." + ) + + +class MarkSafe(Expr): + """Mark the wrapped expression as safe (wrap it as `Markup`).""" + + fields = ("expr",) + expr: Expr + + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup: + eval_ctx = get_eval_context(self, eval_ctx) + return Markup(self.expr.as_const(eval_ctx)) + + +class MarkSafeIfAutoescape(Expr): + """Mark the wrapped expression as safe (wrap it as `Markup`) but + only if autoescaping is active. + + .. versionadded:: 2.5 + """ + + fields = ("expr",) + expr: Expr + + def as_const( + self, eval_ctx: t.Optional[EvalContext] = None + ) -> t.Union[Markup, t.Any]: + eval_ctx = get_eval_context(self, eval_ctx) + if eval_ctx.volatile: + raise Impossible() + expr = self.expr.as_const(eval_ctx) + if eval_ctx.autoescape: + return Markup(expr) + return expr + + +class ContextReference(Expr): + """Returns the current template context. It can be used like a + :class:`Name` node, with a ``'load'`` ctx and will return the + current :class:`~jinja2.runtime.Context` object. + + Here an example that assigns the current template name to a + variable named `foo`:: + + Assign(Name('foo', ctx='store'), + Getattr(ContextReference(), 'name')) + + This is basically equivalent to using the + :func:`~jinja2.pass_context` decorator when using the high-level + API, which causes a reference to the context to be passed as the + first argument to a function. + """ + + +class DerivedContextReference(Expr): + """Return the current template context including locals. Behaves + exactly like :class:`ContextReference`, but includes local + variables, such as from a ``for`` loop. + + .. versionadded:: 2.11 + """ + + +class Continue(Stmt): + """Continue a loop.""" + + +class Break(Stmt): + """Break a loop.""" + + +class Scope(Stmt): + """An artificial scope.""" + + fields = ("body",) + body: t.List[Node] + + +class OverlayScope(Stmt): + """An overlay scope for extensions. This is a largely unoptimized scope + that however can be used to introduce completely arbitrary variables into + a sub scope from a dictionary or dictionary like object. The `context` + field has to evaluate to a dictionary object. + + Example usage:: + + OverlayScope(context=self.call_method('get_context'), + body=[...]) + + .. versionadded:: 2.10 + """ + + fields = ("context", "body") + context: Expr + body: t.List[Node] + + +class EvalContextModifier(Stmt): + """Modifies the eval context. For each option that should be modified, + a :class:`Keyword` has to be added to the :attr:`options` list. + + Example to change the `autoescape` setting:: + + EvalContextModifier(options=[Keyword('autoescape', Const(True))]) + """ + + fields = ("options",) + options: t.List[Keyword] + + +class ScopedEvalContextModifier(EvalContextModifier): + """Modifies the eval context and reverts it later. Works exactly like + :class:`EvalContextModifier` but will only modify the + :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`. + """ + + fields = ("body",) + body: t.List[Node] + + +# make sure nobody creates custom nodes +def _failing_new(*args: t.Any, **kwargs: t.Any) -> "te.NoReturn": + raise TypeError("can't create custom node types") + + +NodeType.__new__ = staticmethod(_failing_new) # type: ignore +del _failing_new diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/optimizer.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/optimizer.py new file mode 100644 index 0000000000000000000000000000000000000000..fe1010705e7b29d4fa1900b3a0438ab93d7b582c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/optimizer.py @@ -0,0 +1,47 @@ +"""The optimizer tries to constant fold expressions and modify the AST +in place so that it should be faster to evaluate. + +Because the AST does not contain all the scoping information and the +compiler has to find that out, we cannot do all the optimizations we +want. For example, loop unrolling doesn't work because unrolled loops +would have a different scope. The solution would be a second syntax tree +that stored the scoping rules. +""" +import typing as t + +from . import nodes +from .visitor import NodeTransformer + +if t.TYPE_CHECKING: + from .environment import Environment + + +def optimize(node: nodes.Node, environment: "Environment") -> nodes.Node: + """The context hint can be used to perform an static optimization + based on the context given.""" + optimizer = Optimizer(environment) + return t.cast(nodes.Node, optimizer.visit(node)) + + +class Optimizer(NodeTransformer): + def __init__(self, environment: "t.Optional[Environment]") -> None: + self.environment = environment + + def generic_visit( + self, node: nodes.Node, *args: t.Any, **kwargs: t.Any + ) -> nodes.Node: + node = super().generic_visit(node, *args, **kwargs) + + # Do constant folding. Some other nodes besides Expr have + # as_const, but folding them causes errors later on. + if isinstance(node, nodes.Expr): + try: + return nodes.Const.from_untrusted( + node.as_const(args[0] if args else None), + lineno=node.lineno, + environment=self.environment, + ) + except nodes.Impossible: + pass + + return node diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/parser.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..cefce2dfa1d2a4171838b0d0135af8ea3ff7d62c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/parser.py @@ -0,0 +1,1032 @@ +"""Parse tokens from the lexer into nodes for the compiler.""" +import typing +import typing as t + +from . import nodes +from .exceptions import TemplateAssertionError +from .exceptions import TemplateSyntaxError +from .lexer import describe_token +from .lexer import describe_token_expr + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +_ImportInclude = t.TypeVar("_ImportInclude", nodes.Import, nodes.Include) +_MacroCall = t.TypeVar("_MacroCall", nodes.Macro, nodes.CallBlock) + +_statement_keywords = frozenset( + [ + "for", + "if", + "block", + "extends", + "print", + "macro", + "include", + "from", + "import", + "set", + "with", + "autoescape", + ] +) +_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"]) + +_math_nodes: t.Dict[str, t.Type[nodes.Expr]] = { + "add": nodes.Add, + "sub": nodes.Sub, + "mul": nodes.Mul, + "div": nodes.Div, + "floordiv": nodes.FloorDiv, + "mod": nodes.Mod, +} + + +class Parser: + """This is the central parsing class Jinja uses. It's passed to + extensions and can be used to parse expressions or statements. + """ + + def __init__( + self, + environment: "Environment", + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> None: + self.environment = environment + self.stream = environment._tokenize(source, name, filename, state) + self.name = name + self.filename = filename + self.closed = False + self.extensions: t.Dict[ + str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]] + ] = {} + for extension in environment.iter_extensions(): + for tag in extension.tags: + self.extensions[tag] = extension.parse + self._last_identifier = 0 + self._tag_stack: t.List[str] = [] + self._end_token_stack: t.List[t.Tuple[str, ...]] = [] + + def fail( + self, + msg: str, + lineno: t.Optional[int] = None, + exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError, + ) -> "te.NoReturn": + """Convenience method that raises `exc` with the message, passed + line number or last line number as well as the current name and + filename. + """ + if lineno is None: + lineno = self.stream.current.lineno + raise exc(msg, lineno, self.name, self.filename) + + def _fail_ut_eof( + self, + name: t.Optional[str], + end_token_stack: t.List[t.Tuple[str, ...]], + lineno: t.Optional[int], + ) -> "te.NoReturn": + expected: t.Set[str] = set() + for exprs in end_token_stack: + expected.update(map(describe_token_expr, exprs)) + if end_token_stack: + currently_looking: t.Optional[str] = " or ".join( + map(repr, map(describe_token_expr, end_token_stack[-1])) + ) + else: + currently_looking = None + + if name is None: + message = ["Unexpected end of template."] + else: + message = [f"Encountered unknown tag {name!r}."] + + if currently_looking: + if name is not None and name in expected: + message.append( + "You probably made a nesting mistake. Jinja is expecting this tag," + f" but currently looking for {currently_looking}." + ) + else: + message.append( + f"Jinja was looking for the following tags: {currently_looking}." + ) + + if self._tag_stack: + message.append( + "The innermost block that needs to be closed is" + f" {self._tag_stack[-1]!r}." + ) + + self.fail(" ".join(message), lineno) + + def fail_unknown_tag( + self, name: str, lineno: t.Optional[int] = None + ) -> "te.NoReturn": + """Called if the parser encounters an unknown tag. Tries to fail + with a human readable error message that could help to identify + the problem. + """ + self._fail_ut_eof(name, self._end_token_stack, lineno) + + def fail_eof( + self, + end_tokens: t.Optional[t.Tuple[str, ...]] = None, + lineno: t.Optional[int] = None, + ) -> "te.NoReturn": + """Like fail_unknown_tag but for end of template situations.""" + stack = list(self._end_token_stack) + if end_tokens is not None: + stack.append(end_tokens) + self._fail_ut_eof(None, stack, lineno) + + def is_tuple_end( + self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None + ) -> bool: + """Are we at the end of a tuple?""" + if self.stream.current.type in ("variable_end", "block_end", "rparen"): + return True + elif extra_end_rules is not None: + return self.stream.current.test_any(extra_end_rules) # type: ignore + return False + + def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName: + """Return a new free identifier as :class:`~jinja2.nodes.InternalName`.""" + self._last_identifier += 1 + rv = object.__new__(nodes.InternalName) + nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno) + return rv + + def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]: + """Parse a single statement.""" + token = self.stream.current + if token.type != "name": + self.fail("tag name expected", token.lineno) + self._tag_stack.append(token.value) + pop_tag = True + try: + if token.value in _statement_keywords: + f = getattr(self, f"parse_{self.stream.current.value}") + return f() # type: ignore + if token.value == "call": + return self.parse_call_block() + if token.value == "filter": + return self.parse_filter_block() + ext = self.extensions.get(token.value) + if ext is not None: + return ext(self) + + # did not work out, remove the token we pushed by accident + # from the stack so that the unknown tag fail function can + # produce a proper error message. + self._tag_stack.pop() + pop_tag = False + self.fail_unknown_tag(token.value, token.lineno) + finally: + if pop_tag: + self._tag_stack.pop() + + def parse_statements( + self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False + ) -> t.List[nodes.Node]: + """Parse multiple statements into a list until one of the end tokens + is reached. This is used to parse the body of statements as it also + parses template data if appropriate. The parser checks first if the + current token is a colon and skips it if there is one. Then it checks + for the block end and parses until if one of the `end_tokens` is + reached. Per default the active token in the stream at the end of + the call is the matched end token. If this is not wanted `drop_needle` + can be set to `True` and the end token is removed. + """ + # the first token may be a colon for python compatibility + self.stream.skip_if("colon") + + # in the future it would be possible to add whole code sections + # by adding some sort of end of statement token and parsing those here. + self.stream.expect("block_end") + result = self.subparse(end_tokens) + + # we reached the end of the template too early, the subparser + # does not check for this, so we do that now + if self.stream.current.type == "eof": + self.fail_eof(end_tokens) + + if drop_needle: + next(self.stream) + return result + + def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]: + """Parse an assign statement.""" + lineno = next(self.stream).lineno + target = self.parse_assign_target(with_namespace=True) + if self.stream.skip_if("assign"): + expr = self.parse_tuple() + return nodes.Assign(target, expr, lineno=lineno) + filter_node = self.parse_filter(None) + body = self.parse_statements(("name:endset",), drop_needle=True) + return nodes.AssignBlock(target, filter_node, body, lineno=lineno) + + def parse_for(self) -> nodes.For: + """Parse a for loop.""" + lineno = self.stream.expect("name:for").lineno + target = self.parse_assign_target(extra_end_rules=("name:in",)) + self.stream.expect("name:in") + iter = self.parse_tuple( + with_condexpr=False, extra_end_rules=("name:recursive",) + ) + test = None + if self.stream.skip_if("name:if"): + test = self.parse_expression() + recursive = self.stream.skip_if("name:recursive") + body = self.parse_statements(("name:endfor", "name:else")) + if next(self.stream).value == "endfor": + else_ = [] + else: + else_ = self.parse_statements(("name:endfor",), drop_needle=True) + return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno) + + def parse_if(self) -> nodes.If: + """Parse an if construct.""" + node = result = nodes.If(lineno=self.stream.expect("name:if").lineno) + while True: + node.test = self.parse_tuple(with_condexpr=False) + node.body = self.parse_statements(("name:elif", "name:else", "name:endif")) + node.elif_ = [] + node.else_ = [] + token = next(self.stream) + if token.test("name:elif"): + node = nodes.If(lineno=self.stream.current.lineno) + result.elif_.append(node) + continue + elif token.test("name:else"): + result.else_ = self.parse_statements(("name:endif",), drop_needle=True) + break + return result + + def parse_with(self) -> nodes.With: + node = nodes.With(lineno=next(self.stream).lineno) + targets: t.List[nodes.Expr] = [] + values: t.List[nodes.Expr] = [] + while self.stream.current.type != "block_end": + if targets: + self.stream.expect("comma") + target = self.parse_assign_target() + target.set_ctx("param") + targets.append(target) + self.stream.expect("assign") + values.append(self.parse_expression()) + node.targets = targets + node.values = values + node.body = self.parse_statements(("name:endwith",), drop_needle=True) + return node + + def parse_autoescape(self) -> nodes.Scope: + node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno) + node.options = [nodes.Keyword("autoescape", self.parse_expression())] + node.body = self.parse_statements(("name:endautoescape",), drop_needle=True) + return nodes.Scope([node]) + + def parse_block(self) -> nodes.Block: + node = nodes.Block(lineno=next(self.stream).lineno) + node.name = self.stream.expect("name").value + node.scoped = self.stream.skip_if("name:scoped") + node.required = self.stream.skip_if("name:required") + + # common problem people encounter when switching from django + # to jinja. we do not support hyphens in block names, so let's + # raise a nicer error message in that case. + if self.stream.current.type == "sub": + self.fail( + "Block names in Jinja have to be valid Python identifiers and may not" + " contain hyphens, use an underscore instead." + ) + + node.body = self.parse_statements(("name:endblock",), drop_needle=True) + + # enforce that required blocks only contain whitespace or comments + # by asserting that the body, if not empty, is just TemplateData nodes + # with whitespace data + if node.required and not all( + isinstance(child, nodes.TemplateData) and child.data.isspace() + for body in node.body + for child in body.nodes # type: ignore + ): + self.fail("Required blocks can only contain comments or whitespace") + + self.stream.skip_if("name:" + node.name) + return node + + def parse_extends(self) -> nodes.Extends: + node = nodes.Extends(lineno=next(self.stream).lineno) + node.template = self.parse_expression() + return node + + def parse_import_context( + self, node: _ImportInclude, default: bool + ) -> _ImportInclude: + if self.stream.current.test_any( + "name:with", "name:without" + ) and self.stream.look().test("name:context"): + node.with_context = next(self.stream).value == "with" + self.stream.skip() + else: + node.with_context = default + return node + + def parse_include(self) -> nodes.Include: + node = nodes.Include(lineno=next(self.stream).lineno) + node.template = self.parse_expression() + if self.stream.current.test("name:ignore") and self.stream.look().test( + "name:missing" + ): + node.ignore_missing = True + self.stream.skip(2) + else: + node.ignore_missing = False + return self.parse_import_context(node, True) + + def parse_import(self) -> nodes.Import: + node = nodes.Import(lineno=next(self.stream).lineno) + node.template = self.parse_expression() + self.stream.expect("name:as") + node.target = self.parse_assign_target(name_only=True).name + return self.parse_import_context(node, False) + + def parse_from(self) -> nodes.FromImport: + node = nodes.FromImport(lineno=next(self.stream).lineno) + node.template = self.parse_expression() + self.stream.expect("name:import") + node.names = [] + + def parse_context() -> bool: + if self.stream.current.value in { + "with", + "without", + } and self.stream.look().test("name:context"): + node.with_context = next(self.stream).value == "with" + self.stream.skip() + return True + return False + + while True: + if node.names: + self.stream.expect("comma") + if self.stream.current.type == "name": + if parse_context(): + break + target = self.parse_assign_target(name_only=True) + if target.name.startswith("_"): + self.fail( + "names starting with an underline can not be imported", + target.lineno, + exc=TemplateAssertionError, + ) + if self.stream.skip_if("name:as"): + alias = self.parse_assign_target(name_only=True) + node.names.append((target.name, alias.name)) + else: + node.names.append(target.name) + if parse_context() or self.stream.current.type != "comma": + break + else: + self.stream.expect("name") + if not hasattr(node, "with_context"): + node.with_context = False + return node + + def parse_signature(self, node: _MacroCall) -> None: + args = node.args = [] + defaults = node.defaults = [] + self.stream.expect("lparen") + while self.stream.current.type != "rparen": + if args: + self.stream.expect("comma") + arg = self.parse_assign_target(name_only=True) + arg.set_ctx("param") + if self.stream.skip_if("assign"): + defaults.append(self.parse_expression()) + elif defaults: + self.fail("non-default argument follows default argument") + args.append(arg) + self.stream.expect("rparen") + + def parse_call_block(self) -> nodes.CallBlock: + node = nodes.CallBlock(lineno=next(self.stream).lineno) + if self.stream.current.type == "lparen": + self.parse_signature(node) + else: + node.args = [] + node.defaults = [] + + call_node = self.parse_expression() + if not isinstance(call_node, nodes.Call): + self.fail("expected call", node.lineno) + node.call = call_node + node.body = self.parse_statements(("name:endcall",), drop_needle=True) + return node + + def parse_filter_block(self) -> nodes.FilterBlock: + node = nodes.FilterBlock(lineno=next(self.stream).lineno) + node.filter = self.parse_filter(None, start_inline=True) # type: ignore + node.body = self.parse_statements(("name:endfilter",), drop_needle=True) + return node + + def parse_macro(self) -> nodes.Macro: + node = nodes.Macro(lineno=next(self.stream).lineno) + node.name = self.parse_assign_target(name_only=True).name + self.parse_signature(node) + node.body = self.parse_statements(("name:endmacro",), drop_needle=True) + return node + + def parse_print(self) -> nodes.Output: + node = nodes.Output(lineno=next(self.stream).lineno) + node.nodes = [] + while self.stream.current.type != "block_end": + if node.nodes: + self.stream.expect("comma") + node.nodes.append(self.parse_expression()) + return node + + @typing.overload + def parse_assign_target( + self, with_tuple: bool = ..., name_only: "te.Literal[True]" = ... + ) -> nodes.Name: + ... + + @typing.overload + def parse_assign_target( + self, + with_tuple: bool = True, + name_only: bool = False, + extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + with_namespace: bool = False, + ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: + ... + + def parse_assign_target( + self, + with_tuple: bool = True, + name_only: bool = False, + extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + with_namespace: bool = False, + ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: + """Parse an assignment target. As Jinja allows assignments to + tuples, this function can parse all allowed assignment targets. Per + default assignments to tuples are parsed, that can be disable however + by setting `with_tuple` to `False`. If only assignments to names are + wanted `name_only` can be set to `True`. The `extra_end_rules` + parameter is forwarded to the tuple parsing function. If + `with_namespace` is enabled, a namespace assignment may be parsed. + """ + target: nodes.Expr + + if with_namespace and self.stream.look().type == "dot": + token = self.stream.expect("name") + next(self.stream) # dot + attr = self.stream.expect("name") + target = nodes.NSRef(token.value, attr.value, lineno=token.lineno) + elif name_only: + token = self.stream.expect("name") + target = nodes.Name(token.value, "store", lineno=token.lineno) + else: + if with_tuple: + target = self.parse_tuple( + simplified=True, extra_end_rules=extra_end_rules + ) + else: + target = self.parse_primary() + + target.set_ctx("store") + + if not target.can_assign(): + self.fail( + f"can't assign to {type(target).__name__.lower()!r}", target.lineno + ) + + return target # type: ignore + + def parse_expression(self, with_condexpr: bool = True) -> nodes.Expr: + """Parse an expression. Per default all expressions are parsed, if + the optional `with_condexpr` parameter is set to `False` conditional + expressions are not parsed. + """ + if with_condexpr: + return self.parse_condexpr() + return self.parse_or() + + def parse_condexpr(self) -> nodes.Expr: + lineno = self.stream.current.lineno + expr1 = self.parse_or() + expr3: t.Optional[nodes.Expr] + + while self.stream.skip_if("name:if"): + expr2 = self.parse_or() + if self.stream.skip_if("name:else"): + expr3 = self.parse_condexpr() + else: + expr3 = None + expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno) + lineno = self.stream.current.lineno + return expr1 + + def parse_or(self) -> nodes.Expr: + lineno = self.stream.current.lineno + left = self.parse_and() + while self.stream.skip_if("name:or"): + right = self.parse_and() + left = nodes.Or(left, right, lineno=lineno) + lineno = self.stream.current.lineno + return left + + def parse_and(self) -> nodes.Expr: + lineno = self.stream.current.lineno + left = self.parse_not() + while self.stream.skip_if("name:and"): + right = self.parse_not() + left = nodes.And(left, right, lineno=lineno) + lineno = self.stream.current.lineno + return left + + def parse_not(self) -> nodes.Expr: + if self.stream.current.test("name:not"): + lineno = next(self.stream).lineno + return nodes.Not(self.parse_not(), lineno=lineno) + return self.parse_compare() + + def parse_compare(self) -> nodes.Expr: + lineno = self.stream.current.lineno + expr = self.parse_math1() + ops = [] + while True: + token_type = self.stream.current.type + if token_type in _compare_operators: + next(self.stream) + ops.append(nodes.Operand(token_type, self.parse_math1())) + elif self.stream.skip_if("name:in"): + ops.append(nodes.Operand("in", self.parse_math1())) + elif self.stream.current.test("name:not") and self.stream.look().test( + "name:in" + ): + self.stream.skip(2) + ops.append(nodes.Operand("notin", self.parse_math1())) + else: + break + lineno = self.stream.current.lineno + if not ops: + return expr + return nodes.Compare(expr, ops, lineno=lineno) + + def parse_math1(self) -> nodes.Expr: + lineno = self.stream.current.lineno + left = self.parse_concat() + while self.stream.current.type in ("add", "sub"): + cls = _math_nodes[self.stream.current.type] + next(self.stream) + right = self.parse_concat() + left = cls(left, right, lineno=lineno) + lineno = self.stream.current.lineno + return left + + def parse_concat(self) -> nodes.Expr: + lineno = self.stream.current.lineno + args = [self.parse_math2()] + while self.stream.current.type == "tilde": + next(self.stream) + args.append(self.parse_math2()) + if len(args) == 1: + return args[0] + return nodes.Concat(args, lineno=lineno) + + def parse_math2(self) -> nodes.Expr: + lineno = self.stream.current.lineno + left = self.parse_pow() + while self.stream.current.type in ("mul", "div", "floordiv", "mod"): + cls = _math_nodes[self.stream.current.type] + next(self.stream) + right = self.parse_pow() + left = cls(left, right, lineno=lineno) + lineno = self.stream.current.lineno + return left + + def parse_pow(self) -> nodes.Expr: + lineno = self.stream.current.lineno + left = self.parse_unary() + while self.stream.current.type == "pow": + next(self.stream) + right = self.parse_unary() + left = nodes.Pow(left, right, lineno=lineno) + lineno = self.stream.current.lineno + return left + + def parse_unary(self, with_filter: bool = True) -> nodes.Expr: + token_type = self.stream.current.type + lineno = self.stream.current.lineno + node: nodes.Expr + + if token_type == "sub": + next(self.stream) + node = nodes.Neg(self.parse_unary(False), lineno=lineno) + elif token_type == "add": + next(self.stream) + node = nodes.Pos(self.parse_unary(False), lineno=lineno) + else: + node = self.parse_primary() + node = self.parse_postfix(node) + if with_filter: + node = self.parse_filter_expr(node) + return node + + def parse_primary(self) -> nodes.Expr: + token = self.stream.current + node: nodes.Expr + if token.type == "name": + if token.value in ("true", "false", "True", "False"): + node = nodes.Const(token.value in ("true", "True"), lineno=token.lineno) + elif token.value in ("none", "None"): + node = nodes.Const(None, lineno=token.lineno) + else: + node = nodes.Name(token.value, "load", lineno=token.lineno) + next(self.stream) + elif token.type == "string": + next(self.stream) + buf = [token.value] + lineno = token.lineno + while self.stream.current.type == "string": + buf.append(self.stream.current.value) + next(self.stream) + node = nodes.Const("".join(buf), lineno=lineno) + elif token.type in ("integer", "float"): + next(self.stream) + node = nodes.Const(token.value, lineno=token.lineno) + elif token.type == "lparen": + next(self.stream) + node = self.parse_tuple(explicit_parentheses=True) + self.stream.expect("rparen") + elif token.type == "lbracket": + node = self.parse_list() + elif token.type == "lbrace": + node = self.parse_dict() + else: + self.fail(f"unexpected {describe_token(token)!r}", token.lineno) + return node + + def parse_tuple( + self, + simplified: bool = False, + with_condexpr: bool = True, + extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + explicit_parentheses: bool = False, + ) -> t.Union[nodes.Tuple, nodes.Expr]: + """Works like `parse_expression` but if multiple expressions are + delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. + This method could also return a regular expression instead of a tuple + if no commas where found. + + The default parsing mode is a full tuple. If `simplified` is `True` + only names and literals are parsed. The `no_condexpr` parameter is + forwarded to :meth:`parse_expression`. + + Because tuples do not require delimiters and may end in a bogus comma + an extra hint is needed that marks the end of a tuple. For example + for loops support tuples between `for` and `in`. In that case the + `extra_end_rules` is set to ``['name:in']``. + + `explicit_parentheses` is true if the parsing was triggered by an + expression in parentheses. This is used to figure out if an empty + tuple is a valid expression or not. + """ + lineno = self.stream.current.lineno + if simplified: + parse = self.parse_primary + elif with_condexpr: + parse = self.parse_expression + else: + + def parse() -> nodes.Expr: + return self.parse_expression(with_condexpr=False) + + args: t.List[nodes.Expr] = [] + is_tuple = False + + while True: + if args: + self.stream.expect("comma") + if self.is_tuple_end(extra_end_rules): + break + args.append(parse()) + if self.stream.current.type == "comma": + is_tuple = True + else: + break + lineno = self.stream.current.lineno + + if not is_tuple: + if args: + return args[0] + + # if we don't have explicit parentheses, an empty tuple is + # not a valid expression. This would mean nothing (literally + # nothing) in the spot of an expression would be an empty + # tuple. + if not explicit_parentheses: + self.fail( + "Expected an expression," + f" got {describe_token(self.stream.current)!r}" + ) + + return nodes.Tuple(args, "load", lineno=lineno) + + def parse_list(self) -> nodes.List: + token = self.stream.expect("lbracket") + items: t.List[nodes.Expr] = [] + while self.stream.current.type != "rbracket": + if items: + self.stream.expect("comma") + if self.stream.current.type == "rbracket": + break + items.append(self.parse_expression()) + self.stream.expect("rbracket") + return nodes.List(items, lineno=token.lineno) + + def parse_dict(self) -> nodes.Dict: + token = self.stream.expect("lbrace") + items: t.List[nodes.Pair] = [] + while self.stream.current.type != "rbrace": + if items: + self.stream.expect("comma") + if self.stream.current.type == "rbrace": + break + key = self.parse_expression() + self.stream.expect("colon") + value = self.parse_expression() + items.append(nodes.Pair(key, value, lineno=key.lineno)) + self.stream.expect("rbrace") + return nodes.Dict(items, lineno=token.lineno) + + def parse_postfix(self, node: nodes.Expr) -> nodes.Expr: + while True: + token_type = self.stream.current.type + if token_type == "dot" or token_type == "lbracket": + node = self.parse_subscript(node) + # calls are valid both after postfix expressions (getattr + # and getitem) as well as filters and tests + elif token_type == "lparen": + node = self.parse_call(node) + else: + break + return node + + def parse_filter_expr(self, node: nodes.Expr) -> nodes.Expr: + while True: + token_type = self.stream.current.type + if token_type == "pipe": + node = self.parse_filter(node) # type: ignore + elif token_type == "name" and self.stream.current.value == "is": + node = self.parse_test(node) + # calls are valid both after postfix expressions (getattr + # and getitem) as well as filters and tests + elif token_type == "lparen": + node = self.parse_call(node) + else: + break + return node + + def parse_subscript( + self, node: nodes.Expr + ) -> t.Union[nodes.Getattr, nodes.Getitem]: + token = next(self.stream) + arg: nodes.Expr + + if token.type == "dot": + attr_token = self.stream.current + next(self.stream) + if attr_token.type == "name": + return nodes.Getattr( + node, attr_token.value, "load", lineno=token.lineno + ) + elif attr_token.type != "integer": + self.fail("expected name or number", attr_token.lineno) + arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) + return nodes.Getitem(node, arg, "load", lineno=token.lineno) + if token.type == "lbracket": + args: t.List[nodes.Expr] = [] + while self.stream.current.type != "rbracket": + if args: + self.stream.expect("comma") + args.append(self.parse_subscribed()) + self.stream.expect("rbracket") + if len(args) == 1: + arg = args[0] + else: + arg = nodes.Tuple(args, "load", lineno=token.lineno) + return nodes.Getitem(node, arg, "load", lineno=token.lineno) + self.fail("expected subscript expression", token.lineno) + + def parse_subscribed(self) -> nodes.Expr: + lineno = self.stream.current.lineno + args: t.List[t.Optional[nodes.Expr]] + + if self.stream.current.type == "colon": + next(self.stream) + args = [None] + else: + node = self.parse_expression() + if self.stream.current.type != "colon": + return node + next(self.stream) + args = [node] + + if self.stream.current.type == "colon": + args.append(None) + elif self.stream.current.type not in ("rbracket", "comma"): + args.append(self.parse_expression()) + else: + args.append(None) + + if self.stream.current.type == "colon": + next(self.stream) + if self.stream.current.type not in ("rbracket", "comma"): + args.append(self.parse_expression()) + else: + args.append(None) + else: + args.append(None) + + return nodes.Slice(lineno=lineno, *args) + + def parse_call_args(self) -> t.Tuple: + token = self.stream.expect("lparen") + args = [] + kwargs = [] + dyn_args = None + dyn_kwargs = None + require_comma = False + + def ensure(expr: bool) -> None: + if not expr: + self.fail("invalid syntax for function call expression", token.lineno) + + while self.stream.current.type != "rparen": + if require_comma: + self.stream.expect("comma") + + # support for trailing comma + if self.stream.current.type == "rparen": + break + + if self.stream.current.type == "mul": + ensure(dyn_args is None and dyn_kwargs is None) + next(self.stream) + dyn_args = self.parse_expression() + elif self.stream.current.type == "pow": + ensure(dyn_kwargs is None) + next(self.stream) + dyn_kwargs = self.parse_expression() + else: + if ( + self.stream.current.type == "name" + and self.stream.look().type == "assign" + ): + # Parsing a kwarg + ensure(dyn_kwargs is None) + key = self.stream.current.value + self.stream.skip(2) + value = self.parse_expression() + kwargs.append(nodes.Keyword(key, value, lineno=value.lineno)) + else: + # Parsing an arg + ensure(dyn_args is None and dyn_kwargs is None and not kwargs) + args.append(self.parse_expression()) + + require_comma = True + + self.stream.expect("rparen") + return args, kwargs, dyn_args, dyn_kwargs + + def parse_call(self, node: nodes.Expr) -> nodes.Call: + # The lparen will be expected in parse_call_args, but the lineno + # needs to be recorded before the stream is advanced. + token = self.stream.current + args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args() + return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno) + + def parse_filter( + self, node: t.Optional[nodes.Expr], start_inline: bool = False + ) -> t.Optional[nodes.Expr]: + while self.stream.current.type == "pipe" or start_inline: + if not start_inline: + next(self.stream) + token = self.stream.expect("name") + name = token.value + while self.stream.current.type == "dot": + next(self.stream) + name += "." + self.stream.expect("name").value + if self.stream.current.type == "lparen": + args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args() + else: + args = [] + kwargs = [] + dyn_args = dyn_kwargs = None + node = nodes.Filter( + node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno + ) + start_inline = False + return node + + def parse_test(self, node: nodes.Expr) -> nodes.Expr: + token = next(self.stream) + if self.stream.current.test("name:not"): + next(self.stream) + negated = True + else: + negated = False + name = self.stream.expect("name").value + while self.stream.current.type == "dot": + next(self.stream) + name += "." + self.stream.expect("name").value + dyn_args = dyn_kwargs = None + kwargs = [] + if self.stream.current.type == "lparen": + args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args() + elif self.stream.current.type in { + "name", + "string", + "integer", + "float", + "lparen", + "lbracket", + "lbrace", + } and not self.stream.current.test_any("name:else", "name:or", "name:and"): + if self.stream.current.test("name:is"): + self.fail("You cannot chain multiple tests with is") + arg_node = self.parse_primary() + arg_node = self.parse_postfix(arg_node) + args = [arg_node] + else: + args = [] + node = nodes.Test( + node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno + ) + if negated: + node = nodes.Not(node, lineno=token.lineno) + return node + + def subparse( + self, end_tokens: t.Optional[t.Tuple[str, ...]] = None + ) -> t.List[nodes.Node]: + body: t.List[nodes.Node] = [] + data_buffer: t.List[nodes.Node] = [] + add_data = data_buffer.append + + if end_tokens is not None: + self._end_token_stack.append(end_tokens) + + def flush_data() -> None: + if data_buffer: + lineno = data_buffer[0].lineno + body.append(nodes.Output(data_buffer[:], lineno=lineno)) + del data_buffer[:] + + try: + while self.stream: + token = self.stream.current + if token.type == "data": + if token.value: + add_data(nodes.TemplateData(token.value, lineno=token.lineno)) + next(self.stream) + elif token.type == "variable_begin": + next(self.stream) + add_data(self.parse_tuple(with_condexpr=True)) + self.stream.expect("variable_end") + elif token.type == "block_begin": + flush_data() + next(self.stream) + if end_tokens is not None and self.stream.current.test_any( + *end_tokens + ): + return body + rv = self.parse_statement() + if isinstance(rv, list): + body.extend(rv) + else: + body.append(rv) + self.stream.expect("block_end") + else: + raise AssertionError("internal parsing error") + + flush_data() + finally: + if end_tokens is not None: + self._end_token_stack.pop() + return body + + def parse(self) -> nodes.Template: + """Parse the whole template into a `Template` node.""" + result = nodes.Template(self.subparse(), lineno=1) + result.set_environment(self.environment) + return result diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/py.typed b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/runtime.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/runtime.py new file mode 100644 index 0000000000000000000000000000000000000000..985842b284270bcd52855029f13d3da19d718349 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/runtime.py @@ -0,0 +1,1053 @@ +"""The runtime functions and state used by compiled templates.""" +import functools +import sys +import typing as t +from collections import abc +from itertools import chain + +from markupsafe import escape # noqa: F401 +from markupsafe import Markup +from markupsafe import soft_str + +from .async_utils import auto_aiter +from .async_utils import auto_await # noqa: F401 +from .exceptions import TemplateNotFound # noqa: F401 +from .exceptions import TemplateRuntimeError # noqa: F401 +from .exceptions import UndefinedError +from .nodes import EvalContext +from .utils import _PassArg +from .utils import concat +from .utils import internalcode +from .utils import missing +from .utils import Namespace # noqa: F401 +from .utils import object_type_repr +from .utils import pass_eval_context + +V = t.TypeVar("V") +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +if t.TYPE_CHECKING: + import logging + import typing_extensions as te + from .environment import Environment + + class LoopRenderFunc(te.Protocol): + def __call__( + self, + reciter: t.Iterable[V], + loop_render_func: "LoopRenderFunc", + depth: int = 0, + ) -> str: + ... + + +# these variables are exported to the template runtime +exported = [ + "LoopContext", + "TemplateReference", + "Macro", + "Markup", + "TemplateRuntimeError", + "missing", + "escape", + "markup_join", + "str_join", + "identity", + "TemplateNotFound", + "Namespace", + "Undefined", + "internalcode", +] +async_exported = [ + "AsyncLoopContext", + "auto_aiter", + "auto_await", +] + + +def identity(x: V) -> V: + """Returns its argument. Useful for certain things in the + environment. + """ + return x + + +def markup_join(seq: t.Iterable[t.Any]) -> str: + """Concatenation that escapes if necessary and converts to string.""" + buf = [] + iterator = map(soft_str, seq) + for arg in iterator: + buf.append(arg) + if hasattr(arg, "__html__"): + return Markup("").join(chain(buf, iterator)) + return concat(buf) + + +def str_join(seq: t.Iterable[t.Any]) -> str: + """Simple args to string conversion and concatenation.""" + return concat(map(str, seq)) + + +def new_context( + environment: "Environment", + template_name: t.Optional[str], + blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]], + vars: t.Optional[t.Dict[str, t.Any]] = None, + shared: bool = False, + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + locals: t.Optional[t.Mapping[str, t.Any]] = None, +) -> "Context": + """Internal helper for context creation.""" + if vars is None: + vars = {} + if shared: + parent = vars + else: + parent = dict(globals or (), **vars) + if locals: + # if the parent is shared a copy should be created because + # we don't want to modify the dict passed + if shared: + parent = dict(parent) + for key, value in locals.items(): + if value is not missing: + parent[key] = value + return environment.context_class( + environment, parent, template_name, blocks, globals=globals + ) + + +class TemplateReference: + """The `self` in templates.""" + + def __init__(self, context: "Context") -> None: + self.__context = context + + def __getitem__(self, name: str) -> t.Any: + blocks = self.__context.blocks[name] + return BlockReference(name, self.__context, blocks, 0) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.__context.name!r}>" + + +def _dict_method_all(dict_method: F) -> F: + @functools.wraps(dict_method) + def f_all(self: "Context") -> t.Any: + return dict_method(self.get_all()) + + return t.cast(F, f_all) + + +@abc.Mapping.register +class Context: + """The template context holds the variables of a template. It stores the + values passed to the template and also the names the template exports. + Creating instances is neither supported nor useful as it's created + automatically at various stages of the template evaluation and should not + be created by hand. + + The context is immutable. Modifications on :attr:`parent` **must not** + happen and modifications on :attr:`vars` are allowed from generated + template code only. Template filters and global functions marked as + :func:`pass_context` get the active context passed as first argument + and are allowed to access the context read-only. + + The template context supports read only dict operations (`get`, + `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, + `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` + method that doesn't fail with a `KeyError` but returns an + :class:`Undefined` object for missing variables. + """ + + def __init__( + self, + environment: "Environment", + parent: t.Dict[str, t.Any], + name: t.Optional[str], + blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]], + globals: t.Optional[t.MutableMapping[str, t.Any]] = None, + ): + self.parent = parent + self.vars: t.Dict[str, t.Any] = {} + self.environment: "Environment" = environment + self.eval_ctx = EvalContext(self.environment, name) + self.exported_vars: t.Set[str] = set() + self.name = name + self.globals_keys = set() if globals is None else set(globals) + + # create the initial mapping of blocks. Whenever template inheritance + # takes place the runtime will update this mapping with the new blocks + # from the template. + self.blocks = {k: [v] for k, v in blocks.items()} + + def super( + self, name: str, current: t.Callable[["Context"], t.Iterator[str]] + ) -> t.Union["BlockReference", "Undefined"]: + """Render a parent block.""" + try: + blocks = self.blocks[name] + index = blocks.index(current) + 1 + blocks[index] + except LookupError: + return self.environment.undefined( + f"there is no parent block called {name!r}.", name="super" + ) + return BlockReference(name, self, blocks, index) + + def get(self, key: str, default: t.Any = None) -> t.Any: + """Look up a variable by name, or return a default if the key is + not found. + + :param key: The variable name to look up. + :param default: The value to return if the key is not found. + """ + try: + return self[key] + except KeyError: + return default + + def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]: + """Look up a variable by name, or return an :class:`Undefined` + object if the key is not found. + + If you need to add custom behavior, override + :meth:`resolve_or_missing`, not this method. The various lookup + functions use that method, not this one. + + :param key: The variable name to look up. + """ + rv = self.resolve_or_missing(key) + + if rv is missing: + return self.environment.undefined(name=key) + + return rv + + def resolve_or_missing(self, key: str) -> t.Any: + """Look up a variable by name, or return a ``missing`` sentinel + if the key is not found. + + Override this method to add custom lookup behavior. + :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this + method. Don't call this method directly. + + :param key: The variable name to look up. + """ + if key in self.vars: + return self.vars[key] + + if key in self.parent: + return self.parent[key] + + return missing + + def get_exported(self) -> t.Dict[str, t.Any]: + """Get a new dict with the exported variables.""" + return {k: self.vars[k] for k in self.exported_vars} + + def get_all(self) -> t.Dict[str, t.Any]: + """Return the complete context as dict including the exported + variables. For optimizations reasons this might not return an + actual copy so be careful with using it. + """ + if not self.vars: + return self.parent + if not self.parent: + return self.vars + return dict(self.parent, **self.vars) + + @internalcode + def call( + __self, __obj: t.Callable, *args: t.Any, **kwargs: t.Any # noqa: B902 + ) -> t.Union[t.Any, "Undefined"]: + """Call the callable with the arguments and keyword arguments + provided but inject the active context or environment as first + argument if the callable has :func:`pass_context` or + :func:`pass_environment`. + """ + if __debug__: + __traceback_hide__ = True # noqa + + # Allow callable classes to take a context + if ( + hasattr(__obj, "__call__") # noqa: B004 + and _PassArg.from_obj(__obj.__call__) is not None # type: ignore + ): + __obj = __obj.__call__ # type: ignore + + pass_arg = _PassArg.from_obj(__obj) + + if pass_arg is _PassArg.context: + # the active context should have access to variables set in + # loops and blocks without mutating the context itself + if kwargs.get("_loop_vars"): + __self = __self.derived(kwargs["_loop_vars"]) + if kwargs.get("_block_vars"): + __self = __self.derived(kwargs["_block_vars"]) + args = (__self,) + args + elif pass_arg is _PassArg.eval_context: + args = (__self.eval_ctx,) + args + elif pass_arg is _PassArg.environment: + args = (__self.environment,) + args + + kwargs.pop("_block_vars", None) + kwargs.pop("_loop_vars", None) + + try: + return __obj(*args, **kwargs) + except StopIteration: + return __self.environment.undefined( + "value was undefined because a callable raised a" + " StopIteration exception" + ) + + def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context": + """Internal helper function to create a derived context. This is + used in situations where the system needs a new context in the same + template that is independent. + """ + context = new_context( + self.environment, self.name, {}, self.get_all(), True, None, locals + ) + context.eval_ctx = self.eval_ctx + context.blocks.update((k, list(v)) for k, v in self.blocks.items()) + return context + + keys = _dict_method_all(dict.keys) + values = _dict_method_all(dict.values) + items = _dict_method_all(dict.items) + + def __contains__(self, name: str) -> bool: + return name in self.vars or name in self.parent + + def __getitem__(self, key: str) -> t.Any: + """Look up a variable by name with ``[]`` syntax, or raise a + ``KeyError`` if the key is not found. + """ + item = self.resolve_or_missing(key) + + if item is missing: + raise KeyError(key) + + return item + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>" + + +class BlockReference: + """One block on a template reference.""" + + def __init__( + self, + name: str, + context: "Context", + stack: t.List[t.Callable[["Context"], t.Iterator[str]]], + depth: int, + ) -> None: + self.name = name + self._context = context + self._stack = stack + self._depth = depth + + @property + def super(self) -> t.Union["BlockReference", "Undefined"]: + """Super the block.""" + if self._depth + 1 >= len(self._stack): + return self._context.environment.undefined( + f"there is no parent block called {self.name!r}.", name="super" + ) + return BlockReference(self.name, self._context, self._stack, self._depth + 1) + + @internalcode + async def _async_call(self) -> str: + rv = concat( + [x async for x in self._stack[self._depth](self._context)] # type: ignore + ) + + if self._context.eval_ctx.autoescape: + return Markup(rv) + + return rv + + @internalcode + def __call__(self) -> str: + if self._context.environment.is_async: + return self._async_call() # type: ignore + + rv = concat(self._stack[self._depth](self._context)) + + if self._context.eval_ctx.autoescape: + return Markup(rv) + + return rv + + +class LoopContext: + """A wrapper iterable for dynamic ``for`` loops, with information + about the loop and iteration. + """ + + #: Current iteration of the loop, starting at 0. + index0 = -1 + + _length: t.Optional[int] = None + _after: t.Any = missing + _current: t.Any = missing + _before: t.Any = missing + _last_changed_value: t.Any = missing + + def __init__( + self, + iterable: t.Iterable[V], + undefined: t.Type["Undefined"], + recurse: t.Optional["LoopRenderFunc"] = None, + depth0: int = 0, + ) -> None: + """ + :param iterable: Iterable to wrap. + :param undefined: :class:`Undefined` class to use for next and + previous items. + :param recurse: The function to render the loop body when the + loop is marked recursive. + :param depth0: Incremented when looping recursively. + """ + self._iterable = iterable + self._iterator = self._to_iterator(iterable) + self._undefined = undefined + self._recurse = recurse + #: How many levels deep a recursive loop currently is, starting at 0. + self.depth0 = depth0 + + @staticmethod + def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]: + return iter(iterable) + + @property + def length(self) -> int: + """Length of the iterable. + + If the iterable is a generator or otherwise does not have a + size, it is eagerly evaluated to get a size. + """ + if self._length is not None: + return self._length + + try: + self._length = len(self._iterable) # type: ignore + except TypeError: + iterable = list(self._iterator) + self._iterator = self._to_iterator(iterable) + self._length = len(iterable) + self.index + (self._after is not missing) + + return self._length + + def __len__(self) -> int: + return self.length + + @property + def depth(self) -> int: + """How many levels deep a recursive loop currently is, starting at 1.""" + return self.depth0 + 1 + + @property + def index(self) -> int: + """Current iteration of the loop, starting at 1.""" + return self.index0 + 1 + + @property + def revindex0(self) -> int: + """Number of iterations from the end of the loop, ending at 0. + + Requires calculating :attr:`length`. + """ + return self.length - self.index + + @property + def revindex(self) -> int: + """Number of iterations from the end of the loop, ending at 1. + + Requires calculating :attr:`length`. + """ + return self.length - self.index0 + + @property + def first(self) -> bool: + """Whether this is the first iteration of the loop.""" + return self.index0 == 0 + + def _peek_next(self) -> t.Any: + """Return the next element in the iterable, or :data:`missing` + if the iterable is exhausted. Only peeks one item ahead, caching + the result in :attr:`_last` for use in subsequent checks. The + cache is reset when :meth:`__next__` is called. + """ + if self._after is not missing: + return self._after + + self._after = next(self._iterator, missing) + return self._after + + @property + def last(self) -> bool: + """Whether this is the last iteration of the loop. + + Causes the iterable to advance early. See + :func:`itertools.groupby` for issues this can cause. + The :func:`groupby` filter avoids that issue. + """ + return self._peek_next() is missing + + @property + def previtem(self) -> t.Union[t.Any, "Undefined"]: + """The item in the previous iteration. Undefined during the + first iteration. + """ + if self.first: + return self._undefined("there is no previous item") + + return self._before + + @property + def nextitem(self) -> t.Union[t.Any, "Undefined"]: + """The item in the next iteration. Undefined during the last + iteration. + + Causes the iterable to advance early. See + :func:`itertools.groupby` for issues this can cause. + The :func:`jinja-filters.groupby` filter avoids that issue. + """ + rv = self._peek_next() + + if rv is missing: + return self._undefined("there is no next item") + + return rv + + def cycle(self, *args: V) -> V: + """Return a value from the given args, cycling through based on + the current :attr:`index0`. + + :param args: One or more values to cycle through. + """ + if not args: + raise TypeError("no items for cycling given") + + return args[self.index0 % len(args)] + + def changed(self, *value: t.Any) -> bool: + """Return ``True`` if previously called with a different value + (including when called for the first time). + + :param value: One or more values to compare to the last call. + """ + if self._last_changed_value != value: + self._last_changed_value = value + return True + + return False + + def __iter__(self) -> "LoopContext": + return self + + def __next__(self) -> t.Tuple[t.Any, "LoopContext"]: + if self._after is not missing: + rv = self._after + self._after = missing + else: + rv = next(self._iterator) + + self.index0 += 1 + self._before = self._current + self._current = rv + return rv, self + + @internalcode + def __call__(self, iterable: t.Iterable[V]) -> str: + """When iterating over nested data, render the body of the loop + recursively with the given inner iterable data. + + The loop must have the ``recursive`` marker for this to work. + """ + if self._recurse is None: + raise TypeError( + "The loop must have the 'recursive' marker to be called recursively." + ) + + return self._recurse(iterable, self._recurse, depth=self.depth) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.index}/{self.length}>" + + +class AsyncLoopContext(LoopContext): + _iterator: t.AsyncIterator[t.Any] # type: ignore + + @staticmethod + def _to_iterator( # type: ignore + iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]] + ) -> t.AsyncIterator[V]: + return auto_aiter(iterable) + + @property + async def length(self) -> int: # type: ignore + if self._length is not None: + return self._length + + try: + self._length = len(self._iterable) # type: ignore + except TypeError: + iterable = [x async for x in self._iterator] + self._iterator = self._to_iterator(iterable) + self._length = len(iterable) + self.index + (self._after is not missing) + + return self._length + + @property + async def revindex0(self) -> int: # type: ignore + return await self.length - self.index + + @property + async def revindex(self) -> int: # type: ignore + return await self.length - self.index0 + + async def _peek_next(self) -> t.Any: + if self._after is not missing: + return self._after + + try: + self._after = await self._iterator.__anext__() + except StopAsyncIteration: + self._after = missing + + return self._after + + @property + async def last(self) -> bool: # type: ignore + return await self._peek_next() is missing + + @property + async def nextitem(self) -> t.Union[t.Any, "Undefined"]: + rv = await self._peek_next() + + if rv is missing: + return self._undefined("there is no next item") + + return rv + + def __aiter__(self) -> "AsyncLoopContext": + return self + + async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]: + if self._after is not missing: + rv = self._after + self._after = missing + else: + rv = await self._iterator.__anext__() + + self.index0 += 1 + self._before = self._current + self._current = rv + return rv, self + + +class Macro: + """Wraps a macro function.""" + + def __init__( + self, + environment: "Environment", + func: t.Callable[..., str], + name: str, + arguments: t.List[str], + catch_kwargs: bool, + catch_varargs: bool, + caller: bool, + default_autoescape: t.Optional[bool] = None, + ): + self._environment = environment + self._func = func + self._argument_count = len(arguments) + self.name = name + self.arguments = arguments + self.catch_kwargs = catch_kwargs + self.catch_varargs = catch_varargs + self.caller = caller + self.explicit_caller = "caller" in arguments + + if default_autoescape is None: + if callable(environment.autoescape): + default_autoescape = environment.autoescape(None) + else: + default_autoescape = environment.autoescape + + self._default_autoescape = default_autoescape + + @internalcode + @pass_eval_context + def __call__(self, *args: t.Any, **kwargs: t.Any) -> str: + # This requires a bit of explanation, In the past we used to + # decide largely based on compile-time information if a macro is + # safe or unsafe. While there was a volatile mode it was largely + # unused for deciding on escaping. This turns out to be + # problematic for macros because whether a macro is safe depends not + # on the escape mode when it was defined, but rather when it was used. + # + # Because however we export macros from the module system and + # there are historic callers that do not pass an eval context (and + # will continue to not pass one), we need to perform an instance + # check here. + # + # This is considered safe because an eval context is not a valid + # argument to callables otherwise anyway. Worst case here is + # that if no eval context is passed we fall back to the compile + # time autoescape flag. + if args and isinstance(args[0], EvalContext): + autoescape = args[0].autoescape + args = args[1:] + else: + autoescape = self._default_autoescape + + # try to consume the positional arguments + arguments = list(args[: self._argument_count]) + off = len(arguments) + + # For information why this is necessary refer to the handling + # of caller in the `macro_body` handler in the compiler. + found_caller = False + + # if the number of arguments consumed is not the number of + # arguments expected we start filling in keyword arguments + # and defaults. + if off != self._argument_count: + for name in self.arguments[len(arguments) :]: + try: + value = kwargs.pop(name) + except KeyError: + value = missing + if name == "caller": + found_caller = True + arguments.append(value) + else: + found_caller = self.explicit_caller + + # it's important that the order of these arguments does not change + # if not also changed in the compiler's `function_scoping` method. + # the order is caller, keyword arguments, positional arguments! + if self.caller and not found_caller: + caller = kwargs.pop("caller", None) + if caller is None: + caller = self._environment.undefined("No caller defined", name="caller") + arguments.append(caller) + + if self.catch_kwargs: + arguments.append(kwargs) + elif kwargs: + if "caller" in kwargs: + raise TypeError( + f"macro {self.name!r} was invoked with two values for the special" + " caller argument. This is most likely a bug." + ) + raise TypeError( + f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}" + ) + if self.catch_varargs: + arguments.append(args[self._argument_count :]) + elif len(args) > self._argument_count: + raise TypeError( + f"macro {self.name!r} takes not more than" + f" {len(self.arguments)} argument(s)" + ) + + return self._invoke(arguments, autoescape) + + async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: + rv = await self._func(*arguments) # type: ignore + + if autoescape: + return Markup(rv) + + return rv # type: ignore + + def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: + if self._environment.is_async: + return self._async_invoke(arguments, autoescape) # type: ignore + + rv = self._func(*arguments) + + if autoescape: + rv = Markup(rv) + + return rv + + def __repr__(self) -> str: + name = "anonymous" if self.name is None else repr(self.name) + return f"<{type(self).__name__} {name}>" + + +class Undefined: + """The default undefined type. This undefined type can be printed and + iterated over, but every other access will raise an :exc:`UndefinedError`: + + >>> foo = Undefined(name='foo') + >>> str(foo) + '' + >>> not foo + True + >>> foo + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + """ + + __slots__ = ( + "_undefined_hint", + "_undefined_obj", + "_undefined_name", + "_undefined_exception", + ) + + def __init__( + self, + hint: t.Optional[str] = None, + obj: t.Any = missing, + name: t.Optional[str] = None, + exc: t.Type[TemplateRuntimeError] = UndefinedError, + ) -> None: + self._undefined_hint = hint + self._undefined_obj = obj + self._undefined_name = name + self._undefined_exception = exc + + @property + def _undefined_message(self) -> str: + """Build a message about the undefined value based on how it was + accessed. + """ + if self._undefined_hint: + return self._undefined_hint + + if self._undefined_obj is missing: + return f"{self._undefined_name!r} is undefined" + + if not isinstance(self._undefined_name, str): + return ( + f"{object_type_repr(self._undefined_obj)} has no" + f" element {self._undefined_name!r}" + ) + + return ( + f"{object_type_repr(self._undefined_obj)!r} has no" + f" attribute {self._undefined_name!r}" + ) + + @internalcode + def _fail_with_undefined_error( + self, *args: t.Any, **kwargs: t.Any + ) -> "te.NoReturn": + """Raise an :exc:`UndefinedError` when operations are performed + on the undefined value. + """ + raise self._undefined_exception(self._undefined_message) + + @internalcode + def __getattr__(self, name: str) -> t.Any: + if name[:2] == "__": + raise AttributeError(name) + + return self._fail_with_undefined_error() + + __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error + __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error + __truediv__ = __rtruediv__ = _fail_with_undefined_error + __floordiv__ = __rfloordiv__ = _fail_with_undefined_error + __mod__ = __rmod__ = _fail_with_undefined_error + __pos__ = __neg__ = _fail_with_undefined_error + __call__ = __getitem__ = _fail_with_undefined_error + __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error + __int__ = __float__ = __complex__ = _fail_with_undefined_error + __pow__ = __rpow__ = _fail_with_undefined_error + + def __eq__(self, other: t.Any) -> bool: + return type(self) is type(other) + + def __ne__(self, other: t.Any) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return id(type(self)) + + def __str__(self) -> str: + return "" + + def __len__(self) -> int: + return 0 + + def __iter__(self) -> t.Iterator[t.Any]: + yield from () + + async def __aiter__(self) -> t.AsyncIterator[t.Any]: + for _ in (): + yield + + def __bool__(self) -> bool: + return False + + def __repr__(self) -> str: + return "Undefined" + + +def make_logging_undefined( + logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined +) -> t.Type[Undefined]: + """Given a logger object this returns a new undefined class that will + log certain failures. It will log iterations and printing. If no + logger is given a default logger is created. + + Example:: + + logger = logging.getLogger(__name__) + LoggingUndefined = make_logging_undefined( + logger=logger, + base=Undefined + ) + + .. versionadded:: 2.8 + + :param logger: the logger to use. If not provided, a default logger + is created. + :param base: the base class to add logging functionality to. This + defaults to :class:`Undefined`. + """ + if logger is None: + import logging + + logger = logging.getLogger(__name__) + logger.addHandler(logging.StreamHandler(sys.stderr)) + + def _log_message(undef: Undefined) -> None: + logger.warning( # type: ignore + "Template variable warning: %s", undef._undefined_message + ) + + class LoggingUndefined(base): # type: ignore + __slots__ = () + + def _fail_with_undefined_error( # type: ignore + self, *args: t.Any, **kwargs: t.Any + ) -> "te.NoReturn": + try: + super()._fail_with_undefined_error(*args, **kwargs) + except self._undefined_exception as e: + logger.error("Template variable error: %s", e) # type: ignore + raise e + + def __str__(self) -> str: + _log_message(self) + return super().__str__() # type: ignore + + def __iter__(self) -> t.Iterator[t.Any]: + _log_message(self) + return super().__iter__() # type: ignore + + def __bool__(self) -> bool: + _log_message(self) + return super().__bool__() # type: ignore + + return LoggingUndefined + + +class ChainableUndefined(Undefined): + """An undefined that is chainable, where both ``__getattr__`` and + ``__getitem__`` return itself rather than raising an + :exc:`UndefinedError`. + + >>> foo = ChainableUndefined(name='foo') + >>> str(foo.bar['baz']) + '' + >>> foo.bar['baz'] + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + + .. versionadded:: 2.11.0 + """ + + __slots__ = () + + def __html__(self) -> str: + return str(self) + + def __getattr__(self, _: str) -> "ChainableUndefined": + return self + + __getitem__ = __getattr__ # type: ignore + + +class DebugUndefined(Undefined): + """An undefined that returns the debug info when printed. + + >>> foo = DebugUndefined(name='foo') + >>> str(foo) + '{{ foo }}' + >>> not foo + True + >>> foo + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + """ + + __slots__ = () + + def __str__(self) -> str: + if self._undefined_hint: + message = f"undefined value printed: {self._undefined_hint}" + + elif self._undefined_obj is missing: + message = self._undefined_name # type: ignore + + else: + message = ( + f"no such element: {object_type_repr(self._undefined_obj)}" + f"[{self._undefined_name!r}]" + ) + + return f"{{{{ {message} }}}}" + + +class StrictUndefined(Undefined): + """An undefined that barks on print and iteration as well as boolean + tests and all kinds of comparisons. In other words: you can do nothing + with it except checking if it's defined using the `defined` test. + + >>> foo = StrictUndefined(name='foo') + >>> str(foo) + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + >>> not foo + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + >>> foo + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + """ + + __slots__ = () + __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error + __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error + __contains__ = Undefined._fail_with_undefined_error + + +# Remove slots attributes, after the metaclass is applied they are +# unneeded and contain wrong data for subclasses. +del ( + Undefined.__slots__, + ChainableUndefined.__slots__, + DebugUndefined.__slots__, + StrictUndefined.__slots__, +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/sandbox.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/sandbox.py new file mode 100644 index 0000000000000000000000000000000000000000..06d74148eccea79d1f5a0ca2fb76ecc246f87d62 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/sandbox.py @@ -0,0 +1,428 @@ +"""A sandbox layer that ensures unsafe operations cannot be performed. +Useful when the template itself comes from an untrusted source. +""" +import operator +import types +import typing as t +from _string import formatter_field_name_split # type: ignore +from collections import abc +from collections import deque +from string import Formatter + +from markupsafe import EscapeFormatter +from markupsafe import Markup + +from .environment import Environment +from .exceptions import SecurityError +from .runtime import Context +from .runtime import Undefined + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +#: maximum number of items a range may produce +MAX_RANGE = 100000 + +#: Unsafe function attributes. +UNSAFE_FUNCTION_ATTRIBUTES: t.Set[str] = set() + +#: Unsafe method attributes. Function attributes are unsafe for methods too. +UNSAFE_METHOD_ATTRIBUTES: t.Set[str] = set() + +#: unsafe generator attributes. +UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"} + +#: unsafe attributes on coroutines +UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"} + +#: unsafe attributes on async generators +UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"} + +_mutable_spec: t.Tuple[t.Tuple[t.Type, t.FrozenSet[str]], ...] = ( + ( + abc.MutableSet, + frozenset( + [ + "add", + "clear", + "difference_update", + "discard", + "pop", + "remove", + "symmetric_difference_update", + "update", + ] + ), + ), + ( + abc.MutableMapping, + frozenset(["clear", "pop", "popitem", "setdefault", "update"]), + ), + ( + abc.MutableSequence, + frozenset(["append", "reverse", "insert", "sort", "extend", "remove"]), + ), + ( + deque, + frozenset( + [ + "append", + "appendleft", + "clear", + "extend", + "extendleft", + "pop", + "popleft", + "remove", + "rotate", + ] + ), + ), +) + + +def inspect_format_method(callable: t.Callable) -> t.Optional[str]: + if not isinstance( + callable, (types.MethodType, types.BuiltinMethodType) + ) or callable.__name__ not in ("format", "format_map"): + return None + + obj = callable.__self__ + + if isinstance(obj, str): + return obj + + return None + + +def safe_range(*args: int) -> range: + """A range that can't generate ranges with a length of more than + MAX_RANGE items. + """ + rng = range(*args) + + if len(rng) > MAX_RANGE: + raise OverflowError( + "Range too big. The sandbox blocks ranges larger than" + f" MAX_RANGE ({MAX_RANGE})." + ) + + return rng + + +def unsafe(f: F) -> F: + """Marks a function or method as unsafe. + + .. code-block: python + + @unsafe + def delete(self): + pass + """ + f.unsafe_callable = True # type: ignore + return f + + +def is_internal_attribute(obj: t.Any, attr: str) -> bool: + """Test if the attribute given is an internal python attribute. For + example this function returns `True` for the `func_code` attribute of + python objects. This is useful if the environment method + :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden. + + >>> from jinja2.sandbox import is_internal_attribute + >>> is_internal_attribute(str, "mro") + True + >>> is_internal_attribute(str, "upper") + False + """ + if isinstance(obj, types.FunctionType): + if attr in UNSAFE_FUNCTION_ATTRIBUTES: + return True + elif isinstance(obj, types.MethodType): + if attr in UNSAFE_FUNCTION_ATTRIBUTES or attr in UNSAFE_METHOD_ATTRIBUTES: + return True + elif isinstance(obj, type): + if attr == "mro": + return True + elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)): + return True + elif isinstance(obj, types.GeneratorType): + if attr in UNSAFE_GENERATOR_ATTRIBUTES: + return True + elif hasattr(types, "CoroutineType") and isinstance(obj, types.CoroutineType): + if attr in UNSAFE_COROUTINE_ATTRIBUTES: + return True + elif hasattr(types, "AsyncGeneratorType") and isinstance( + obj, types.AsyncGeneratorType + ): + if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES: + return True + return attr.startswith("__") + + +def modifies_known_mutable(obj: t.Any, attr: str) -> bool: + """This function checks if an attribute on a builtin mutable object + (list, dict, set or deque) or the corresponding ABCs would modify it + if called. + + >>> modifies_known_mutable({}, "clear") + True + >>> modifies_known_mutable({}, "keys") + False + >>> modifies_known_mutable([], "append") + True + >>> modifies_known_mutable([], "index") + False + + If called with an unsupported object, ``False`` is returned. + + >>> modifies_known_mutable("foo", "upper") + False + """ + for typespec, unsafe in _mutable_spec: + if isinstance(obj, typespec): + return attr in unsafe + return False + + +class SandboxedEnvironment(Environment): + """The sandboxed environment. It works like the regular environment but + tells the compiler to generate sandboxed code. Additionally subclasses of + this environment may override the methods that tell the runtime what + attributes or functions are safe to access. + + If the template tries to access insecure code a :exc:`SecurityError` is + raised. However also other exceptions may occur during the rendering so + the caller has to ensure that all exceptions are caught. + """ + + sandboxed = True + + #: default callback table for the binary operators. A copy of this is + #: available on each instance of a sandboxed environment as + #: :attr:`binop_table` + default_binop_table: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { + "+": operator.add, + "-": operator.sub, + "*": operator.mul, + "/": operator.truediv, + "//": operator.floordiv, + "**": operator.pow, + "%": operator.mod, + } + + #: default callback table for the unary operators. A copy of this is + #: available on each instance of a sandboxed environment as + #: :attr:`unop_table` + default_unop_table: t.Dict[str, t.Callable[[t.Any], t.Any]] = { + "+": operator.pos, + "-": operator.neg, + } + + #: a set of binary operators that should be intercepted. Each operator + #: that is added to this set (empty by default) is delegated to the + #: :meth:`call_binop` method that will perform the operator. The default + #: operator callback is specified by :attr:`binop_table`. + #: + #: The following binary operators are interceptable: + #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` + #: + #: The default operation form the operator table corresponds to the + #: builtin function. Intercepted calls are always slower than the native + #: operator call, so make sure only to intercept the ones you are + #: interested in. + #: + #: .. versionadded:: 2.6 + intercepted_binops: t.FrozenSet[str] = frozenset() + + #: a set of unary operators that should be intercepted. Each operator + #: that is added to this set (empty by default) is delegated to the + #: :meth:`call_unop` method that will perform the operator. The default + #: operator callback is specified by :attr:`unop_table`. + #: + #: The following unary operators are interceptable: ``+``, ``-`` + #: + #: The default operation form the operator table corresponds to the + #: builtin function. Intercepted calls are always slower than the native + #: operator call, so make sure only to intercept the ones you are + #: interested in. + #: + #: .. versionadded:: 2.6 + intercepted_unops: t.FrozenSet[str] = frozenset() + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.globals["range"] = safe_range + self.binop_table = self.default_binop_table.copy() + self.unop_table = self.default_unop_table.copy() + + def is_safe_attribute(self, obj: t.Any, attr: str, value: t.Any) -> bool: + """The sandboxed environment will call this method to check if the + attribute of an object is safe to access. Per default all attributes + starting with an underscore are considered private as well as the + special attributes of internal python objects as returned by the + :func:`is_internal_attribute` function. + """ + return not (attr.startswith("_") or is_internal_attribute(obj, attr)) + + def is_safe_callable(self, obj: t.Any) -> bool: + """Check if an object is safely callable. By default callables + are considered safe unless decorated with :func:`unsafe`. + + This also recognizes the Django convention of setting + ``func.alters_data = True``. + """ + return not ( + getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False) + ) + + def call_binop( + self, context: Context, operator: str, left: t.Any, right: t.Any + ) -> t.Any: + """For intercepted binary operator calls (:meth:`intercepted_binops`) + this function is executed instead of the builtin operator. This can + be used to fine tune the behavior of certain operators. + + .. versionadded:: 2.6 + """ + return self.binop_table[operator](left, right) + + def call_unop(self, context: Context, operator: str, arg: t.Any) -> t.Any: + """For intercepted unary operator calls (:meth:`intercepted_unops`) + this function is executed instead of the builtin operator. This can + be used to fine tune the behavior of certain operators. + + .. versionadded:: 2.6 + """ + return self.unop_table[operator](arg) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Subscribe an object from sandboxed code.""" + try: + return obj[argument] + except (TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + value = getattr(obj, attr) + except AttributeError: + pass + else: + if self.is_safe_attribute(obj, argument, value): + return value + return self.unsafe_undefined(obj, argument) + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Union[t.Any, Undefined]: + """Subscribe an object from sandboxed code and prefer the + attribute. The attribute passed *must* be a bytestring. + """ + try: + value = getattr(obj, attribute) + except AttributeError: + try: + return obj[attribute] + except (TypeError, LookupError): + pass + else: + if self.is_safe_attribute(obj, attribute, value): + return value + return self.unsafe_undefined(obj, attribute) + return self.undefined(obj=obj, name=attribute) + + def unsafe_undefined(self, obj: t.Any, attribute: str) -> Undefined: + """Return an undefined object for unsafe attributes.""" + return self.undefined( + f"access to attribute {attribute!r} of" + f" {type(obj).__name__!r} object is unsafe.", + name=attribute, + obj=obj, + exc=SecurityError, + ) + + def format_string( + self, + s: str, + args: t.Tuple[t.Any, ...], + kwargs: t.Dict[str, t.Any], + format_func: t.Optional[t.Callable] = None, + ) -> str: + """If a format call is detected, then this is routed through this + method so that our safety sandbox can be used for it. + """ + formatter: SandboxedFormatter + if isinstance(s, Markup): + formatter = SandboxedEscapeFormatter(self, escape=s.escape) + else: + formatter = SandboxedFormatter(self) + + if format_func is not None and format_func.__name__ == "format_map": + if len(args) != 1 or kwargs: + raise TypeError( + "format_map() takes exactly one argument" + f" {len(args) + (kwargs is not None)} given" + ) + + kwargs = args[0] + args = () + + rv = formatter.vformat(s, args, kwargs) + return type(s)(rv) + + def call( + __self, # noqa: B902 + __context: Context, + __obj: t.Any, + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + """Call an object from sandboxed code.""" + fmt = inspect_format_method(__obj) + if fmt is not None: + return __self.format_string(fmt, args, kwargs, __obj) + + # the double prefixes are to avoid double keyword argument + # errors when proxying the call. + if not __self.is_safe_callable(__obj): + raise SecurityError(f"{__obj!r} is not safely callable") + return __context.call(__obj, *args, **kwargs) + + +class ImmutableSandboxedEnvironment(SandboxedEnvironment): + """Works exactly like the regular `SandboxedEnvironment` but does not + permit modifications on the builtin mutable objects `list`, `set`, and + `dict` by using the :func:`modifies_known_mutable` function. + """ + + def is_safe_attribute(self, obj: t.Any, attr: str, value: t.Any) -> bool: + if not super().is_safe_attribute(obj, attr, value): + return False + + return not modifies_known_mutable(obj, attr) + + +class SandboxedFormatter(Formatter): + def __init__(self, env: Environment, **kwargs: t.Any) -> None: + self._env = env + super().__init__(**kwargs) + + def get_field( + self, field_name: str, args: t.Sequence[t.Any], kwargs: t.Mapping[str, t.Any] + ) -> t.Tuple[t.Any, str]: + first, rest = formatter_field_name_split(field_name) + obj = self.get_value(first, args, kwargs) + for is_attr, i in rest: + if is_attr: + obj = self._env.getattr(obj, i) + else: + obj = self._env.getitem(obj, i) + return obj, first + + +class SandboxedEscapeFormatter(SandboxedFormatter, EscapeFormatter): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/tests.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..a467cf08b54879ee734617611aef72ed946d4566 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/tests.py @@ -0,0 +1,255 @@ +"""Built-in template tests used with the ``is`` operator.""" +import operator +import typing as t +from collections import abc +from numbers import Number + +from .runtime import Undefined +from .utils import pass_environment + +if t.TYPE_CHECKING: + from .environment import Environment + + +def test_odd(value: int) -> bool: + """Return true if the variable is odd.""" + return value % 2 == 1 + + +def test_even(value: int) -> bool: + """Return true if the variable is even.""" + return value % 2 == 0 + + +def test_divisibleby(value: int, num: int) -> bool: + """Check if a variable is divisible by a number.""" + return value % num == 0 + + +def test_defined(value: t.Any) -> bool: + """Return true if the variable is defined: + + .. sourcecode:: jinja + + {% if variable is defined %} + value of variable: {{ variable }} + {% else %} + variable is not defined + {% endif %} + + See the :func:`default` filter for a simple way to set undefined + variables. + """ + return not isinstance(value, Undefined) + + +def test_undefined(value: t.Any) -> bool: + """Like :func:`defined` but the other way round.""" + return isinstance(value, Undefined) + + +@pass_environment +def test_filter(env: "Environment", value: str) -> bool: + """Check if a filter exists by name. Useful if a filter may be + optionally available. + + .. code-block:: jinja + + {% if 'markdown' is filter %} + {{ value | markdown }} + {% else %} + {{ value }} + {% endif %} + + .. versionadded:: 3.0 + """ + return value in env.filters + + +@pass_environment +def test_test(env: "Environment", value: str) -> bool: + """Check if a test exists by name. Useful if a test may be + optionally available. + + .. code-block:: jinja + + {% if 'loud' is test %} + {% if value is loud %} + {{ value|upper }} + {% else %} + {{ value|lower }} + {% endif %} + {% else %} + {{ value }} + {% endif %} + + .. versionadded:: 3.0 + """ + return value in env.tests + + +def test_none(value: t.Any) -> bool: + """Return true if the variable is none.""" + return value is None + + +def test_boolean(value: t.Any) -> bool: + """Return true if the object is a boolean value. + + .. versionadded:: 2.11 + """ + return value is True or value is False + + +def test_false(value: t.Any) -> bool: + """Return true if the object is False. + + .. versionadded:: 2.11 + """ + return value is False + + +def test_true(value: t.Any) -> bool: + """Return true if the object is True. + + .. versionadded:: 2.11 + """ + return value is True + + +# NOTE: The existing 'number' test matches booleans and floats +def test_integer(value: t.Any) -> bool: + """Return true if the object is an integer. + + .. versionadded:: 2.11 + """ + return isinstance(value, int) and value is not True and value is not False + + +# NOTE: The existing 'number' test matches booleans and integers +def test_float(value: t.Any) -> bool: + """Return true if the object is a float. + + .. versionadded:: 2.11 + """ + return isinstance(value, float) + + +def test_lower(value: str) -> bool: + """Return true if the variable is lowercased.""" + return str(value).islower() + + +def test_upper(value: str) -> bool: + """Return true if the variable is uppercased.""" + return str(value).isupper() + + +def test_string(value: t.Any) -> bool: + """Return true if the object is a string.""" + return isinstance(value, str) + + +def test_mapping(value: t.Any) -> bool: + """Return true if the object is a mapping (dict etc.). + + .. versionadded:: 2.6 + """ + return isinstance(value, abc.Mapping) + + +def test_number(value: t.Any) -> bool: + """Return true if the variable is a number.""" + return isinstance(value, Number) + + +def test_sequence(value: t.Any) -> bool: + """Return true if the variable is a sequence. Sequences are variables + that are iterable. + """ + try: + len(value) + value.__getitem__ + except Exception: + return False + + return True + + +def test_sameas(value: t.Any, other: t.Any) -> bool: + """Check if an object points to the same memory address than another + object: + + .. sourcecode:: jinja + + {% if foo.attribute is sameas false %} + the foo attribute really is the `False` singleton + {% endif %} + """ + return value is other + + +def test_iterable(value: t.Any) -> bool: + """Check if it's possible to iterate over an object.""" + try: + iter(value) + except TypeError: + return False + + return True + + +def test_escaped(value: t.Any) -> bool: + """Check if the value is escaped.""" + return hasattr(value, "__html__") + + +def test_in(value: t.Any, seq: t.Container) -> bool: + """Check if value is in seq. + + .. versionadded:: 2.10 + """ + return value in seq + + +TESTS = { + "odd": test_odd, + "even": test_even, + "divisibleby": test_divisibleby, + "defined": test_defined, + "undefined": test_undefined, + "filter": test_filter, + "test": test_test, + "none": test_none, + "boolean": test_boolean, + "false": test_false, + "true": test_true, + "integer": test_integer, + "float": test_float, + "lower": test_lower, + "upper": test_upper, + "string": test_string, + "mapping": test_mapping, + "number": test_number, + "sequence": test_sequence, + "iterable": test_iterable, + "callable": callable, + "sameas": test_sameas, + "escaped": test_escaped, + "in": test_in, + "==": operator.eq, + "eq": operator.eq, + "equalto": operator.eq, + "!=": operator.ne, + "ne": operator.ne, + ">": operator.gt, + "gt": operator.gt, + "greaterthan": operator.gt, + "ge": operator.ge, + ">=": operator.ge, + "<": operator.lt, + "lt": operator.lt, + "lessthan": operator.lt, + "<=": operator.le, + "le": operator.le, +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..9b5f5a50eb6773c4085f8572a45b3fa351367565 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/utils.py @@ -0,0 +1,755 @@ +import enum +import json +import os +import re +import typing as t +from collections import abc +from collections import deque +from random import choice +from random import randrange +from threading import Lock +from types import CodeType +from urllib.parse import quote_from_bytes + +import markupsafe + +if t.TYPE_CHECKING: + import typing_extensions as te + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +# special singleton representing missing values for the runtime +missing: t.Any = type("MissingType", (), {"__repr__": lambda x: "missing"})() + +internal_code: t.MutableSet[CodeType] = set() + +concat = "".join + + +def pass_context(f: F) -> F: + """Pass the :class:`~jinja2.runtime.Context` as the first argument + to the decorated function when called while rendering a template. + + Can be used on functions, filters, and tests. + + If only ``Context.eval_context`` is needed, use + :func:`pass_eval_context`. If only ``Context.environment`` is + needed, use :func:`pass_environment`. + + .. versionadded:: 3.0.0 + Replaces ``contextfunction`` and ``contextfilter``. + """ + f.jinja_pass_arg = _PassArg.context # type: ignore + return f + + +def pass_eval_context(f: F) -> F: + """Pass the :class:`~jinja2.nodes.EvalContext` as the first argument + to the decorated function when called while rendering a template. + See :ref:`eval-context`. + + Can be used on functions, filters, and tests. + + If only ``EvalContext.environment`` is needed, use + :func:`pass_environment`. + + .. versionadded:: 3.0.0 + Replaces ``evalcontextfunction`` and ``evalcontextfilter``. + """ + f.jinja_pass_arg = _PassArg.eval_context # type: ignore + return f + + +def pass_environment(f: F) -> F: + """Pass the :class:`~jinja2.Environment` as the first argument to + the decorated function when called while rendering a template. + + Can be used on functions, filters, and tests. + + .. versionadded:: 3.0.0 + Replaces ``environmentfunction`` and ``environmentfilter``. + """ + f.jinja_pass_arg = _PassArg.environment # type: ignore + return f + + +class _PassArg(enum.Enum): + context = enum.auto() + eval_context = enum.auto() + environment = enum.auto() + + @classmethod + def from_obj(cls, obj: F) -> t.Optional["_PassArg"]: + if hasattr(obj, "jinja_pass_arg"): + return obj.jinja_pass_arg # type: ignore + + return None + + +def internalcode(f: F) -> F: + """Marks the function as internally used""" + internal_code.add(f.__code__) + return f + + +def is_undefined(obj: t.Any) -> bool: + """Check if the object passed is undefined. This does nothing more than + performing an instance check against :class:`Undefined` but looks nicer. + This can be used for custom filters or tests that want to react to + undefined variables. For example a custom default filter can look like + this:: + + def default(var, default=''): + if is_undefined(var): + return default + return var + """ + from .runtime import Undefined + + return isinstance(obj, Undefined) + + +def consume(iterable: t.Iterable[t.Any]) -> None: + """Consumes an iterable without doing anything with it.""" + for _ in iterable: + pass + + +def clear_caches() -> None: + """Jinja keeps internal caches for environments and lexers. These are + used so that Jinja doesn't have to recreate environments and lexers all + the time. Normally you don't have to care about that but if you are + measuring memory consumption you may want to clean the caches. + """ + from .environment import get_spontaneous_environment + from .lexer import _lexer_cache + + get_spontaneous_environment.cache_clear() + _lexer_cache.clear() + + +def import_string(import_name: str, silent: bool = False) -> t.Any: + """Imports an object based on a string. This is useful if you want to + use import paths as endpoints or something similar. An import path can + be specified either in dotted notation (``xml.sax.saxutils.escape``) + or with a colon as object delimiter (``xml.sax.saxutils:escape``). + + If the `silent` is True the return value will be `None` if the import + fails. + + :return: imported object + """ + try: + if ":" in import_name: + module, obj = import_name.split(":", 1) + elif "." in import_name: + module, _, obj = import_name.rpartition(".") + else: + return __import__(import_name) + return getattr(__import__(module, None, None, [obj]), obj) + except (ImportError, AttributeError): + if not silent: + raise + + +def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]: + """Returns a file descriptor for the filename if that file exists, + otherwise ``None``. + """ + if not os.path.isfile(filename): + return None + + return open(filename, mode) + + +def object_type_repr(obj: t.Any) -> str: + """Returns the name of the object's type. For some recognized + singletons the name of the object is returned instead. (For + example for `None` and `Ellipsis`). + """ + if obj is None: + return "None" + elif obj is Ellipsis: + return "Ellipsis" + + cls = type(obj) + + if cls.__module__ == "builtins": + return f"{cls.__name__} object" + + return f"{cls.__module__}.{cls.__name__} object" + + +def pformat(obj: t.Any) -> str: + """Format an object using :func:`pprint.pformat`.""" + from pprint import pformat # type: ignore + + return pformat(obj) + + +_http_re = re.compile( + r""" + ^ + ( + (https?://|www\.) # scheme or www + (([\w%-]+\.)+)? # subdomain + ( + [a-z]{2,63} # basic tld + | + xn--[\w%]{2,59} # idna tld + ) + | + ([\w%-]{2,63}\.)+ # basic domain + (com|net|int|edu|gov|org|info|mil) # basic tld + | + (https?://) # scheme + ( + (([\d]{1,3})(\.[\d]{1,3}){3}) # IPv4 + | + (\[([\da-f]{0,4}:){2}([\da-f]{0,4}:?){1,6}]) # IPv6 + ) + ) + (?::[\d]{1,5})? # port + (?:[/?#]\S*)? # path, query, and fragment + $ + """, + re.IGNORECASE | re.VERBOSE, +) +_email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$") + + +def urlize( + text: str, + trim_url_limit: t.Optional[int] = None, + rel: t.Optional[str] = None, + target: t.Optional[str] = None, + extra_schemes: t.Optional[t.Iterable[str]] = None, +) -> str: + """Convert URLs in text into clickable links. + + This may not recognize links in some situations. Usually, a more + comprehensive formatter, such as a Markdown library, is a better + choice. + + Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email + addresses. Links with trailing punctuation (periods, commas, closing + parentheses) and leading punctuation (opening parentheses) are + recognized excluding the punctuation. Email addresses that include + header fields are not recognized (for example, + ``mailto:address@example.com?cc=copy@example.com``). + + :param text: Original text containing URLs to link. + :param trim_url_limit: Shorten displayed URL values to this length. + :param target: Add the ``target`` attribute to links. + :param rel: Add the ``rel`` attribute to links. + :param extra_schemes: Recognize URLs that start with these schemes + in addition to the default behavior. + + .. versionchanged:: 3.0 + The ``extra_schemes`` parameter was added. + + .. versionchanged:: 3.0 + Generate ``https://`` links for URLs without a scheme. + + .. versionchanged:: 3.0 + The parsing rules were updated. Recognize email addresses with + or without the ``mailto:`` scheme. Validate IP addresses. Ignore + parentheses and brackets in more cases. + """ + if trim_url_limit is not None: + + def trim_url(x: str) -> str: + if len(x) > trim_url_limit: # type: ignore + return f"{x[:trim_url_limit]}..." + + return x + + else: + + def trim_url(x: str) -> str: + return x + + words = re.split(r"(\s+)", str(markupsafe.escape(text))) + rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else "" + target_attr = f' target="{markupsafe.escape(target)}"' if target else "" + + for i, word in enumerate(words): + head, middle, tail = "", word, "" + match = re.match(r"^([(<]|<)+", middle) + + if match: + head = match.group() + middle = middle[match.end() :] + + # Unlike lead, which is anchored to the start of the string, + # need to check that the string ends with any of the characters + # before trying to match all of them, to avoid backtracking. + if middle.endswith((")", ">", ".", ",", "\n", ">")): + match = re.search(r"([)>.,\n]|>)+$", middle) + + if match: + tail = match.group() + middle = middle[: match.start()] + + # Prefer balancing parentheses in URLs instead of ignoring a + # trailing character. + for start_char, end_char in ("(", ")"), ("<", ">"), ("<", ">"): + start_count = middle.count(start_char) + + if start_count <= middle.count(end_char): + # Balanced, or lighter on the left + continue + + # Move as many as possible from the tail to balance + for _ in range(min(start_count, tail.count(end_char))): + end_index = tail.index(end_char) + len(end_char) + # Move anything in the tail before the end char too + middle += tail[:end_index] + tail = tail[end_index:] + + if _http_re.match(middle): + if middle.startswith("https://") or middle.startswith("http://"): + middle = ( + f'<a href="{middle}"{rel_attr}{target_attr}>{trim_url(middle)}</a>' + ) + else: + middle = ( + f'<a href="https://{middle}"{rel_attr}{target_attr}>' + f"{trim_url(middle)}</a>" + ) + + elif middle.startswith("mailto:") and _email_re.match(middle[7:]): + middle = f'<a href="{middle}">{middle[7:]}</a>' + + elif ( + "@" in middle + and not middle.startswith("www.") + and ":" not in middle + and _email_re.match(middle) + ): + middle = f'<a href="mailto:{middle}">{middle}</a>' + + elif extra_schemes is not None: + for scheme in extra_schemes: + if middle != scheme and middle.startswith(scheme): + middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>' + + words[i] = f"{head}{middle}{tail}" + + return "".join(words) + + +def generate_lorem_ipsum( + n: int = 5, html: bool = True, min: int = 20, max: int = 100 +) -> str: + """Generate some lorem ipsum for the template.""" + from .constants import LOREM_IPSUM_WORDS + + words = LOREM_IPSUM_WORDS.split() + result = [] + + for _ in range(n): + next_capitalized = True + last_comma = last_fullstop = 0 + word = None + last = None + p = [] + + # each paragraph contains out of 20 to 100 words. + for idx, _ in enumerate(range(randrange(min, max))): + while True: + word = choice(words) + if word != last: + last = word + break + if next_capitalized: + word = word.capitalize() + next_capitalized = False + # add commas + if idx - randrange(3, 8) > last_comma: + last_comma = idx + last_fullstop += 2 + word += "," + # add end of sentences + if idx - randrange(10, 20) > last_fullstop: + last_comma = last_fullstop = idx + word += "." + next_capitalized = True + p.append(word) + + # ensure that the paragraph ends with a dot. + p_str = " ".join(p) + + if p_str.endswith(","): + p_str = p_str[:-1] + "." + elif not p_str.endswith("."): + p_str += "." + + result.append(p_str) + + if not html: + return "\n\n".join(result) + return markupsafe.Markup( + "\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result) + ) + + +def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str: + """Quote a string for use in a URL using the given charset. + + :param obj: String or bytes to quote. Other types are converted to + string then encoded to bytes using the given charset. + :param charset: Encode text to bytes using this charset. + :param for_qs: Quote "/" and use "+" for spaces. + """ + if not isinstance(obj, bytes): + if not isinstance(obj, str): + obj = str(obj) + + obj = obj.encode(charset) + + safe = b"" if for_qs else b"/" + rv = quote_from_bytes(obj, safe) + + if for_qs: + rv = rv.replace("%20", "+") + + return rv + + +@abc.MutableMapping.register +class LRUCache: + """A simple LRU Cache implementation.""" + + # this is fast for small capacities (something below 1000) but doesn't + # scale. But as long as it's only used as storage for templates this + # won't do any harm. + + def __init__(self, capacity: int) -> None: + self.capacity = capacity + self._mapping: t.Dict[t.Any, t.Any] = {} + self._queue: "te.Deque[t.Any]" = deque() + self._postinit() + + def _postinit(self) -> None: + # alias all queue methods for faster lookup + self._popleft = self._queue.popleft + self._pop = self._queue.pop + self._remove = self._queue.remove + self._wlock = Lock() + self._append = self._queue.append + + def __getstate__(self) -> t.Mapping[str, t.Any]: + return { + "capacity": self.capacity, + "_mapping": self._mapping, + "_queue": self._queue, + } + + def __setstate__(self, d: t.Mapping[str, t.Any]) -> None: + self.__dict__.update(d) + self._postinit() + + def __getnewargs__(self) -> t.Tuple: + return (self.capacity,) + + def copy(self) -> "LRUCache": + """Return a shallow copy of the instance.""" + rv = self.__class__(self.capacity) + rv._mapping.update(self._mapping) + rv._queue.extend(self._queue) + return rv + + def get(self, key: t.Any, default: t.Any = None) -> t.Any: + """Return an item from the cache dict or `default`""" + try: + return self[key] + except KeyError: + return default + + def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any: + """Set `default` if the key is not in the cache otherwise + leave unchanged. Return the value of this key. + """ + try: + return self[key] + except KeyError: + self[key] = default + return default + + def clear(self) -> None: + """Clear the cache.""" + with self._wlock: + self._mapping.clear() + self._queue.clear() + + def __contains__(self, key: t.Any) -> bool: + """Check if a key exists in this cache.""" + return key in self._mapping + + def __len__(self) -> int: + """Return the current size of the cache.""" + return len(self._mapping) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self._mapping!r}>" + + def __getitem__(self, key: t.Any) -> t.Any: + """Get an item from the cache. Moves the item up so that it has the + highest priority then. + + Raise a `KeyError` if it does not exist. + """ + with self._wlock: + rv = self._mapping[key] + + if self._queue[-1] != key: + try: + self._remove(key) + except ValueError: + # if something removed the key from the container + # when we read, ignore the ValueError that we would + # get otherwise. + pass + + self._append(key) + + return rv + + def __setitem__(self, key: t.Any, value: t.Any) -> None: + """Sets the value for an item. Moves the item up so that it + has the highest priority then. + """ + with self._wlock: + if key in self._mapping: + self._remove(key) + elif len(self._mapping) == self.capacity: + del self._mapping[self._popleft()] + + self._append(key) + self._mapping[key] = value + + def __delitem__(self, key: t.Any) -> None: + """Remove an item from the cache dict. + Raise a `KeyError` if it does not exist. + """ + with self._wlock: + del self._mapping[key] + + try: + self._remove(key) + except ValueError: + pass + + def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]: + """Return a list of items.""" + result = [(key, self._mapping[key]) for key in list(self._queue)] + result.reverse() + return result + + def values(self) -> t.Iterable[t.Any]: + """Return a list of all values.""" + return [x[1] for x in self.items()] + + def keys(self) -> t.Iterable[t.Any]: + """Return a list of all keys ordered by most recent usage.""" + return list(self) + + def __iter__(self) -> t.Iterator[t.Any]: + return reversed(tuple(self._queue)) + + def __reversed__(self) -> t.Iterator[t.Any]: + """Iterate over the keys in the cache dict, oldest items + coming first. + """ + return iter(tuple(self._queue)) + + __copy__ = copy + + +def select_autoescape( + enabled_extensions: t.Collection[str] = ("html", "htm", "xml"), + disabled_extensions: t.Collection[str] = (), + default_for_string: bool = True, + default: bool = False, +) -> t.Callable[[t.Optional[str]], bool]: + """Intelligently sets the initial value of autoescaping based on the + filename of the template. This is the recommended way to configure + autoescaping if you do not want to write a custom function yourself. + + If you want to enable it for all templates created from strings or + for all templates with `.html` and `.xml` extensions:: + + from jinja2 import Environment, select_autoescape + env = Environment(autoescape=select_autoescape( + enabled_extensions=('html', 'xml'), + default_for_string=True, + )) + + Example configuration to turn it on at all times except if the template + ends with `.txt`:: + + from jinja2 import Environment, select_autoescape + env = Environment(autoescape=select_autoescape( + disabled_extensions=('txt',), + default_for_string=True, + default=True, + )) + + The `enabled_extensions` is an iterable of all the extensions that + autoescaping should be enabled for. Likewise `disabled_extensions` is + a list of all templates it should be disabled for. If a template is + loaded from a string then the default from `default_for_string` is used. + If nothing matches then the initial value of autoescaping is set to the + value of `default`. + + For security reasons this function operates case insensitive. + + .. versionadded:: 2.9 + """ + enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions) + disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions) + + def autoescape(template_name: t.Optional[str]) -> bool: + if template_name is None: + return default_for_string + template_name = template_name.lower() + if template_name.endswith(enabled_patterns): + return True + if template_name.endswith(disabled_patterns): + return False + return default + + return autoescape + + +def htmlsafe_json_dumps( + obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any +) -> markupsafe.Markup: + """Serialize an object to a string of JSON with :func:`json.dumps`, + then replace HTML-unsafe characters with Unicode escapes and mark + the result safe with :class:`~markupsafe.Markup`. + + This is available in templates as the ``|tojson`` filter. + + The following characters are escaped: ``<``, ``>``, ``&``, ``'``. + + The returned string is safe to render in HTML documents and + ``<script>`` tags. The exception is in HTML attributes that are + double quoted; either use single quotes or the ``|forceescape`` + filter. + + :param obj: The object to serialize to JSON. + :param dumps: The ``dumps`` function to use. Defaults to + ``env.policies["json.dumps_function"]``, which defaults to + :func:`json.dumps`. + :param kwargs: Extra arguments to pass to ``dumps``. Merged onto + ``env.policies["json.dumps_kwargs"]``. + + .. versionchanged:: 3.0 + The ``dumper`` parameter is renamed to ``dumps``. + + .. versionadded:: 2.9 + """ + if dumps is None: + dumps = json.dumps + + return markupsafe.Markup( + dumps(obj, **kwargs) + .replace("<", "\\u003c") + .replace(">", "\\u003e") + .replace("&", "\\u0026") + .replace("'", "\\u0027") + ) + + +class Cycler: + """Cycle through values by yield them one at a time, then restarting + once the end is reached. Available as ``cycler`` in templates. + + Similar to ``loop.cycle``, but can be used outside loops or across + multiple loops. For example, render a list of folders and files in a + list, alternating giving them "odd" and "even" classes. + + .. code-block:: html+jinja + + {% set row_class = cycler("odd", "even") %} + <ul class="browser"> + {% for folder in folders %} + <li class="folder {{ row_class.next() }}">{{ folder }} + {% endfor %} + {% for file in files %} + <li class="file {{ row_class.next() }}">{{ file }} + {% endfor %} + </ul> + + :param items: Each positional argument will be yielded in the order + given for each cycle. + + .. versionadded:: 2.1 + """ + + def __init__(self, *items: t.Any) -> None: + if not items: + raise RuntimeError("at least one item has to be provided") + self.items = items + self.pos = 0 + + def reset(self) -> None: + """Resets the current item to the first item.""" + self.pos = 0 + + @property + def current(self) -> t.Any: + """Return the current item. Equivalent to the item that will be + returned next time :meth:`next` is called. + """ + return self.items[self.pos] + + def next(self) -> t.Any: + """Return the current item, then advance :attr:`current` to the + next item. + """ + rv = self.current + self.pos = (self.pos + 1) % len(self.items) + return rv + + __next__ = next + + +class Joiner: + """A joining helper for templates.""" + + def __init__(self, sep: str = ", ") -> None: + self.sep = sep + self.used = False + + def __call__(self) -> str: + if not self.used: + self.used = True + return "" + return self.sep + + +class Namespace: + """A namespace object that can hold arbitrary attributes. It may be + initialized from a dictionary or with keyword arguments.""" + + def __init__(*args: t.Any, **kwargs: t.Any) -> None: # noqa: B902 + self, args = args[0], args[1:] + self.__attrs = dict(*args, **kwargs) + + def __getattribute__(self, name: str) -> t.Any: + # __class__ is needed for the awaitable check in async mode + if name in {"_Namespace__attrs", "__class__"}: + return object.__getattribute__(self, name) + try: + return self.__attrs[name] + except KeyError: + raise AttributeError(name) from None + + def __setitem__(self, name: str, value: t.Any) -> None: + self.__attrs[name] = value + + def __repr__(self) -> str: + return f"<Namespace {self.__attrs!r}>" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jinja2/visitor.py b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/visitor.py new file mode 100644 index 0000000000000000000000000000000000000000..17c6aaba570742652f70bf1e7bf1a576c9d256ae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jinja2/visitor.py @@ -0,0 +1,92 @@ +"""API for traversing the AST nodes. Implemented by the compiler and +meta introspection. +""" +import typing as t + +from .nodes import Node + +if t.TYPE_CHECKING: + import typing_extensions as te + + class VisitCallable(te.Protocol): + def __call__(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any: + ... + + +class NodeVisitor: + """Walks the abstract syntax tree and call visitor functions for every + node found. The visitor functions may return values which will be + forwarded by the `visit` method. + + Per default the visitor functions for the nodes are ``'visit_'`` + + class name of the node. So a `TryFinally` node visit function would + be `visit_TryFinally`. This behavior can be changed by overriding + the `get_visitor` function. If no visitor function exists for a node + (return value `None`) the `generic_visit` visitor is used instead. + """ + + def get_visitor(self, node: Node) -> "t.Optional[VisitCallable]": + """Return the visitor function for this node or `None` if no visitor + exists for this node. In that case the generic visit function is + used instead. + """ + return getattr(self, f"visit_{type(node).__name__}", None) + + def visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Visit a node.""" + f = self.get_visitor(node) + + if f is not None: + return f(node, *args, **kwargs) + + return self.generic_visit(node, *args, **kwargs) + + def generic_visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Called if no explicit visitor function exists for a node.""" + for child_node in node.iter_child_nodes(): + self.visit(child_node, *args, **kwargs) + + +class NodeTransformer(NodeVisitor): + """Walks the abstract syntax tree and allows modifications of nodes. + + The `NodeTransformer` will walk the AST and use the return value of the + visitor functions to replace or remove the old node. If the return + value of the visitor function is `None` the node will be removed + from the previous location otherwise it's replaced with the return + value. The return value may be the original node in which case no + replacement takes place. + """ + + def generic_visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> Node: + for field, old_value in node.iter_fields(): + if isinstance(old_value, list): + new_values = [] + for value in old_value: + if isinstance(value, Node): + value = self.visit(value, *args, **kwargs) + if value is None: + continue + elif not isinstance(value, Node): + new_values.extend(value) + continue + new_values.append(value) + old_value[:] = new_values + elif isinstance(old_value, Node): + new_node = self.visit(old_value, *args, **kwargs) + if new_node is None: + delattr(node, field) + else: + setattr(node, field, new_node) + return node + + def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.List[Node]: + """As transformers may return lists in some places this method + can be used to enforce a list as return value. + """ + rv = self.visit(node, *args, **kwargs) + + if not isinstance(rv, list): + return [rv] + + return rv diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..26c79b243f3689d334a3b39544055d2c12484608 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__init__.py @@ -0,0 +1,72 @@ +from .api_jwk import PyJWK, PyJWKSet +from .api_jws import ( + PyJWS, + get_algorithm_by_name, + get_unverified_header, + register_algorithm, + unregister_algorithm, +) +from .api_jwt import PyJWT, decode, encode +from .exceptions import ( + DecodeError, + ExpiredSignatureError, + ImmatureSignatureError, + InvalidAlgorithmError, + InvalidAudienceError, + InvalidIssuedAtError, + InvalidIssuerError, + InvalidKeyError, + InvalidSignatureError, + InvalidTokenError, + MissingRequiredClaimError, + PyJWKClientError, + PyJWKError, + PyJWKSetError, + PyJWTError, +) +from .jwks_client import PyJWKClient + +__version__ = "2.6.0" + +__title__ = "PyJWT" +__description__ = "JSON Web Token implementation in Python" +__url__ = "https://pyjwt.readthedocs.io" +__uri__ = __url__ +__doc__ = f"{__description__} <{__uri__}>" + +__author__ = "José Padilla" +__email__ = "hello@jpadilla.com" + +__license__ = "MIT" +__copyright__ = "Copyright 2015-2022 José Padilla" + + +__all__ = [ + "PyJWS", + "PyJWT", + "PyJWKClient", + "PyJWK", + "PyJWKSet", + "decode", + "encode", + "get_unverified_header", + "register_algorithm", + "unregister_algorithm", + "get_algorithm_by_name", + # Exceptions + "DecodeError", + "ExpiredSignatureError", + "ImmatureSignatureError", + "InvalidAlgorithmError", + "InvalidAudienceError", + "InvalidIssuedAtError", + "InvalidIssuerError", + "InvalidKeyError", + "InvalidSignatureError", + "InvalidTokenError", + "MissingRequiredClaimError", + "PyJWKClientError", + "PyJWKError", + "PyJWKSetError", + "PyJWTError", +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb818f57f6311e4fe9d41865881de7d73aa006f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/algorithms.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/algorithms.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..413587d29a0103669033b659de37d29f162f6389 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/algorithms.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwk.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwk.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c29709bd1b9f37693fc717e8064f2810101739a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwk.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jws.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jws.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5d66b08676f7384b0c20535f2c02b6e657aee41 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jws.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwt.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwt.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0baf1aee1c2c9b72fba539cbafe215687dc5e699 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/api_jwt.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98ac9183f1c25e17ef691ad118a6849e6e436889 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/help.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/help.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1f39946f5b57c7b8f21e6cf71f3302a7bec91b8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/help.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwk_set_cache.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwk_set_cache.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8adbb3cecb274dc1813554ba0afe78ff1632790 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwk_set_cache.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwks_client.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwks_client.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ba20f43050b55a15b4136b1e1161ae6c00a5295 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/jwks_client.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1bcef392ff418b147e92543b45fd63192e85885c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/warnings.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/warnings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9259fc68be0edb296afcfe77202867a688df2cd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/jwt/__pycache__/warnings.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/algorithms.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/algorithms.py new file mode 100644 index 0000000000000000000000000000000000000000..93fadf4c7042f0e1d07fe5d58d6304ba3b0062c9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/algorithms.py @@ -0,0 +1,712 @@ +import hashlib +import hmac +import json + +from .exceptions import InvalidKeyError +from .utils import ( + base64url_decode, + base64url_encode, + der_to_raw_signature, + force_bytes, + from_base64url_uint, + is_pem_format, + is_ssh_key, + raw_to_der_signature, + to_base64url_uint, +) + +try: + import cryptography.exceptions + from cryptography.exceptions import InvalidSignature + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import ec, padding + from cryptography.hazmat.primitives.asymmetric.ec import ( + EllipticCurvePrivateKey, + EllipticCurvePublicKey, + ) + from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, + ) + from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, + ) + from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKey, + RSAPrivateNumbers, + RSAPublicKey, + RSAPublicNumbers, + rsa_crt_dmp1, + rsa_crt_dmq1, + rsa_crt_iqmp, + rsa_recover_prime_factors, + ) + from cryptography.hazmat.primitives.serialization import ( + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, + load_pem_private_key, + load_pem_public_key, + load_ssh_public_key, + ) + + has_crypto = True +except ModuleNotFoundError: + has_crypto = False + +requires_cryptography = { + "RS256", + "RS384", + "RS512", + "ES256", + "ES256K", + "ES384", + "ES521", + "ES512", + "PS256", + "PS384", + "PS512", + "EdDSA", +} + + +def get_default_algorithms(): + """ + Returns the algorithms that are implemented by the library. + """ + default_algorithms = { + "none": NoneAlgorithm(), + "HS256": HMACAlgorithm(HMACAlgorithm.SHA256), + "HS384": HMACAlgorithm(HMACAlgorithm.SHA384), + "HS512": HMACAlgorithm(HMACAlgorithm.SHA512), + } + + if has_crypto: + default_algorithms.update( + { + "RS256": RSAAlgorithm(RSAAlgorithm.SHA256), + "RS384": RSAAlgorithm(RSAAlgorithm.SHA384), + "RS512": RSAAlgorithm(RSAAlgorithm.SHA512), + "ES256": ECAlgorithm(ECAlgorithm.SHA256), + "ES256K": ECAlgorithm(ECAlgorithm.SHA256), + "ES384": ECAlgorithm(ECAlgorithm.SHA384), + "ES521": ECAlgorithm(ECAlgorithm.SHA512), + "ES512": ECAlgorithm( + ECAlgorithm.SHA512 + ), # Backward compat for #219 fix + "PS256": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256), + "PS384": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA384), + "PS512": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA512), + "EdDSA": OKPAlgorithm(), + } + ) + + return default_algorithms + + +class Algorithm: + """ + The interface for an algorithm used to sign and verify tokens. + """ + + def prepare_key(self, key): + """ + Performs necessary validation and conversions on the key and returns + the key value in the proper format for sign() and verify(). + """ + raise NotImplementedError + + def sign(self, msg, key): + """ + Returns a digital signature for the specified message + using the specified key value. + """ + raise NotImplementedError + + def verify(self, msg, key, sig): + """ + Verifies that the specified digital signature is valid + for the specified message and key values. + """ + raise NotImplementedError + + @staticmethod + def to_jwk(key_obj): + """ + Serializes a given RSA key into a JWK + """ + raise NotImplementedError + + @staticmethod + def from_jwk(jwk): + """ + Deserializes a given RSA key from JWK back into a PublicKey or PrivateKey object + """ + raise NotImplementedError + + +class NoneAlgorithm(Algorithm): + """ + Placeholder for use when no signing or verification + operations are required. + """ + + def prepare_key(self, key): + if key == "": + key = None + + if key is not None: + raise InvalidKeyError('When alg = "none", key value must be None.') + + return key + + def sign(self, msg, key): + return b"" + + def verify(self, msg, key, sig): + return False + + +class HMACAlgorithm(Algorithm): + """ + Performs signing and verification operations using HMAC + and the specified hash function. + """ + + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + + def __init__(self, hash_alg): + self.hash_alg = hash_alg + + def prepare_key(self, key): + key = force_bytes(key) + + if is_pem_format(key) or is_ssh_key(key): + raise InvalidKeyError( + "The specified key is an asymmetric key or x509 certificate and" + " should not be used as an HMAC secret." + ) + + return key + + @staticmethod + def to_jwk(key_obj): + return json.dumps( + { + "k": base64url_encode(force_bytes(key_obj)).decode(), + "kty": "oct", + } + ) + + @staticmethod + def from_jwk(jwk): + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") + + if obj.get("kty") != "oct": + raise InvalidKeyError("Not an HMAC key") + + return base64url_decode(obj["k"]) + + def sign(self, msg, key): + return hmac.new(key, msg, self.hash_alg).digest() + + def verify(self, msg, key, sig): + return hmac.compare_digest(sig, self.sign(msg, key)) + + +if has_crypto: + + class RSAAlgorithm(Algorithm): + """ + Performs signing and verification operations using + RSASSA-PKCS-v1_5 and the specified hash function. + """ + + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, hash_alg): + self.hash_alg = hash_alg + + def prepare_key(self, key): + if isinstance(key, (RSAPrivateKey, RSAPublicKey)): + return key + + if not isinstance(key, (bytes, str)): + raise TypeError("Expecting a PEM-formatted key.") + + key = force_bytes(key) + + try: + if key.startswith(b"ssh-rsa"): + key = load_ssh_public_key(key) + else: + key = load_pem_private_key(key, password=None) + except ValueError: + key = load_pem_public_key(key) + return key + + @staticmethod + def to_jwk(key_obj): + obj = None + + if getattr(key_obj, "private_numbers", None): + # Private key + numbers = key_obj.private_numbers() + + obj = { + "kty": "RSA", + "key_ops": ["sign"], + "n": to_base64url_uint(numbers.public_numbers.n).decode(), + "e": to_base64url_uint(numbers.public_numbers.e).decode(), + "d": to_base64url_uint(numbers.d).decode(), + "p": to_base64url_uint(numbers.p).decode(), + "q": to_base64url_uint(numbers.q).decode(), + "dp": to_base64url_uint(numbers.dmp1).decode(), + "dq": to_base64url_uint(numbers.dmq1).decode(), + "qi": to_base64url_uint(numbers.iqmp).decode(), + } + + elif getattr(key_obj, "verify", None): + # Public key + numbers = key_obj.public_numbers() + + obj = { + "kty": "RSA", + "key_ops": ["verify"], + "n": to_base64url_uint(numbers.n).decode(), + "e": to_base64url_uint(numbers.e).decode(), + } + else: + raise InvalidKeyError("Not a public or private key") + + return json.dumps(obj) + + @staticmethod + def from_jwk(jwk): + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") + + if obj.get("kty") != "RSA": + raise InvalidKeyError("Not an RSA key") + + if "d" in obj and "e" in obj and "n" in obj: + # Private key + if "oth" in obj: + raise InvalidKeyError( + "Unsupported RSA private key: > 2 primes not supported" + ) + + other_props = ["p", "q", "dp", "dq", "qi"] + props_found = [prop in obj for prop in other_props] + any_props_found = any(props_found) + + if any_props_found and not all(props_found): + raise InvalidKeyError( + "RSA key must include all parameters if any are present besides d" + ) + + public_numbers = RSAPublicNumbers( + from_base64url_uint(obj["e"]), + from_base64url_uint(obj["n"]), + ) + + if any_props_found: + numbers = RSAPrivateNumbers( + d=from_base64url_uint(obj["d"]), + p=from_base64url_uint(obj["p"]), + q=from_base64url_uint(obj["q"]), + dmp1=from_base64url_uint(obj["dp"]), + dmq1=from_base64url_uint(obj["dq"]), + iqmp=from_base64url_uint(obj["qi"]), + public_numbers=public_numbers, + ) + else: + d = from_base64url_uint(obj["d"]) + p, q = rsa_recover_prime_factors( + public_numbers.n, d, public_numbers.e + ) + + numbers = RSAPrivateNumbers( + d=d, + p=p, + q=q, + dmp1=rsa_crt_dmp1(d, p), + dmq1=rsa_crt_dmq1(d, q), + iqmp=rsa_crt_iqmp(p, q), + public_numbers=public_numbers, + ) + + return numbers.private_key() + elif "n" in obj and "e" in obj: + # Public key + numbers = RSAPublicNumbers( + from_base64url_uint(obj["e"]), + from_base64url_uint(obj["n"]), + ) + + return numbers.public_key() + else: + raise InvalidKeyError("Not a public or private key") + + def sign(self, msg, key): + return key.sign(msg, padding.PKCS1v15(), self.hash_alg()) + + def verify(self, msg, key, sig): + try: + key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg()) + return True + except InvalidSignature: + return False + + class ECAlgorithm(Algorithm): + """ + Performs signing and verification operations using + ECDSA and the specified hash function + """ + + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, hash_alg): + self.hash_alg = hash_alg + + def prepare_key(self, key): + if isinstance(key, (EllipticCurvePrivateKey, EllipticCurvePublicKey)): + return key + + if not isinstance(key, (bytes, str)): + raise TypeError("Expecting a PEM-formatted key.") + + key = force_bytes(key) + + # Attempt to load key. We don't know if it's + # a Signing Key or a Verifying Key, so we try + # the Verifying Key first. + try: + if key.startswith(b"ecdsa-sha2-"): + key = load_ssh_public_key(key) + else: + key = load_pem_public_key(key) + except ValueError: + key = load_pem_private_key(key, password=None) + + # Explicit check the key to prevent confusing errors from cryptography + if not isinstance(key, (EllipticCurvePrivateKey, EllipticCurvePublicKey)): + raise InvalidKeyError( + "Expecting a EllipticCurvePrivateKey/EllipticCurvePublicKey. Wrong key provided for ECDSA algorithms" + ) + + return key + + def sign(self, msg, key): + der_sig = key.sign(msg, ec.ECDSA(self.hash_alg())) + + return der_to_raw_signature(der_sig, key.curve) + + def verify(self, msg, key, sig): + try: + der_sig = raw_to_der_signature(sig, key.curve) + except ValueError: + return False + + try: + if isinstance(key, EllipticCurvePrivateKey): + key = key.public_key() + key.verify(der_sig, msg, ec.ECDSA(self.hash_alg())) + return True + except InvalidSignature: + return False + + @staticmethod + def to_jwk(key_obj): + + if isinstance(key_obj, EllipticCurvePrivateKey): + public_numbers = key_obj.public_key().public_numbers() + elif isinstance(key_obj, EllipticCurvePublicKey): + public_numbers = key_obj.public_numbers() + else: + raise InvalidKeyError("Not a public or private key") + + if isinstance(key_obj.curve, ec.SECP256R1): + crv = "P-256" + elif isinstance(key_obj.curve, ec.SECP384R1): + crv = "P-384" + elif isinstance(key_obj.curve, ec.SECP521R1): + crv = "P-521" + elif isinstance(key_obj.curve, ec.SECP256K1): + crv = "secp256k1" + else: + raise InvalidKeyError(f"Invalid curve: {key_obj.curve}") + + obj = { + "kty": "EC", + "crv": crv, + "x": to_base64url_uint(public_numbers.x).decode(), + "y": to_base64url_uint(public_numbers.y).decode(), + } + + if isinstance(key_obj, EllipticCurvePrivateKey): + obj["d"] = to_base64url_uint( + key_obj.private_numbers().private_value + ).decode() + + return json.dumps(obj) + + @staticmethod + def from_jwk(jwk): + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") + + if obj.get("kty") != "EC": + raise InvalidKeyError("Not an Elliptic curve key") + + if "x" not in obj or "y" not in obj: + raise InvalidKeyError("Not an Elliptic curve key") + + x = base64url_decode(obj.get("x")) + y = base64url_decode(obj.get("y")) + + curve = obj.get("crv") + if curve == "P-256": + if len(x) == len(y) == 32: + curve_obj = ec.SECP256R1() + else: + raise InvalidKeyError("Coords should be 32 bytes for curve P-256") + elif curve == "P-384": + if len(x) == len(y) == 48: + curve_obj = ec.SECP384R1() + else: + raise InvalidKeyError("Coords should be 48 bytes for curve P-384") + elif curve == "P-521": + if len(x) == len(y) == 66: + curve_obj = ec.SECP521R1() + else: + raise InvalidKeyError("Coords should be 66 bytes for curve P-521") + elif curve == "secp256k1": + if len(x) == len(y) == 32: + curve_obj = ec.SECP256K1() + else: + raise InvalidKeyError( + "Coords should be 32 bytes for curve secp256k1" + ) + else: + raise InvalidKeyError(f"Invalid curve: {curve}") + + public_numbers = ec.EllipticCurvePublicNumbers( + x=int.from_bytes(x, byteorder="big"), + y=int.from_bytes(y, byteorder="big"), + curve=curve_obj, + ) + + if "d" not in obj: + return public_numbers.public_key() + + d = base64url_decode(obj.get("d")) + if len(d) != len(x): + raise InvalidKeyError( + "D should be {} bytes for curve {}", len(x), curve + ) + + return ec.EllipticCurvePrivateNumbers( + int.from_bytes(d, byteorder="big"), public_numbers + ).private_key() + + class RSAPSSAlgorithm(RSAAlgorithm): + """ + Performs a signature using RSASSA-PSS with MGF1 + """ + + def sign(self, msg, key): + return key.sign( + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg.digest_size, + ), + self.hash_alg(), + ) + + def verify(self, msg, key, sig): + try: + key.verify( + sig, + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg.digest_size, + ), + self.hash_alg(), + ) + return True + except InvalidSignature: + return False + + class OKPAlgorithm(Algorithm): + """ + Performs signing and verification operations using EdDSA + + This class requires ``cryptography>=2.6`` to be installed. + """ + + def __init__(self, **kwargs): + pass + + def prepare_key(self, key): + if isinstance(key, (bytes, str)): + if isinstance(key, str): + key = key.encode("utf-8") + str_key = key.decode("utf-8") + + if "-----BEGIN PUBLIC" in str_key: + key = load_pem_public_key(key) + elif "-----BEGIN PRIVATE" in str_key: + key = load_pem_private_key(key, password=None) + elif str_key[0:4] == "ssh-": + key = load_ssh_public_key(key) + + # Explicit check the key to prevent confusing errors from cryptography + if not isinstance( + key, + (Ed25519PrivateKey, Ed25519PublicKey, Ed448PrivateKey, Ed448PublicKey), + ): + raise InvalidKeyError( + "Expecting a EllipticCurvePrivateKey/EllipticCurvePublicKey. Wrong key provided for EdDSA algorithms" + ) + + return key + + def sign(self, msg, key): + """ + Sign a message ``msg`` using the EdDSA private key ``key`` + :param str|bytes msg: Message to sign + :param Ed25519PrivateKey}Ed448PrivateKey key: A :class:`.Ed25519PrivateKey` + or :class:`.Ed448PrivateKey` isinstance + :return bytes signature: The signature, as bytes + """ + msg = bytes(msg, "utf-8") if type(msg) is not bytes else msg + return key.sign(msg) + + def verify(self, msg, key, sig): + """ + Verify a given ``msg`` against a signature ``sig`` using the EdDSA key ``key`` + + :param str|bytes sig: EdDSA signature to check ``msg`` against + :param str|bytes msg: Message to sign + :param Ed25519PrivateKey|Ed25519PublicKey|Ed448PrivateKey|Ed448PublicKey key: + A private or public EdDSA key instance + :return bool verified: True if signature is valid, False if not. + """ + try: + msg = bytes(msg, "utf-8") if type(msg) is not bytes else msg + sig = bytes(sig, "utf-8") if type(sig) is not bytes else sig + + if isinstance(key, (Ed25519PrivateKey, Ed448PrivateKey)): + key = key.public_key() + key.verify(sig, msg) + return True # If no exception was raised, the signature is valid. + except cryptography.exceptions.InvalidSignature: + return False + + @staticmethod + def to_jwk(key): + if isinstance(key, (Ed25519PublicKey, Ed448PublicKey)): + x = key.public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + crv = "Ed25519" if isinstance(key, Ed25519PublicKey) else "Ed448" + return json.dumps( + { + "x": base64url_encode(force_bytes(x)).decode(), + "kty": "OKP", + "crv": crv, + } + ) + + if isinstance(key, (Ed25519PrivateKey, Ed448PrivateKey)): + d = key.private_bytes( + encoding=Encoding.Raw, + format=PrivateFormat.Raw, + encryption_algorithm=NoEncryption(), + ) + + x = key.public_key().public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + + crv = "Ed25519" if isinstance(key, Ed25519PrivateKey) else "Ed448" + return json.dumps( + { + "x": base64url_encode(force_bytes(x)).decode(), + "d": base64url_encode(force_bytes(d)).decode(), + "kty": "OKP", + "crv": crv, + } + ) + + raise InvalidKeyError("Not a public or private key") + + @staticmethod + def from_jwk(jwk): + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") + + if obj.get("kty") != "OKP": + raise InvalidKeyError("Not an Octet Key Pair") + + curve = obj.get("crv") + if curve != "Ed25519" and curve != "Ed448": + raise InvalidKeyError(f"Invalid curve: {curve}") + + if "x" not in obj: + raise InvalidKeyError('OKP should have "x" parameter') + x = base64url_decode(obj.get("x")) + + try: + if "d" not in obj: + if curve == "Ed25519": + return Ed25519PublicKey.from_public_bytes(x) + return Ed448PublicKey.from_public_bytes(x) + d = base64url_decode(obj.get("d")) + if curve == "Ed25519": + return Ed25519PrivateKey.from_private_bytes(d) + return Ed448PrivateKey.from_private_bytes(d) + except ValueError as err: + raise InvalidKeyError("Invalid key parameter") from err diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwk.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwk.py new file mode 100644 index 0000000000000000000000000000000000000000..aa3dd3219f40a8eac65802bca0b79d489683360b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwk.py @@ -0,0 +1,125 @@ +from __future__ import annotations + +import json +import time + +from .algorithms import get_default_algorithms +from .exceptions import InvalidKeyError, PyJWKError, PyJWKSetError + + +class PyJWK: + def __init__(self, jwk_data, algorithm=None): + self._algorithms = get_default_algorithms() + self._jwk_data = jwk_data + + kty = self._jwk_data.get("kty", None) + if not kty: + raise InvalidKeyError(f"kty is not found: {self._jwk_data}") + + if not algorithm and isinstance(self._jwk_data, dict): + algorithm = self._jwk_data.get("alg", None) + + if not algorithm: + # Determine alg with kty (and crv). + crv = self._jwk_data.get("crv", None) + if kty == "EC": + if crv == "P-256" or not crv: + algorithm = "ES256" + elif crv == "P-384": + algorithm = "ES384" + elif crv == "P-521": + algorithm = "ES512" + elif crv == "secp256k1": + algorithm = "ES256K" + else: + raise InvalidKeyError(f"Unsupported crv: {crv}") + elif kty == "RSA": + algorithm = "RS256" + elif kty == "oct": + algorithm = "HS256" + elif kty == "OKP": + if not crv: + raise InvalidKeyError(f"crv is not found: {self._jwk_data}") + if crv == "Ed25519": + algorithm = "EdDSA" + else: + raise InvalidKeyError(f"Unsupported crv: {crv}") + else: + raise InvalidKeyError(f"Unsupported kty: {kty}") + + self.Algorithm = self._algorithms.get(algorithm) + + if not self.Algorithm: + raise PyJWKError(f"Unable to find a algorithm for key: {self._jwk_data}") + + self.key = self.Algorithm.from_jwk(self._jwk_data) + + @staticmethod + def from_dict(obj, algorithm=None): + return PyJWK(obj, algorithm) + + @staticmethod + def from_json(data, algorithm=None): + obj = json.loads(data) + return PyJWK.from_dict(obj, algorithm) + + @property + def key_type(self): + return self._jwk_data.get("kty", None) + + @property + def key_id(self): + return self._jwk_data.get("kid", None) + + @property + def public_key_use(self): + return self._jwk_data.get("use", None) + + +class PyJWKSet: + def __init__(self, keys: list[dict]) -> None: + self.keys = [] + + if not keys: + raise PyJWKSetError("The JWK Set did not contain any keys") + + if not isinstance(keys, list): + raise PyJWKSetError("Invalid JWK Set value") + + for key in keys: + try: + self.keys.append(PyJWK(key)) + except PyJWKError: + # skip unusable keys + continue + + if len(self.keys) == 0: + raise PyJWKSetError("The JWK Set did not contain any usable keys") + + @staticmethod + def from_dict(obj): + keys = obj.get("keys", []) + return PyJWKSet(keys) + + @staticmethod + def from_json(data): + obj = json.loads(data) + return PyJWKSet.from_dict(obj) + + def __getitem__(self, kid): + for key in self.keys: + if key.key_id == kid: + return key + raise KeyError(f"keyset has no key for kid: {kid}") + + +class PyJWTSetWithTimestamp: + def __init__(self, jwk_set: PyJWKSet): + self.jwk_set = jwk_set + self.timestamp = time.monotonic() + + def get_jwk_set(self): + return self.jwk_set + + def get_timestamp(self): + return self.timestamp diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jws.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jws.py new file mode 100644 index 0000000000000000000000000000000000000000..ab8490f9f308e93ab4fa268e6123d6964b426e92 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jws.py @@ -0,0 +1,319 @@ +from __future__ import annotations + +import binascii +import json +import warnings +from typing import Any, Type + +from .algorithms import ( + Algorithm, + get_default_algorithms, + has_crypto, + requires_cryptography, +) +from .exceptions import ( + DecodeError, + InvalidAlgorithmError, + InvalidSignatureError, + InvalidTokenError, +) +from .utils import base64url_decode, base64url_encode +from .warnings import RemovedInPyjwt3Warning + + +class PyJWS: + header_typ = "JWT" + + def __init__(self, algorithms=None, options=None) -> None: + self._algorithms = get_default_algorithms() + self._valid_algs = ( + set(algorithms) if algorithms is not None else set(self._algorithms) + ) + + # Remove algorithms that aren't on the whitelist + for key in list(self._algorithms.keys()): + if key not in self._valid_algs: + del self._algorithms[key] + + if options is None: + options = {} + self.options = {**self._get_default_options(), **options} + + @staticmethod + def _get_default_options() -> dict[str, bool]: + return {"verify_signature": True} + + def register_algorithm(self, alg_id: str, alg_obj: Algorithm) -> None: + """ + Registers a new Algorithm for use when creating and verifying tokens. + """ + if alg_id in self._algorithms: + raise ValueError("Algorithm already has a handler.") + + if not isinstance(alg_obj, Algorithm): + raise TypeError("Object is not of type `Algorithm`") + + self._algorithms[alg_id] = alg_obj + self._valid_algs.add(alg_id) + + def unregister_algorithm(self, alg_id: str) -> None: + """ + Unregisters an Algorithm for use when creating and verifying tokens + Throws KeyError if algorithm is not registered. + """ + if alg_id not in self._algorithms: + raise KeyError( + "The specified algorithm could not be removed" + " because it is not registered." + ) + + del self._algorithms[alg_id] + self._valid_algs.remove(alg_id) + + def get_algorithms(self) -> list[str]: + """ + Returns a list of supported values for the 'alg' parameter. + """ + return list(self._valid_algs) + + def get_algorithm_by_name(self, alg_name: str) -> Algorithm: + """ + For a given string name, return the matching Algorithm object. + + Example usage: + + >>> jws_obj.get_algorithm_by_name("RS256") + """ + try: + return self._algorithms[alg_name] + except KeyError as e: + if not has_crypto and alg_name in requires_cryptography: + raise NotImplementedError( + f"Algorithm '{alg_name}' could not be found. Do you have cryptography installed?" + ) from e + raise NotImplementedError("Algorithm not supported") from e + + def encode( + self, + payload: bytes, + key: str, + algorithm: str | None = "HS256", + headers: dict[str, Any] | None = None, + json_encoder: Type[json.JSONEncoder] | None = None, + is_payload_detached: bool = False, + ) -> str: + segments = [] + + # declare a new var to narrow the type for type checkers + algorithm_: str = algorithm if algorithm is not None else "none" + + # Prefer headers values if present to function parameters. + if headers: + headers_alg = headers.get("alg") + if headers_alg: + algorithm_ = headers["alg"] + + headers_b64 = headers.get("b64") + if headers_b64 is False: + is_payload_detached = True + + # Header + header: dict[str, Any] = {"typ": self.header_typ, "alg": algorithm_} + + if headers: + self._validate_headers(headers) + header.update(headers) + + if not header["typ"]: + del header["typ"] + + if is_payload_detached: + header["b64"] = False + elif "b64" in header: + # True is the standard value for b64, so no need for it + del header["b64"] + + # Fix for headers misorder - issue #715 + json_header = json.dumps( + header, separators=(",", ":"), cls=json_encoder, sort_keys=True + ).encode() + + segments.append(base64url_encode(json_header)) + + if is_payload_detached: + msg_payload = payload + else: + msg_payload = base64url_encode(payload) + segments.append(msg_payload) + + # Segments + signing_input = b".".join(segments) + + alg_obj = self.get_algorithm_by_name(algorithm_) + key = alg_obj.prepare_key(key) + signature = alg_obj.sign(signing_input, key) + + segments.append(base64url_encode(signature)) + + # Don't put the payload content inside the encoded token when detached + if is_payload_detached: + segments[1] = b"" + encoded_string = b".".join(segments) + + return encoded_string.decode("utf-8") + + def decode_complete( + self, + jwt: str, + key: str = "", + algorithms: list[str] | None = None, + options: dict[str, Any] | None = None, + detached_payload: bytes | None = None, + **kwargs, + ) -> dict[str, Any]: + if kwargs: + warnings.warn( + "passing additional kwargs to decode_complete() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + ) + if options is None: + options = {} + merged_options = {**self.options, **options} + verify_signature = merged_options["verify_signature"] + + if verify_signature and not algorithms: + raise DecodeError( + 'It is required that you pass in a value for the "algorithms" argument when calling decode().' + ) + + payload, signing_input, header, signature = self._load(jwt) + + if header.get("b64", True) is False: + if detached_payload is None: + raise DecodeError( + 'It is required that you pass in a value for the "detached_payload" argument to decode a message having the b64 header set to false.' + ) + payload = detached_payload + signing_input = b".".join([signing_input.rsplit(b".", 1)[0], payload]) + + if verify_signature: + self._verify_signature(signing_input, header, signature, key, algorithms) + + return { + "payload": payload, + "header": header, + "signature": signature, + } + + def decode( + self, + jwt: str, + key: str = "", + algorithms: list[str] | None = None, + options: dict[str, Any] | None = None, + detached_payload: bytes | None = None, + **kwargs, + ) -> str: + if kwargs: + warnings.warn( + "passing additional kwargs to decode() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + ) + decoded = self.decode_complete( + jwt, key, algorithms, options, detached_payload=detached_payload + ) + return decoded["payload"] + + def get_unverified_header(self, jwt: str | bytes) -> dict: + """Returns back the JWT header parameters as a dict() + + Note: The signature is not verified so the header parameters + should not be fully trusted until signature verification is complete + """ + headers = self._load(jwt)[2] + self._validate_headers(headers) + + return headers + + def _load(self, jwt: str | bytes) -> tuple[bytes, bytes, dict, bytes]: + if isinstance(jwt, str): + jwt = jwt.encode("utf-8") + + if not isinstance(jwt, bytes): + raise DecodeError(f"Invalid token type. Token must be a {bytes}") + + try: + signing_input, crypto_segment = jwt.rsplit(b".", 1) + header_segment, payload_segment = signing_input.split(b".", 1) + except ValueError as err: + raise DecodeError("Not enough segments") from err + + try: + header_data = base64url_decode(header_segment) + except (TypeError, binascii.Error) as err: + raise DecodeError("Invalid header padding") from err + + try: + header = json.loads(header_data) + except ValueError as e: + raise DecodeError(f"Invalid header string: {e}") from e + + if not isinstance(header, dict): + raise DecodeError("Invalid header string: must be a json object") + + try: + payload = base64url_decode(payload_segment) + except (TypeError, binascii.Error) as err: + raise DecodeError("Invalid payload padding") from err + + try: + signature = base64url_decode(crypto_segment) + except (TypeError, binascii.Error) as err: + raise DecodeError("Invalid crypto padding") from err + + return (payload, signing_input, header, signature) + + def _verify_signature( + self, + signing_input: bytes, + header: dict, + signature: bytes, + key: str = "", + algorithms: list[str] | None = None, + ) -> None: + + alg = header.get("alg") + + if not alg or (algorithms is not None and alg not in algorithms): + raise InvalidAlgorithmError("The specified alg value is not allowed") + + try: + alg_obj = self.get_algorithm_by_name(alg) + except NotImplementedError as e: + raise InvalidAlgorithmError("Algorithm not supported") from e + key = alg_obj.prepare_key(key) + + if not alg_obj.verify(signing_input, key, signature): + raise InvalidSignatureError("Signature verification failed") + + def _validate_headers(self, headers: dict[str, Any]) -> None: + if "kid" in headers: + self._validate_kid(headers["kid"]) + + def _validate_kid(self, kid: str) -> None: + if not isinstance(kid, str): + raise InvalidTokenError("Key ID header parameter must be a string") + + +_jws_global_obj = PyJWS() +encode = _jws_global_obj.encode +decode_complete = _jws_global_obj.decode_complete +decode = _jws_global_obj.decode +register_algorithm = _jws_global_obj.register_algorithm +unregister_algorithm = _jws_global_obj.unregister_algorithm +get_algorithm_by_name = _jws_global_obj.get_algorithm_by_name +get_unverified_header = _jws_global_obj.get_unverified_header diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwt.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwt.py new file mode 100644 index 0000000000000000000000000000000000000000..4bb1ee1fa4a8e1be09a51d25da52c5dab916259c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/api_jwt.py @@ -0,0 +1,281 @@ +from __future__ import annotations + +import json +import warnings +from calendar import timegm +from collections.abc import Iterable, Mapping +from datetime import datetime, timedelta, timezone +from typing import Any, Dict, List, Optional, Type, Union + +from . import api_jws +from .exceptions import ( + DecodeError, + ExpiredSignatureError, + ImmatureSignatureError, + InvalidAudienceError, + InvalidIssuedAtError, + InvalidIssuerError, + MissingRequiredClaimError, +) +from .warnings import RemovedInPyjwt3Warning + + +class PyJWT: + def __init__(self, options=None): + if options is None: + options = {} + self.options = {**self._get_default_options(), **options} + + @staticmethod + def _get_default_options() -> Dict[str, Union[bool, List[str]]]: + return { + "verify_signature": True, + "verify_exp": True, + "verify_nbf": True, + "verify_iat": True, + "verify_aud": True, + "verify_iss": True, + "require": [], + } + + def encode( + self, + payload: Dict[str, Any], + key: str, + algorithm: Optional[str] = "HS256", + headers: Optional[Dict[str, Any]] = None, + json_encoder: Optional[Type[json.JSONEncoder]] = None, + ) -> str: + # Check that we get a mapping + if not isinstance(payload, Mapping): + raise TypeError( + "Expecting a mapping object, as JWT only supports " + "JSON objects as payloads." + ) + + # Payload + payload = payload.copy() + for time_claim in ["exp", "iat", "nbf"]: + # Convert datetime to a intDate value in known time-format claims + if isinstance(payload.get(time_claim), datetime): + payload[time_claim] = timegm(payload[time_claim].utctimetuple()) + + json_payload = json.dumps( + payload, separators=(",", ":"), cls=json_encoder + ).encode("utf-8") + + return api_jws.encode(json_payload, key, algorithm, headers, json_encoder) + + def decode_complete( + self, + jwt: str, + key: str = "", + algorithms: Optional[List[str]] = None, + options: Optional[Dict[str, Any]] = None, + # deprecated arg, remove in pyjwt3 + verify: Optional[bool] = None, + # could be used as passthrough to api_jws, consider removal in pyjwt3 + detached_payload: Optional[bytes] = None, + # passthrough arguments to _validate_claims + # consider putting in options + audience: Optional[Union[str, Iterable[str]]] = None, + issuer: Optional[str] = None, + leeway: Union[int, float, timedelta] = 0, + # kwargs + **kwargs, + ) -> Dict[str, Any]: + if kwargs: + warnings.warn( + "passing additional kwargs to decode_complete() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + ) + options = dict(options or {}) # shallow-copy or initialize an empty dict + options.setdefault("verify_signature", True) + + # If the user has set the legacy `verify` argument, and it doesn't match + # what the relevant `options` entry for the argument is, inform the user + # that they're likely making a mistake. + if verify is not None and verify != options["verify_signature"]: + warnings.warn( + "The `verify` argument to `decode` does nothing in PyJWT 2.0 and newer. " + "The equivalent is setting `verify_signature` to False in the `options` dictionary. " + "This invocation has a mismatch between the kwarg and the option entry.", + category=DeprecationWarning, + ) + + if not options["verify_signature"]: + options.setdefault("verify_exp", False) + options.setdefault("verify_nbf", False) + options.setdefault("verify_iat", False) + options.setdefault("verify_aud", False) + options.setdefault("verify_iss", False) + + if options["verify_signature"] and not algorithms: + raise DecodeError( + 'It is required that you pass in a value for the "algorithms" argument when calling decode().' + ) + + decoded = api_jws.decode_complete( + jwt, + key=key, + algorithms=algorithms, + options=options, + detached_payload=detached_payload, + ) + + try: + payload = json.loads(decoded["payload"]) + except ValueError as e: + raise DecodeError(f"Invalid payload string: {e}") + if not isinstance(payload, dict): + raise DecodeError("Invalid payload string: must be a json object") + + merged_options = {**self.options, **options} + self._validate_claims( + payload, merged_options, audience=audience, issuer=issuer, leeway=leeway + ) + + decoded["payload"] = payload + return decoded + + def decode( + self, + jwt: str, + key: str = "", + algorithms: Optional[List[str]] = None, + options: Optional[Dict[str, Any]] = None, + # deprecated arg, remove in pyjwt3 + verify: Optional[bool] = None, + # could be used as passthrough to api_jws, consider removal in pyjwt3 + detached_payload: Optional[bytes] = None, + # passthrough arguments to _validate_claims + # consider putting in options + audience: Optional[Union[str, Iterable[str]]] = None, + issuer: Optional[str] = None, + leeway: Union[int, float, timedelta] = 0, + # kwargs + **kwargs, + ) -> Dict[str, Any]: + if kwargs: + warnings.warn( + "passing additional kwargs to decode() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + ) + decoded = self.decode_complete( + jwt, + key, + algorithms, + options, + verify=verify, + detached_payload=detached_payload, + audience=audience, + issuer=issuer, + leeway=leeway, + ) + return decoded["payload"] + + def _validate_claims(self, payload, options, audience=None, issuer=None, leeway=0): + if isinstance(leeway, timedelta): + leeway = leeway.total_seconds() + + if audience is not None and not isinstance(audience, (str, Iterable)): + raise TypeError("audience must be a string, iterable or None") + + self._validate_required_claims(payload, options) + + now = timegm(datetime.now(tz=timezone.utc).utctimetuple()) + + if "iat" in payload and options["verify_iat"]: + self._validate_iat(payload, now, leeway) + + if "nbf" in payload and options["verify_nbf"]: + self._validate_nbf(payload, now, leeway) + + if "exp" in payload and options["verify_exp"]: + self._validate_exp(payload, now, leeway) + + if options["verify_iss"]: + self._validate_iss(payload, issuer) + + if options["verify_aud"]: + self._validate_aud(payload, audience) + + def _validate_required_claims(self, payload, options): + for claim in options["require"]: + if payload.get(claim) is None: + raise MissingRequiredClaimError(claim) + + def _validate_iat(self, payload, now, leeway): + iat = payload["iat"] + try: + int(iat) + except ValueError: + raise InvalidIssuedAtError("Issued At claim (iat) must be an integer.") + if iat > (now + leeway): + raise ImmatureSignatureError("The token is not yet valid (iat)") + + def _validate_nbf(self, payload, now, leeway): + try: + nbf = int(payload["nbf"]) + except ValueError: + raise DecodeError("Not Before claim (nbf) must be an integer.") + + if nbf > (now + leeway): + raise ImmatureSignatureError("The token is not yet valid (nbf)") + + def _validate_exp(self, payload, now, leeway): + try: + exp = int(payload["exp"]) + except ValueError: + raise DecodeError("Expiration Time claim (exp) must be an" " integer.") + + if exp <= (now - leeway): + raise ExpiredSignatureError("Signature has expired") + + def _validate_aud(self, payload, audience): + if audience is None: + if "aud" not in payload or not payload["aud"]: + return + # Application did not specify an audience, but + # the token has the 'aud' claim + raise InvalidAudienceError("Invalid audience") + + if "aud" not in payload or not payload["aud"]: + # Application specified an audience, but it could not be + # verified since the token does not contain a claim. + raise MissingRequiredClaimError("aud") + + audience_claims = payload["aud"] + + if isinstance(audience_claims, str): + audience_claims = [audience_claims] + if not isinstance(audience_claims, list): + raise InvalidAudienceError("Invalid claim format in token") + if any(not isinstance(c, str) for c in audience_claims): + raise InvalidAudienceError("Invalid claim format in token") + + if isinstance(audience, str): + audience = [audience] + + if all(aud not in audience_claims for aud in audience): + raise InvalidAudienceError("Invalid audience") + + def _validate_iss(self, payload, issuer): + if issuer is None: + return + + if "iss" not in payload: + raise MissingRequiredClaimError("iss") + + if payload["iss"] != issuer: + raise InvalidIssuerError("Invalid issuer") + + +_jwt_global_obj = PyJWT() +encode = _jwt_global_obj.encode +decode_complete = _jwt_global_obj.decode_complete +decode = _jwt_global_obj.decode diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..ee201add1aac9c778669ed2316286b0fbfa3c30b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/exceptions.py @@ -0,0 +1,66 @@ +class PyJWTError(Exception): + """ + Base class for all exceptions + """ + + pass + + +class InvalidTokenError(PyJWTError): + pass + + +class DecodeError(InvalidTokenError): + pass + + +class InvalidSignatureError(DecodeError): + pass + + +class ExpiredSignatureError(InvalidTokenError): + pass + + +class InvalidAudienceError(InvalidTokenError): + pass + + +class InvalidIssuerError(InvalidTokenError): + pass + + +class InvalidIssuedAtError(InvalidTokenError): + pass + + +class ImmatureSignatureError(InvalidTokenError): + pass + + +class InvalidKeyError(PyJWTError): + pass + + +class InvalidAlgorithmError(InvalidTokenError): + pass + + +class MissingRequiredClaimError(InvalidTokenError): + def __init__(self, claim): + self.claim = claim + + def __str__(self): + return f'Token is missing the "{self.claim}" claim' + + +class PyJWKError(PyJWTError): + pass + + +class PyJWKSetError(PyJWTError): + pass + + +class PyJWKClientError(PyJWTError): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/help.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/help.py new file mode 100644 index 0000000000000000000000000000000000000000..0c02eb925c9a5578d5bd7b04be7566c9d59065cd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/help.py @@ -0,0 +1,62 @@ +import json +import platform +import sys +from typing import Dict + +from . import __version__ as pyjwt_version + +try: + import cryptography +except ModuleNotFoundError: + cryptography = None + + +def info() -> Dict[str, Dict[str, str]]: + """ + Generate information for a bug report. + Based on the requests package help utility module. + """ + try: + platform_info = { + "system": platform.system(), + "release": platform.release(), + } + except OSError: + platform_info = {"system": "Unknown", "release": "Unknown"} + + implementation = platform.python_implementation() + + if implementation == "CPython": + implementation_version = platform.python_version() + elif implementation == "PyPy": + pypy_version_info = getattr(sys, "pypy_version_info") + implementation_version = ( + f"{pypy_version_info.major}." + f"{pypy_version_info.minor}." + f"{pypy_version_info.micro}" + ) + if pypy_version_info.releaselevel != "final": + implementation_version = "".join( + [implementation_version, pypy_version_info.releaselevel] + ) + else: + implementation_version = "Unknown" + + return { + "platform": platform_info, + "implementation": { + "name": implementation, + "version": implementation_version, + }, + "cryptography": {"version": getattr(cryptography, "__version__", "")}, + "pyjwt": {"version": pyjwt_version}, + } + + +def main() -> None: + """Pretty-print the bug information as JSON.""" + print(json.dumps(info(), sort_keys=True, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwk_set_cache.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwk_set_cache.py new file mode 100644 index 0000000000000000000000000000000000000000..e8c2a7e0a7760b06a2aef00ca2127608ef2f1a1f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwk_set_cache.py @@ -0,0 +1,32 @@ +import time +from typing import Optional + +from .api_jwk import PyJWKSet, PyJWTSetWithTimestamp + + +class JWKSetCache: + def __init__(self, lifespan: int): + self.jwk_set_with_timestamp: Optional[PyJWTSetWithTimestamp] = None + self.lifespan = lifespan + + def put(self, jwk_set: PyJWKSet): + if jwk_set is not None: + self.jwk_set_with_timestamp = PyJWTSetWithTimestamp(jwk_set) + else: + # clear cache + self.jwk_set_with_timestamp = None + + def get(self) -> Optional[PyJWKSet]: + if self.jwk_set_with_timestamp is None or self.is_expired(): + return None + + return self.jwk_set_with_timestamp.get_jwk_set() + + def is_expired(self) -> bool: + + return ( + self.jwk_set_with_timestamp is not None + and self.lifespan > -1 + and time.monotonic() + > self.jwk_set_with_timestamp.get_timestamp() + self.lifespan + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwks_client.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwks_client.py new file mode 100644 index 0000000000000000000000000000000000000000..b4e98007ca545dfedbf35b12edfdf79cc17ab655 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/jwks_client.py @@ -0,0 +1,107 @@ +import json +import urllib.request +from functools import lru_cache +from typing import Any, List, Optional +from urllib.error import URLError + +from .api_jwk import PyJWK, PyJWKSet +from .api_jwt import decode_complete as decode_token +from .exceptions import PyJWKClientError +from .jwk_set_cache import JWKSetCache + + +class PyJWKClient: + def __init__( + self, + uri: str, + cache_keys: bool = False, + max_cached_keys: int = 16, + cache_jwk_set: bool = True, + lifespan: int = 300, + ): + self.uri = uri + self.jwk_set_cache: Optional[JWKSetCache] = None + + if cache_jwk_set: + # Init jwt set cache with default or given lifespan. + # Default lifespan is 300 seconds (5 minutes). + if lifespan <= 0: + raise PyJWKClientError( + f'Lifespan must be greater than 0, the input is "{lifespan}"' + ) + self.jwk_set_cache = JWKSetCache(lifespan) + else: + self.jwk_set_cache = None + + if cache_keys: + # Cache signing keys + # Ignore mypy (https://github.com/python/mypy/issues/2427) + self.get_signing_key = lru_cache(maxsize=max_cached_keys)(self.get_signing_key) # type: ignore + + def fetch_data(self) -> Any: + jwk_set: Any = None + try: + with urllib.request.urlopen(self.uri) as response: + jwk_set = json.load(response) + except URLError as e: + raise PyJWKClientError(f'Fail to fetch data from the url, err: "{e}"') + else: + return jwk_set + finally: + if self.jwk_set_cache is not None: + self.jwk_set_cache.put(jwk_set) + + def get_jwk_set(self, refresh: bool = False) -> PyJWKSet: + data = None + if self.jwk_set_cache is not None and not refresh: + data = self.jwk_set_cache.get() + + if data is None: + data = self.fetch_data() + + return PyJWKSet.from_dict(data) + + def get_signing_keys(self, refresh: bool = False) -> List[PyJWK]: + jwk_set = self.get_jwk_set(refresh) + signing_keys = [ + jwk_set_key + for jwk_set_key in jwk_set.keys + if jwk_set_key.public_key_use in ["sig", None] and jwk_set_key.key_id + ] + + if not signing_keys: + raise PyJWKClientError("The JWKS endpoint did not contain any signing keys") + + return signing_keys + + def get_signing_key(self, kid: str) -> PyJWK: + signing_keys = self.get_signing_keys() + signing_key = self.match_kid(signing_keys, kid) + + if not signing_key: + # If no matching signing key from the jwk set, refresh the jwk set and try again. + signing_keys = self.get_signing_keys(refresh=True) + signing_key = self.match_kid(signing_keys, kid) + + if not signing_key: + raise PyJWKClientError( + f'Unable to find a signing key that matches: "{kid}"' + ) + + return signing_key + + def get_signing_key_from_jwt(self, token: str) -> PyJWK: + unverified = decode_token(token, options={"verify_signature": False}) + header = unverified["header"] + return self.get_signing_key(header.get("kid")) + + @staticmethod + def match_kid(signing_keys: List[PyJWK], kid: str) -> Optional[PyJWK]: + signing_key = None + + for key in signing_keys: + if key.key_id == kid: + signing_key = key + break + + return signing_key diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/py.typed b/Latest_Group_Project/.venv/Lib/site-packages/jwt/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..16cae0662e48f605db54cdf86ba1008dba5a4003 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/utils.py @@ -0,0 +1,160 @@ +import base64 +import binascii +import re +from typing import Union + +try: + from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurve + from cryptography.hazmat.primitives.asymmetric.utils import ( + decode_dss_signature, + encode_dss_signature, + ) +except ModuleNotFoundError: + EllipticCurve = None + + +def force_bytes(value: Union[str, bytes]) -> bytes: + if isinstance(value, str): + return value.encode("utf-8") + elif isinstance(value, bytes): + return value + else: + raise TypeError("Expected a string value") + + +def base64url_decode(input: Union[str, bytes]) -> bytes: + if isinstance(input, str): + input = input.encode("ascii") + + rem = len(input) % 4 + + if rem > 0: + input += b"=" * (4 - rem) + + return base64.urlsafe_b64decode(input) + + +def base64url_encode(input: bytes) -> bytes: + return base64.urlsafe_b64encode(input).replace(b"=", b"") + + +def to_base64url_uint(val: int) -> bytes: + if val < 0: + raise ValueError("Must be a positive integer") + + int_bytes = bytes_from_int(val) + + if len(int_bytes) == 0: + int_bytes = b"\x00" + + return base64url_encode(int_bytes) + + +def from_base64url_uint(val: Union[str, bytes]) -> int: + if isinstance(val, str): + val = val.encode("ascii") + + data = base64url_decode(val) + return int.from_bytes(data, byteorder="big") + + +def number_to_bytes(num: int, num_bytes: int) -> bytes: + padded_hex = "%0*x" % (2 * num_bytes, num) + return binascii.a2b_hex(padded_hex.encode("ascii")) + + +def bytes_to_number(string: bytes) -> int: + return int(binascii.b2a_hex(string), 16) + + +def bytes_from_int(val: int) -> bytes: + remaining = val + byte_length = 0 + + while remaining != 0: + remaining >>= 8 + byte_length += 1 + + return val.to_bytes(byte_length, "big", signed=False) + + +def der_to_raw_signature(der_sig: bytes, curve: EllipticCurve) -> bytes: + num_bits = curve.key_size + num_bytes = (num_bits + 7) // 8 + + r, s = decode_dss_signature(der_sig) + + return number_to_bytes(r, num_bytes) + number_to_bytes(s, num_bytes) + + +def raw_to_der_signature(raw_sig: bytes, curve: EllipticCurve) -> bytes: + num_bits = curve.key_size + num_bytes = (num_bits + 7) // 8 + + if len(raw_sig) != 2 * num_bytes: + raise ValueError("Invalid signature") + + r = bytes_to_number(raw_sig[:num_bytes]) + s = bytes_to_number(raw_sig[num_bytes:]) + + return encode_dss_signature(r, s) + + +# Based on https://github.com/hynek/pem/blob/7ad94db26b0bc21d10953f5dbad3acfdfacf57aa/src/pem/_core.py#L224-L252 +_PEMS = { + b"CERTIFICATE", + b"TRUSTED CERTIFICATE", + b"PRIVATE KEY", + b"PUBLIC KEY", + b"ENCRYPTED PRIVATE KEY", + b"OPENSSH PRIVATE KEY", + b"DSA PRIVATE KEY", + b"RSA PRIVATE KEY", + b"RSA PUBLIC KEY", + b"EC PRIVATE KEY", + b"DH PARAMETERS", + b"NEW CERTIFICATE REQUEST", + b"CERTIFICATE REQUEST", + b"SSH2 PUBLIC KEY", + b"SSH2 ENCRYPTED PRIVATE KEY", + b"X509 CRL", +} + +_PEM_RE = re.compile( + b"----[- ]BEGIN (" + + b"|".join(_PEMS) + + b""")[- ]----\r? +.+?\r? +----[- ]END \\1[- ]----\r?\n?""", + re.DOTALL, +) + + +def is_pem_format(key: bytes) -> bool: + return bool(_PEM_RE.search(key)) + + +# Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 +_CERT_SUFFIX = b"-cert-v01@openssh.com" +_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") +_SSH_KEY_FORMATS = [ + b"ssh-ed25519", + b"ssh-rsa", + b"ssh-dss", + b"ecdsa-sha2-nistp256", + b"ecdsa-sha2-nistp384", + b"ecdsa-sha2-nistp521", +] + + +def is_ssh_key(key: bytes) -> bool: + if any(string_value in key for string_value in _SSH_KEY_FORMATS): + return True + + ssh_pubkey_match = _SSH_PUBKEY_RC.match(key) + if ssh_pubkey_match: + key_type = ssh_pubkey_match.group(1) + if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]: + return True + + return False diff --git a/Latest_Group_Project/.venv/Lib/site-packages/jwt/warnings.py b/Latest_Group_Project/.venv/Lib/site-packages/jwt/warnings.py new file mode 100644 index 0000000000000000000000000000000000000000..8762a8cbb3408b5b30901d4dd39fc53097eb31d8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/jwt/warnings.py @@ -0,0 +1,2 @@ +class RemovedInPyjwt3Warning(DeprecationWarning): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7166b1920e127e5ec2dd98da57ec8374cb946163 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__init__.py @@ -0,0 +1,295 @@ +import functools +import re +import string +import typing as t + +if t.TYPE_CHECKING: + import typing_extensions as te + + class HasHTML(te.Protocol): + def __html__(self) -> str: + pass + + +__version__ = "2.1.2" + +_strip_comments_re = re.compile(r"<!--.*?-->", re.DOTALL) +_strip_tags_re = re.compile(r"<.*?>", re.DOTALL) + + +def _simple_escaping_wrapper(name: str) -> t.Callable[..., "Markup"]: + orig = getattr(str, name) + + @functools.wraps(orig) + def wrapped(self: "Markup", *args: t.Any, **kwargs: t.Any) -> "Markup": + args = _escape_argspec(list(args), enumerate(args), self.escape) # type: ignore + _escape_argspec(kwargs, kwargs.items(), self.escape) + return self.__class__(orig(self, *args, **kwargs)) + + return wrapped + + +class Markup(str): + """A string that is ready to be safely inserted into an HTML or XML + document, either because it was escaped or because it was marked + safe. + + Passing an object to the constructor converts it to text and wraps + it to mark it safe without escaping. To escape the text, use the + :meth:`escape` class method instead. + + >>> Markup("Hello, <em>World</em>!") + Markup('Hello, <em>World</em>!') + >>> Markup(42) + Markup('42') + >>> Markup.escape("Hello, <em>World</em>!") + Markup('Hello <em>World</em>!') + + This implements the ``__html__()`` interface that some frameworks + use. Passing an object that implements ``__html__()`` will wrap the + output of that method, marking it safe. + + >>> class Foo: + ... def __html__(self): + ... return '<a href="/foo">foo</a>' + ... + >>> Markup(Foo()) + Markup('<a href="/foo">foo</a>') + + This is a subclass of :class:`str`. It has the same methods, but + escapes their arguments and returns a ``Markup`` instance. + + >>> Markup("<em>%s</em>") % ("foo & bar",) + Markup('<em>foo & bar</em>') + >>> Markup("<em>Hello</em> ") + "<foo>" + Markup('<em>Hello</em> <foo>') + """ + + __slots__ = () + + def __new__( + cls, base: t.Any = "", encoding: t.Optional[str] = None, errors: str = "strict" + ) -> "Markup": + if hasattr(base, "__html__"): + base = base.__html__() + + if encoding is None: + return super().__new__(cls, base) + + return super().__new__(cls, base, encoding, errors) + + def __html__(self) -> "Markup": + return self + + def __add__(self, other: t.Union[str, "HasHTML"]) -> "Markup": + if isinstance(other, str) or hasattr(other, "__html__"): + return self.__class__(super().__add__(self.escape(other))) + + return NotImplemented + + def __radd__(self, other: t.Union[str, "HasHTML"]) -> "Markup": + if isinstance(other, str) or hasattr(other, "__html__"): + return self.escape(other).__add__(self) + + return NotImplemented + + def __mul__(self, num: "te.SupportsIndex") -> "Markup": + if isinstance(num, int): + return self.__class__(super().__mul__(num)) + + return NotImplemented + + __rmul__ = __mul__ + + def __mod__(self, arg: t.Any) -> "Markup": + if isinstance(arg, tuple): + # a tuple of arguments, each wrapped + arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg) + elif hasattr(type(arg), "__getitem__") and not isinstance(arg, str): + # a mapping of arguments, wrapped + arg = _MarkupEscapeHelper(arg, self.escape) + else: + # a single argument, wrapped with the helper and a tuple + arg = (_MarkupEscapeHelper(arg, self.escape),) + + return self.__class__(super().__mod__(arg)) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + def join(self, seq: t.Iterable[t.Union[str, "HasHTML"]]) -> "Markup": + return self.__class__(super().join(map(self.escape, seq))) + + join.__doc__ = str.join.__doc__ + + def split( # type: ignore + self, sep: t.Optional[str] = None, maxsplit: int = -1 + ) -> t.List["Markup"]: + return [self.__class__(v) for v in super().split(sep, maxsplit)] + + split.__doc__ = str.split.__doc__ + + def rsplit( # type: ignore + self, sep: t.Optional[str] = None, maxsplit: int = -1 + ) -> t.List["Markup"]: + return [self.__class__(v) for v in super().rsplit(sep, maxsplit)] + + rsplit.__doc__ = str.rsplit.__doc__ + + def splitlines(self, keepends: bool = False) -> t.List["Markup"]: # type: ignore + return [self.__class__(v) for v in super().splitlines(keepends)] + + splitlines.__doc__ = str.splitlines.__doc__ + + def unescape(self) -> str: + """Convert escaped markup back into a text string. This replaces + HTML entities with the characters they represent. + + >>> Markup("Main » <em>About</em>").unescape() + 'Main » <em>About</em>' + """ + from html import unescape + + return unescape(str(self)) + + def striptags(self) -> str: + """:meth:`unescape` the markup, remove tags, and normalize + whitespace to single spaces. + + >>> Markup("Main »\t<em>About</em>").striptags() + 'Main » About' + """ + # Use two regexes to avoid ambiguous matches. + value = _strip_comments_re.sub("", self) + value = _strip_tags_re.sub("", value) + value = " ".join(value.split()) + return Markup(value).unescape() + + @classmethod + def escape(cls, s: t.Any) -> "Markup": + """Escape a string. Calls :func:`escape` and ensures that for + subclasses the correct type is returned. + """ + rv = escape(s) + + if rv.__class__ is not cls: + return cls(rv) + + return rv + + for method in ( + "__getitem__", + "capitalize", + "title", + "lower", + "upper", + "replace", + "ljust", + "rjust", + "lstrip", + "rstrip", + "center", + "strip", + "translate", + "expandtabs", + "swapcase", + "zfill", + ): + locals()[method] = _simple_escaping_wrapper(method) + + del method + + def partition(self, sep: str) -> t.Tuple["Markup", "Markup", "Markup"]: + l, s, r = super().partition(self.escape(sep)) + cls = self.__class__ + return cls(l), cls(s), cls(r) + + def rpartition(self, sep: str) -> t.Tuple["Markup", "Markup", "Markup"]: + l, s, r = super().rpartition(self.escape(sep)) + cls = self.__class__ + return cls(l), cls(s), cls(r) + + def format(self, *args: t.Any, **kwargs: t.Any) -> "Markup": + formatter = EscapeFormatter(self.escape) + return self.__class__(formatter.vformat(self, args, kwargs)) + + def __html_format__(self, format_spec: str) -> "Markup": + if format_spec: + raise ValueError("Unsupported format specification for Markup.") + + return self + + +class EscapeFormatter(string.Formatter): + __slots__ = ("escape",) + + def __init__(self, escape: t.Callable[[t.Any], Markup]) -> None: + self.escape = escape + super().__init__() + + def format_field(self, value: t.Any, format_spec: str) -> str: + if hasattr(value, "__html_format__"): + rv = value.__html_format__(format_spec) + elif hasattr(value, "__html__"): + if format_spec: + raise ValueError( + f"Format specifier {format_spec} given, but {type(value)} does not" + " define __html_format__. A class that defines __html__ must define" + " __html_format__ to work with format specifiers." + ) + rv = value.__html__() + else: + # We need to make sure the format spec is str here as + # otherwise the wrong callback methods are invoked. + rv = string.Formatter.format_field(self, value, str(format_spec)) + return str(self.escape(rv)) + + +_ListOrDict = t.TypeVar("_ListOrDict", list, dict) + + +def _escape_argspec( + obj: _ListOrDict, iterable: t.Iterable[t.Any], escape: t.Callable[[t.Any], Markup] +) -> _ListOrDict: + """Helper for various string-wrapped functions.""" + for key, value in iterable: + if isinstance(value, str) or hasattr(value, "__html__"): + obj[key] = escape(value) + + return obj + + +class _MarkupEscapeHelper: + """Helper for :meth:`Markup.__mod__`.""" + + __slots__ = ("obj", "escape") + + def __init__(self, obj: t.Any, escape: t.Callable[[t.Any], Markup]) -> None: + self.obj = obj + self.escape = escape + + def __getitem__(self, item: t.Any) -> "_MarkupEscapeHelper": + return _MarkupEscapeHelper(self.obj[item], self.escape) + + def __str__(self) -> str: + return str(self.escape(self.obj)) + + def __repr__(self) -> str: + return str(self.escape(repr(self.obj))) + + def __int__(self) -> int: + return int(self.obj) + + def __float__(self) -> float: + return float(self.obj) + + +# circular import +try: + from ._speedups import escape as escape + from ._speedups import escape_silent as escape_silent + from ._speedups import soft_str as soft_str +except ImportError: + from ._native import escape as escape + from ._native import escape_silent as escape_silent # noqa: F401 + from ._native import soft_str as soft_str # noqa: F401 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b057b77ae81b0fa59369eff32d03dd24869c719f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..118f55d4233a51e3ab853cc5607efd62bccd4194 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_native.py b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_native.py new file mode 100644 index 0000000000000000000000000000000000000000..8117b2716d110074d9a81365c59343e81396b7f5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_native.py @@ -0,0 +1,63 @@ +import typing as t + +from . import Markup + + +def escape(s: t.Any) -> Markup: + """Replace the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in + the string with HTML-safe sequences. Use this if you need to display + text that might contain such characters in HTML. + + If the object has an ``__html__`` method, it is called and the + return value is assumed to already be safe for HTML. + + :param s: An object to be converted to a string and escaped. + :return: A :class:`Markup` string with the escaped text. + """ + if hasattr(s, "__html__"): + return Markup(s.__html__()) + + return Markup( + str(s) + .replace("&", "&") + .replace(">", ">") + .replace("<", "<") + .replace("'", "'") + .replace('"', """) + ) + + +def escape_silent(s: t.Optional[t.Any]) -> Markup: + """Like :func:`escape` but treats ``None`` as the empty string. + Useful with optional values, as otherwise you get the string + ``'None'`` when the value is ``None``. + + >>> escape(None) + Markup('None') + >>> escape_silent(None) + Markup('') + """ + if s is None: + return Markup() + + return escape(s) + + +def soft_str(s: t.Any) -> str: + """Convert an object to a string if it isn't already. This preserves + a :class:`Markup` string rather than converting it back to a basic + string, so it will still be marked as safe and won't be escaped + again. + + >>> value = escape("<User 1>") + >>> value + Markup('<User 1>') + >>> escape(str(value)) + Markup('&lt;User 1&gt;') + >>> escape(soft_str(value)) + Markup('<User 1>') + """ + if not isinstance(s, str): + return str(s) + + return s diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.c b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.c new file mode 100644 index 0000000000000000000000000000000000000000..3c463fb82d53e9a9616acfbbece0eb3be6d0d5e7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.c @@ -0,0 +1,320 @@ +#include <Python.h> + +static PyObject* markup; + +static int +init_constants(void) +{ + PyObject *module; + + /* import markup type so that we can mark the return value */ + module = PyImport_ImportModule("markupsafe"); + if (!module) + return 0; + markup = PyObject_GetAttrString(module, "Markup"); + Py_DECREF(module); + + return 1; +} + +#define GET_DELTA(inp, inp_end, delta) \ + while (inp < inp_end) { \ + switch (*inp++) { \ + case '"': \ + case '\'': \ + case '&': \ + delta += 4; \ + break; \ + case '<': \ + case '>': \ + delta += 3; \ + break; \ + } \ + } + +#define DO_ESCAPE(inp, inp_end, outp) \ + { \ + Py_ssize_t ncopy = 0; \ + while (inp < inp_end) { \ + switch (*inp) { \ + case '"': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = '#'; \ + *outp++ = '3'; \ + *outp++ = '4'; \ + *outp++ = ';'; \ + break; \ + case '\'': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = '#'; \ + *outp++ = '3'; \ + *outp++ = '9'; \ + *outp++ = ';'; \ + break; \ + case '&': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'a'; \ + *outp++ = 'm'; \ + *outp++ = 'p'; \ + *outp++ = ';'; \ + break; \ + case '<': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'l'; \ + *outp++ = 't'; \ + *outp++ = ';'; \ + break; \ + case '>': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'g'; \ + *outp++ = 't'; \ + *outp++ = ';'; \ + break; \ + default: \ + ncopy++; \ + } \ + inp++; \ + } \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + } + +static PyObject* +escape_unicode_kind1(PyUnicodeObject *in) +{ + Py_UCS1 *inp = PyUnicode_1BYTE_DATA(in); + Py_UCS1 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS1 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, + PyUnicode_IS_ASCII(in) ? 127 : 255); + if (!out) + return NULL; + + inp = PyUnicode_1BYTE_DATA(in); + outp = PyUnicode_1BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + +static PyObject* +escape_unicode_kind2(PyUnicodeObject *in) +{ + Py_UCS2 *inp = PyUnicode_2BYTE_DATA(in); + Py_UCS2 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS2 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 65535); + if (!out) + return NULL; + + inp = PyUnicode_2BYTE_DATA(in); + outp = PyUnicode_2BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + + +static PyObject* +escape_unicode_kind4(PyUnicodeObject *in) +{ + Py_UCS4 *inp = PyUnicode_4BYTE_DATA(in); + Py_UCS4 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS4 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 1114111); + if (!out) + return NULL; + + inp = PyUnicode_4BYTE_DATA(in); + outp = PyUnicode_4BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + +static PyObject* +escape_unicode(PyUnicodeObject *in) +{ + if (PyUnicode_READY(in)) + return NULL; + + switch (PyUnicode_KIND(in)) { + case PyUnicode_1BYTE_KIND: + return escape_unicode_kind1(in); + case PyUnicode_2BYTE_KIND: + return escape_unicode_kind2(in); + case PyUnicode_4BYTE_KIND: + return escape_unicode_kind4(in); + } + assert(0); /* shouldn't happen */ + return NULL; +} + +static PyObject* +escape(PyObject *self, PyObject *text) +{ + static PyObject *id_html; + PyObject *s = NULL, *rv = NULL, *html; + + if (id_html == NULL) { + id_html = PyUnicode_InternFromString("__html__"); + if (id_html == NULL) { + return NULL; + } + } + + /* we don't have to escape integers, bools or floats */ + if (PyLong_CheckExact(text) || + PyFloat_CheckExact(text) || PyBool_Check(text) || + text == Py_None) + return PyObject_CallFunctionObjArgs(markup, text, NULL); + + /* if the object has an __html__ method that performs the escaping */ + html = PyObject_GetAttr(text ,id_html); + if (html) { + s = PyObject_CallObject(html, NULL); + Py_DECREF(html); + if (s == NULL) { + return NULL; + } + /* Convert to Markup object */ + rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL); + Py_DECREF(s); + return rv; + } + + /* otherwise make the object unicode if it isn't, then escape */ + PyErr_Clear(); + if (!PyUnicode_Check(text)) { + PyObject *unicode = PyObject_Str(text); + if (!unicode) + return NULL; + s = escape_unicode((PyUnicodeObject*)unicode); + Py_DECREF(unicode); + } + else + s = escape_unicode((PyUnicodeObject*)text); + + /* convert the unicode string into a markup object. */ + rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL); + Py_DECREF(s); + return rv; +} + + +static PyObject* +escape_silent(PyObject *self, PyObject *text) +{ + if (text != Py_None) + return escape(self, text); + return PyObject_CallFunctionObjArgs(markup, NULL); +} + + +static PyObject* +soft_str(PyObject *self, PyObject *s) +{ + if (!PyUnicode_Check(s)) + return PyObject_Str(s); + Py_INCREF(s); + return s; +} + + +static PyMethodDef module_methods[] = { + { + "escape", + (PyCFunction)escape, + METH_O, + "Replace the characters ``&``, ``<``, ``>``, ``'``, and ``\"`` in" + " the string with HTML-safe sequences. Use this if you need to display" + " text that might contain such characters in HTML.\n\n" + "If the object has an ``__html__`` method, it is called and the" + " return value is assumed to already be safe for HTML.\n\n" + ":param s: An object to be converted to a string and escaped.\n" + ":return: A :class:`Markup` string with the escaped text.\n" + }, + { + "escape_silent", + (PyCFunction)escape_silent, + METH_O, + "Like :func:`escape` but treats ``None`` as the empty string." + " Useful with optional values, as otherwise you get the string" + " ``'None'`` when the value is ``None``.\n\n" + ">>> escape(None)\n" + "Markup('None')\n" + ">>> escape_silent(None)\n" + "Markup('')\n" + }, + { + "soft_str", + (PyCFunction)soft_str, + METH_O, + "Convert an object to a string if it isn't already. This preserves" + " a :class:`Markup` string rather than converting it back to a basic" + " string, so it will still be marked as safe and won't be escaped" + " again.\n\n" + ">>> value = escape(\"<User 1>\")\n" + ">>> value\n" + "Markup('<User 1>')\n" + ">>> escape(str(value))\n" + "Markup('&lt;User 1&gt;')\n" + ">>> escape(soft_str(value))\n" + "Markup('<User 1>')\n" + }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +static struct PyModuleDef module_definition = { + PyModuleDef_HEAD_INIT, + "markupsafe._speedups", + NULL, + -1, + module_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit__speedups(void) +{ + if (!init_constants()) + return NULL; + + return PyModule_Create(&module_definition); +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.cp310-win_amd64.pyd b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.cp310-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..30312be820f0d80e53833631520ff57b85ae51cb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.cp310-win_amd64.pyd differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.pyi b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.pyi new file mode 100644 index 0000000000000000000000000000000000000000..f673240f6d299917d829a5fdbf85d25d84dd0a72 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/_speedups.pyi @@ -0,0 +1,9 @@ +from typing import Any +from typing import Optional + +from . import Markup + +def escape(s: Any) -> Markup: ... +def escape_silent(s: Optional[Any]) -> Markup: ... +def soft_str(s: Any) -> str: ... +def soft_unicode(s: Any) -> str: ... diff --git a/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/py.typed b/Latest_Group_Project/.venv/Lib/site-packages/markupsafe/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d5a9e9acd071bf1d2b17d5e7d30746dde7c382b7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019 The OAuthlib Community +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of this project nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..5bb339b0bddf5e8b2a07dd95a4913392fde9702a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/METADATA @@ -0,0 +1,179 @@ +Metadata-Version: 2.1 +Name: oauthlib +Version: 3.2.2 +Summary: A generic, spec-compliant, thorough implementation of the OAuth request-signing logic +Home-page: https://github.com/oauthlib/oauthlib +Author: The OAuthlib Community +Author-email: idan@gazit.me +Maintainer: Ib Lundgren +Maintainer-email: ib.lundgren@gmail.com +License: BSD +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: MacOS +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: Linux +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 :: Only +Classifier: Programming Language :: Python :: Implementation +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE +Provides-Extra: rsa +Requires-Dist: cryptography (>=3.0.0) ; extra == 'rsa' +Provides-Extra: signals +Requires-Dist: blinker (>=1.4.0) ; extra == 'signals' +Provides-Extra: signedtoken +Requires-Dist: cryptography (>=3.0.0) ; extra == 'signedtoken' +Requires-Dist: pyjwt (<3,>=2.0.0) ; extra == 'signedtoken' + +OAuthLib - Python Framework for OAuth1 & OAuth2 +=============================================== + +*A generic, spec-compliant, thorough implementation of the OAuth request-signing +logic for Python 3.6+.* + +.. image:: https://app.travis-ci.com/oauthlib/oauthlib.svg?branch=master + :target: https://app.travis-ci.com/oauthlib/oauthlib + :alt: Travis +.. image:: https://coveralls.io/repos/oauthlib/oauthlib/badge.svg?branch=master + :target: https://coveralls.io/r/oauthlib/oauthlib + :alt: Coveralls +.. image:: https://img.shields.io/pypi/pyversions/oauthlib.svg + :target: https://pypi.org/project/oauthlib/ + :alt: Download from PyPI +.. image:: https://img.shields.io/pypi/l/oauthlib.svg + :target: https://pypi.org/project/oauthlib/ + :alt: License +.. image:: https://app.fossa.io/api/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib.svg?type=shield + :target: https://app.fossa.io/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib?ref=badge_shield + :alt: FOSSA Status +.. image:: https://img.shields.io/readthedocs/oauthlib.svg + :target: https://oauthlib.readthedocs.io/en/latest/index.html + :alt: Read the Docs +.. image:: https://badges.gitter.im/oauthlib/oauthlib.svg + :target: https://gitter.im/oauthlib/Lobby + :alt: Chat on Gitter + + +.. image:: https://raw.githubusercontent.com/oauthlib/oauthlib/8d71b161fd145d11c40d55c9ab66ac134a303253/docs/logo/oauthlib-banner-700x192.png + :target: https://github.com/oauthlib/oauthlib/ + :alt: OAuth + Python = OAuthlib Python Framework + + +OAuth often seems complicated and difficult-to-implement. There are several +prominent libraries for handling OAuth requests, but they all suffer from one or +both of the following: + +1. They predate the `OAuth 1.0 spec`_, AKA RFC 5849. +2. They predate the `OAuth 2.0 spec`_, AKA RFC 6749. +3. They assume the usage of a specific HTTP request library. + +.. _`OAuth 1.0 spec`: https://tools.ietf.org/html/rfc5849 +.. _`OAuth 2.0 spec`: https://tools.ietf.org/html/rfc6749 + +OAuthLib is a framework which implements the logic of OAuth1 or OAuth2 without +assuming a specific HTTP request object or web framework. Use it to graft OAuth +client support onto your favorite HTTP library, or provide support onto your +favourite web framework. If you're a maintainer of such a library, write a thin +veneer on top of OAuthLib and get OAuth support for very little effort. + + +Documentation +-------------- + +Full documentation is available on `Read the Docs`_. All contributions are very +welcome! The documentation is still quite sparse, please open an issue for what +you'd like to know, or discuss it in our `Gitter community`_, or even better, send a +pull request! + +.. _`Gitter community`: https://gitter.im/oauthlib/Lobby +.. _`Read the Docs`: https://oauthlib.readthedocs.io/en/latest/index.html + +Interested in making OAuth requests? +------------------------------------ + +Then you might be more interested in using `requests`_ which has OAuthLib +powered OAuth support provided by the `requests-oauthlib`_ library. + +.. _`requests`: https://github.com/requests/requests +.. _`requests-oauthlib`: https://github.com/requests/requests-oauthlib + +Which web frameworks are supported? +----------------------------------- + +The following packages provide OAuth support using OAuthLib. + +- For Django there is `django-oauth-toolkit`_, which includes `Django REST framework`_ support. +- For Flask there is `flask-oauthlib`_ and `Flask-Dance`_. +- For Pyramid there is `pyramid-oauthlib`_. +- For Bottle there is `bottle-oauthlib`_. + +If you have written an OAuthLib package that supports your favorite framework, +please open a Pull Request, updating the documentation. + +.. _`django-oauth-toolkit`: https://github.com/evonove/django-oauth-toolkit +.. _`flask-oauthlib`: https://github.com/lepture/flask-oauthlib +.. _`Django REST framework`: http://django-rest-framework.org +.. _`Flask-Dance`: https://github.com/singingwolfboy/flask-dance +.. _`pyramid-oauthlib`: https://github.com/tilgovi/pyramid-oauthlib +.. _`bottle-oauthlib`: https://github.com/thomsonreuters/bottle-oauthlib + +Using OAuthLib? Please get in touch! +------------------------------------ +Patching OAuth support onto an http request framework? Creating an OAuth +provider extension for a web framework? Simply using OAuthLib to Get Things Done +or to learn? + +No matter which we'd love to hear from you in our `Gitter community`_ or if you have +anything in particular you would like to have, change or comment on don't +hesitate for a second to send a pull request or open an issue. We might be quite +busy and therefore slow to reply but we love feedback! + +Chances are you have run into something annoying that you wish there was +documentation for, if you wish to gain eternal fame and glory, and a drink if we +have the pleasure to run into each other, please send a docs pull request =) + +.. _`Gitter community`: https://gitter.im/oauthlib/Lobby + +License +------- + +OAuthLib is yours to use and abuse according to the terms of the BSD license. +Check the LICENSE file for full details. + +Credits +------- + +OAuthLib has been started and maintained several years by Idan Gazit and other +amazing `AUTHORS`_. Thanks to their wonderful work, the open-source `community`_ +creation has been possible and the project can stay active and reactive to users +requests. + + +.. _`AUTHORS`: https://github.com/oauthlib/oauthlib/blob/master/AUTHORS +.. _`community`: https://github.com/oauthlib/ + +Changelog +--------- + +*OAuthLib is in active development, with the core of both OAuth1 and OAuth2 +completed, for providers as well as clients.* See `supported features`_ for +details. + +.. _`supported features`: https://oauthlib.readthedocs.io/en/latest/feature_matrix.html + +For a full changelog see ``CHANGELOG.rst``. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..95eef4c36dbdd55ad18931b3fc14a15bce3e0db3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/RECORD @@ -0,0 +1,142 @@ +oauthlib-3.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +oauthlib-3.2.2.dist-info/LICENSE,sha256=PR4S2KxSwLbBSK9tKR9yQAuHIO0WwKxKiYaLbRSxyTk,1530 +oauthlib-3.2.2.dist-info/METADATA,sha256=zEM0Qha7hvi0hlwugHjMoKISoAJG8X-SeMDK3CECSG4,7454 +oauthlib-3.2.2.dist-info/RECORD,, +oauthlib-3.2.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +oauthlib-3.2.2.dist-info/top_level.txt,sha256=gz2py0fFs1AhG1O7KpHPcIXOgXOwdIiCaSnmLkiR12Q,9 +oauthlib/__init__.py,sha256=XeBZVT7i8Hx3nnEIb0MaNWrFQmxS3sc4SvGkOKhnht4,686 +oauthlib/__pycache__/__init__.cpython-310.pyc,, +oauthlib/__pycache__/common.cpython-310.pyc,, +oauthlib/__pycache__/signals.cpython-310.pyc,, +oauthlib/__pycache__/uri_validate.cpython-310.pyc,, +oauthlib/common.py,sha256=VL5A-cXOkRbjMu7E79OxDymV7tLOt0Cm2y1xchEw_Ig,13377 +oauthlib/oauth1/__init__.py,sha256=47hEQ7s_FZXLyUt6XVE-DPC8vUMVsJl7_-HCkNM2IlM,822 +oauthlib/oauth1/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__init__.py,sha256=-5sJHDG3JRZQRJYlCjkj3CP2jZgqEg0OY5pVIxE4mxE,16744 +oauthlib/oauth1/rfc5849/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__pycache__/errors.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__pycache__/parameters.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__pycache__/request_validator.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__pycache__/signature.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/__pycache__/utils.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__init__.py,sha256=SeIECziJ-Sv_NCGnowG3P9UnX_VdFNldRqRywEaJvxY,327 +oauthlib/oauth1/rfc5849/endpoints/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/access_token.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/authorization.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/base.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/pre_configured.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/request_token.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/resource.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/__pycache__/signature_only.cpython-310.pyc,, +oauthlib/oauth1/rfc5849/endpoints/access_token.py,sha256=CRgLV5DqDiwVvbo8MiHySbTEKrxETJV29-VGu-2kQ7Y,9347 +oauthlib/oauth1/rfc5849/endpoints/authorization.py,sha256=zbU7TzO6nB6853UIqtTkhxUV-JTHOdOc-CvdQsIQKWk,6724 +oauthlib/oauth1/rfc5849/endpoints/base.py,sha256=W0IxgaFM7sNFpsis-mo3Ky59wbLl2PNlYjIeqUCvyak,11637 +oauthlib/oauth1/rfc5849/endpoints/pre_configured.py,sha256=Ie5oBUq_JTsXQdvfWhcMRjhH3OOxS_mRHbKBQ9TpsGg,543 +oauthlib/oauth1/rfc5849/endpoints/request_token.py,sha256=1eljiIUPkObutaNDD6J7Kx5Ens1bknqHIEnnEkQGF7k,9291 +oauthlib/oauth1/rfc5849/endpoints/resource.py,sha256=F6f2AecZ1fTdrC7DOERrIFUp2YQ5MLq8-a6VbQLM2ds,7374 +oauthlib/oauth1/rfc5849/endpoints/signature_only.py,sha256=MX5zV66v4-wrR4cu7OmOd_GF3L8ysM60HmEiHtRR0l8,3327 +oauthlib/oauth1/rfc5849/errors.py,sha256=WPvKVjPlgkCYp6TXvcwC8VETkhsZBzphKCkTJKDPNfM,2474 +oauthlib/oauth1/rfc5849/parameters.py,sha256=Abnxpix_Yy7P3A3vbkrV2bkFxtnR5TRTTKdOu9MKydo,4802 +oauthlib/oauth1/rfc5849/request_validator.py,sha256=7Tt1uyt4LAWhKCMrQc9GR_EShZyckPigDXkxDNvxiBE,30987 +oauthlib/oauth1/rfc5849/signature.py,sha256=WY0ArNQg-9HBU2Hl4cpfFfW0Y3WUsW7XRqgL4w5jLmE,32076 +oauthlib/oauth1/rfc5849/utils.py,sha256=IapG_jM6iMe4e0DYWWds1jp-wce2Lf_cuhFrtCP_2ls,2613 +oauthlib/oauth2/__init__.py,sha256=uPkdHF2NEpIM6Ybz-jPPEKU5e56eHptaOz2NPwppyys,1597 +oauthlib/oauth2/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__init__.py,sha256=sJcxfdG6HTloXzhkG8-PTJTVQWoCeNtnw6ODNCJNw58,404 +oauthlib/oauth2/rfc6749/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__pycache__/errors.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__pycache__/parameters.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__pycache__/request_validator.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__pycache__/tokens.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/__pycache__/utils.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__init__.py,sha256=TuYtiErfo0_Ej0816tIv5rBsrwA9BjYz3tu_ZM0X364,504 +oauthlib/oauth2/rfc6749/clients/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/backend_application.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/base.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/legacy_application.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/mobile_application.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/service_application.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/__pycache__/web_application.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/clients/backend_application.py,sha256=2kEw6T5Ii2TMSpvHlvi697_eMV9fXjkjqc8DY5sG310,3224 +oauthlib/oauth2/rfc6749/clients/base.py,sha256=6ZW6ewf4SdS2BBGc-rZunfsGYalOqeucToNN8j8f7lc,26652 +oauthlib/oauth2/rfc6749/clients/legacy_application.py,sha256=9V-PGgToIoQcvmG14g9WiQjsDgWs7OnvLpZfmiA2Z24,4032 +oauthlib/oauth2/rfc6749/clients/mobile_application.py,sha256=eos0OLJmy-e5FFRHD-sjzDjMu7DlQxqayslZfbBtTNE,8878 +oauthlib/oauth2/rfc6749/clients/service_application.py,sha256=wksSW2I-sth3ykXps_CssI0m7GC20lOh5jIl_mIjdQU,7812 +oauthlib/oauth2/rfc6749/clients/web_application.py,sha256=RMk0_wzV-36TdMtcoeZ0I-lSB5sHWDpyWFTg5JFYVFM,12088 +oauthlib/oauth2/rfc6749/endpoints/__init__.py,sha256=RL_txhULl35A74dbvlJ7nvqwp3GMCSCpg_4TvjoO-Xk,553 +oauthlib/oauth2/rfc6749/endpoints/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/authorization.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/base.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/introspect.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/metadata.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/pre_configured.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/resource.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/revocation.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/__pycache__/token.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/endpoints/authorization.py,sha256=2N2Cb_TQtpUPcqDIclsJnZERtaMKmH9uSgGoMZLFnUI,4584 +oauthlib/oauth2/rfc6749/endpoints/base.py,sha256=fUhCGaftD5bm5PstA6L2CqUNb9kHDpUj4_BsvLRbi4w,4130 +oauthlib/oauth2/rfc6749/endpoints/introspect.py,sha256=zMkbHNJUC0Ww4aqs-Px_Yil_bNPSDDcMlZVA4C1nOb0,4947 +oauthlib/oauth2/rfc6749/endpoints/metadata.py,sha256=NOqXwoD34n94pC3IczakrpXMrZSPDruLMUl2_2MjW6Q,10530 +oauthlib/oauth2/rfc6749/endpoints/pre_configured.py,sha256=ChhORao78XGGlnikJsLb6d_FZvKaLGBUM-te-84NeJ8,11954 +oauthlib/oauth2/rfc6749/endpoints/resource.py,sha256=vpXoovgpmByY-IuW0PDccS5IJGFoFiLVjLLUpGFmXX4,3248 +oauthlib/oauth2/rfc6749/endpoints/revocation.py,sha256=68Ukipz7UOdeBCmO5KTRo0vwbUFd8tTG22Ck0hFlumw,5212 +oauthlib/oauth2/rfc6749/endpoints/token.py,sha256=iJDlaSkVR8U6s1_T9fiyVnLgfCgOWsq9PFDcmzL74H4,4595 +oauthlib/oauth2/rfc6749/errors.py,sha256=5EE4Qs3ru34d33wqaFo-WGOofLLYK1jTov9sqG92CW0,12947 +oauthlib/oauth2/rfc6749/grant_types/__init__.py,sha256=im_XwEWmw3dhmzcdfyhkN38xZopBhL3cRShmmCtqQs0,368 +oauthlib/oauth2/rfc6749/grant_types/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/authorization_code.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/base.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/client_credentials.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/implicit.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/refresh_token.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/__pycache__/resource_owner_password_credentials.cpython-310.pyc,, +oauthlib/oauth2/rfc6749/grant_types/authorization_code.py,sha256=RPXH4qdy0byAFjgsEvD0iiOxSrGkbEj7hkweeT8pZRQ,26102 +oauthlib/oauth2/rfc6749/grant_types/base.py,sha256=x5Q6Fm9iScvbkiXU6J_dUzxpXJq-qb_N-TNPYuIiObU,10969 +oauthlib/oauth2/rfc6749/grant_types/client_credentials.py,sha256=Wr0CpWDVmHrIfOBPTYp9RxnISTfYdp5SjSaRAu77vUY,5079 +oauthlib/oauth2/rfc6749/grant_types/implicit.py,sha256=hYAEYOwToxo3eNpGRC9SyJue93tu37jZVL7MYiaErDs,16852 +oauthlib/oauth2/rfc6749/grant_types/refresh_token.py,sha256=3oYMvW0gVhIrjs17RP_SFyZrTNi6hjVrEh45Z1GcIA0,5891 +oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py,sha256=9FsDbrSNNylWKkEvgdafJDzlNncTRCOhIZODo-f4ZIM,8516 +oauthlib/oauth2/rfc6749/parameters.py,sha256=BUGD3N_H9pBRctUYEDCD7dwncqjcHv7hW1ZcHMMQJb4,19016 +oauthlib/oauth2/rfc6749/request_validator.py,sha256=BZj1OURgQh_sxG5agbSpLTeo_IVxvYUqqDKkoAGqCbM,28851 +oauthlib/oauth2/rfc6749/tokens.py,sha256=RMcY7F4fCAoxZbyUUDN9el_B_XRp4ELrY3pj5awA1Do,11116 +oauthlib/oauth2/rfc6749/utils.py,sha256=EKlU_U-FcYkdd8PvXo1irtHTqBXF7gKqdFKBadteZ64,2207 +oauthlib/oauth2/rfc8628/__init__.py,sha256=yfG2QHuDxrp7_9HNKPEeXYXA_qBVZqiRrhI7q2cG4NM,232 +oauthlib/oauth2/rfc8628/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc8628/clients/__init__.py,sha256=indCdGycy9cekvLOBxYbCwtyezEVhl3uKZzoShml-aY,201 +oauthlib/oauth2/rfc8628/clients/__pycache__/__init__.cpython-310.pyc,, +oauthlib/oauth2/rfc8628/clients/__pycache__/device.cpython-310.pyc,, +oauthlib/oauth2/rfc8628/clients/device.py,sha256=0QgAfokzgzh6Jx5Nbnkwi2F67N7HruEAc_ZRCWr-JH0,4052 +oauthlib/openid/__init__.py,sha256=qZQCKCdQt40myte_nxSYrWvzf1VVADqRl8om0-t6LzE,162 +oauthlib/openid/__pycache__/__init__.cpython-310.pyc,, +oauthlib/openid/connect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +oauthlib/openid/connect/__pycache__/__init__.cpython-310.pyc,, +oauthlib/openid/connect/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +oauthlib/openid/connect/core/__pycache__/__init__.cpython-310.pyc,, +oauthlib/openid/connect/core/__pycache__/exceptions.cpython-310.pyc,, +oauthlib/openid/connect/core/__pycache__/request_validator.cpython-310.pyc,, +oauthlib/openid/connect/core/__pycache__/tokens.cpython-310.pyc,, +oauthlib/openid/connect/core/endpoints/__init__.py,sha256=nQ6mGniUaM9X1ENG0tZlPgWgbLdlFESWGK-5_e8mp5Y,229 +oauthlib/openid/connect/core/endpoints/__pycache__/__init__.cpython-310.pyc,, +oauthlib/openid/connect/core/endpoints/__pycache__/pre_configured.cpython-310.pyc,, +oauthlib/openid/connect/core/endpoints/__pycache__/userinfo.cpython-310.pyc,, +oauthlib/openid/connect/core/endpoints/pre_configured.py,sha256=p4Bq4HHUTvCBYXlTHr3PXktABKjHFGC3yBmwxWifzKc,5426 +oauthlib/openid/connect/core/endpoints/userinfo.py,sha256=kc1Q3DN8xByk3Qe_S0LAlmJR2MkXnCnNFqLqVr8y3zU,4096 +oauthlib/openid/connect/core/exceptions.py,sha256=uMMjE7VMc16jyL7TIhpbCx48_MsHD2C_atoMIemBKVA,4790 +oauthlib/openid/connect/core/grant_types/__init__.py,sha256=geSZh6OFlupoC2tg9Bqqsnd31nu1-EheWNobzu86ZqU,426 +oauthlib/openid/connect/core/grant_types/__pycache__/__init__.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/authorization_code.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/base.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/dispatchers.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/hybrid.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/implicit.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/__pycache__/refresh_token.cpython-310.pyc,, +oauthlib/openid/connect/core/grant_types/authorization_code.py,sha256=WOlS5RlSjIk2VNNmC5O4svxfTeUJiXpL3o5Mqn5EULk,1441 +oauthlib/openid/connect/core/grant_types/base.py,sha256=o0Nn_k6X0VB6m6iKpvlm-QMbtWcYzGagX6Uq2XaBS20,15385 +oauthlib/openid/connect/core/grant_types/dispatchers.py,sha256=RsIHHV8ne8fvlU1bL0jIUNb2pb2DbtJ1RYGV2_Z5GVQ,3978 +oauthlib/openid/connect/core/grant_types/hybrid.py,sha256=PHWBazxe3qpJq02rpU93jaK7URxI_r1zl0Ee4ibcaPA,2742 +oauthlib/openid/connect/core/grant_types/implicit.py,sha256=UICxnDNoePZfTUbL5QCBWA231o8XIQEnxocSrPp9gzw,1971 +oauthlib/openid/connect/core/grant_types/refresh_token.py,sha256=8X0i1EHLgBIrlqP10rwJ5lXWO3f8iupmfn2E6DlLmnw,1035 +oauthlib/openid/connect/core/request_validator.py,sha256=-lo1BnAhMWVkCj2Qhpn22LbV6CDmx4Nh4tCOntCg9tQ,13767 +oauthlib/openid/connect/core/tokens.py,sha256=j8WPb5T8SbmprFUJdM2DjafNU_fa1eohkjUeaJagn0s,1605 +oauthlib/signals.py,sha256=_PKDXWqKW6X3IbQUxGqW4eJ5Yi3p8jdOqXPAKfI956E,1489 +oauthlib/uri_validate.py,sha256=1LwAANg5vBjaypKgbDF_qrt_u7rJPlfg1hTrD9oanEU,6112 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..becc9a66ea739ba941d48a749e248761cc6e658a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5f3f0e3450f1ffb7a28cd40aed368a56254cacb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib-3.2.2.dist-info/top_level.txt @@ -0,0 +1 @@ +oauthlib diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d9a5e38ea0481dfbe34f1128e99ae98c8405a2f7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__init__.py @@ -0,0 +1,34 @@ +""" + oauthlib + ~~~~~~~~ + + A generic, spec-compliant, thorough implementation of the OAuth + request-signing logic. + + :copyright: (c) 2019 by The OAuthlib Community + :license: BSD, see LICENSE for details. +""" +import logging +from logging import NullHandler + +__author__ = 'The OAuthlib Community' +__version__ = '3.2.2' + +logging.getLogger('oauthlib').addHandler(NullHandler()) + +_DEBUG = False + +def set_debug(debug_val): + """Set value of debug flag + + :param debug_val: Value to set. Must be a bool value. + """ + global _DEBUG + _DEBUG = debug_val + +def get_debug(): + """Get debug mode value. + + :return: `True` if debug mode is on, `False` otherwise + """ + return _DEBUG diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ef23fb30c3bdfe1adf4d5e55c67a89c125ba74e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/common.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/common.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..450b73d0332add1dddfca0da7119160fd0d540b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/common.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/signals.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/signals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02fb6008a92f8dcf1dd033eb3815862e28594e0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/signals.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/uri_validate.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/uri_validate.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4246c0be7c9cb3b5c34ece13960afb0ee5a1500c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/__pycache__/uri_validate.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/common.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/common.py new file mode 100644 index 0000000000000000000000000000000000000000..395e75efc9d908bc3ac416949408d39e371f05cb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/common.py @@ -0,0 +1,432 @@ +""" +oauthlib.common +~~~~~~~~~~~~~~ + +This module provides data structures and utilities common +to all implementations of OAuth. +""" +import collections +import datetime +import logging +import re +import time +import urllib.parse as urlparse +from urllib.parse import ( + quote as _quote, unquote as _unquote, urlencode as _urlencode, +) + +from . import get_debug + +try: + from secrets import SystemRandom, randbits +except ImportError: + from random import SystemRandom, getrandbits as randbits + +UNICODE_ASCII_CHARACTER_SET = ('abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789') + +CLIENT_ID_CHARACTER_SET = (r' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMN' + 'OPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}') + +SANITIZE_PATTERN = re.compile(r'([^&;]*(?:password|token)[^=]*=)[^&;]+', re.IGNORECASE) +INVALID_HEX_PATTERN = re.compile(r'%[^0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]') + +always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789' '_.-') + +log = logging.getLogger('oauthlib') + + +# 'safe' must be bytes (Python 2.6 requires bytes, other versions allow either) +def quote(s, safe=b'/'): + s = s.encode('utf-8') if isinstance(s, str) else s + s = _quote(s, safe) + # PY3 always returns unicode. PY2 may return either, depending on whether + # it had to modify the string. + if isinstance(s, bytes): + s = s.decode('utf-8') + return s + + +def unquote(s): + s = _unquote(s) + # PY3 always returns unicode. PY2 seems to always return what you give it, + # which differs from quote's behavior. Just to be safe, make sure it is + # unicode before we return. + if isinstance(s, bytes): + s = s.decode('utf-8') + return s + + +def urlencode(params): + utf8_params = encode_params_utf8(params) + urlencoded = _urlencode(utf8_params) + if isinstance(urlencoded, str): + return urlencoded + else: + return urlencoded.decode("utf-8") + + +def encode_params_utf8(params): + """Ensures that all parameters in a list of 2-element tuples are encoded to + bytestrings using UTF-8 + """ + encoded = [] + for k, v in params: + encoded.append(( + k.encode('utf-8') if isinstance(k, str) else k, + v.encode('utf-8') if isinstance(v, str) else v)) + return encoded + + +def decode_params_utf8(params): + """Ensures that all parameters in a list of 2-element tuples are decoded to + unicode using UTF-8. + """ + decoded = [] + for k, v in params: + decoded.append(( + k.decode('utf-8') if isinstance(k, bytes) else k, + v.decode('utf-8') if isinstance(v, bytes) else v)) + return decoded + + +urlencoded = set(always_safe) | set('=&;:%+~,*@!()/?\'$') + + +def urldecode(query): + """Decode a query string in x-www-form-urlencoded format into a sequence + of two-element tuples. + + Unlike urlparse.parse_qsl(..., strict_parsing=True) urldecode will enforce + correct formatting of the query string by validation. If validation fails + a ValueError will be raised. urllib.parse_qsl will only raise errors if + any of name-value pairs omits the equals sign. + """ + # Check if query contains invalid characters + if query and not set(query) <= urlencoded: + error = ("Error trying to decode a non urlencoded string. " + "Found invalid characters: %s " + "in the string: '%s'. " + "Please ensure the request/response body is " + "x-www-form-urlencoded.") + raise ValueError(error % (set(query) - urlencoded, query)) + + # Check for correctly hex encoded values using a regular expression + # All encoded values begin with % followed by two hex characters + # correct = %00, %A0, %0A, %FF + # invalid = %G0, %5H, %PO + if INVALID_HEX_PATTERN.search(query): + raise ValueError('Invalid hex encoding in query string.') + + # We want to allow queries such as "c2" whereas urlparse.parse_qsl + # with the strict_parsing flag will not. + params = urlparse.parse_qsl(query, keep_blank_values=True) + + # unicode all the things + return decode_params_utf8(params) + + +def extract_params(raw): + """Extract parameters and return them as a list of 2-tuples. + + Will successfully extract parameters from urlencoded query strings, + dicts, or lists of 2-tuples. Empty strings/dicts/lists will return an + empty list of parameters. Any other input will result in a return + value of None. + """ + if isinstance(raw, (bytes, str)): + try: + params = urldecode(raw) + except ValueError: + params = None + elif hasattr(raw, '__iter__'): + try: + dict(raw) + except ValueError: + params = None + except TypeError: + params = None + else: + params = list(raw.items() if isinstance(raw, dict) else raw) + params = decode_params_utf8(params) + else: + params = None + + return params + + +def generate_nonce(): + """Generate pseudorandom nonce that is unlikely to repeat. + + Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. + Per `section 3.2.1`_ of the MAC Access Authentication spec. + + A random 64-bit number is appended to the epoch timestamp for both + randomness and to decrease the likelihood of collisions. + + .. _`section 3.2.1`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 + .. _`section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3 + """ + return str(str(randbits(64)) + generate_timestamp()) + + +def generate_timestamp(): + """Get seconds since epoch (UTC). + + Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. + Per `section 3.2.1`_ of the MAC Access Authentication spec. + + .. _`section 3.2.1`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 + .. _`section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3 + """ + return str(int(time.time())) + + +def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): + """Generates a non-guessable OAuth token + + OAuth (1 and 2) does not specify the format of tokens except that they + should be strings of random characters. Tokens should not be guessable + and entropy when generating the random characters is important. Which is + why SystemRandom is used instead of the default random.choice method. + """ + rand = SystemRandom() + return ''.join(rand.choice(chars) for x in range(length)) + + +def generate_signed_token(private_pem, request): + import jwt + + now = datetime.datetime.utcnow() + + claims = { + 'scope': request.scope, + 'exp': now + datetime.timedelta(seconds=request.expires_in) + } + + claims.update(request.claims) + + token = jwt.encode(claims, private_pem, 'RS256') + token = to_unicode(token, "UTF-8") + + return token + + +def verify_signed_token(public_pem, token): + import jwt + + return jwt.decode(token, public_pem, algorithms=['RS256']) + + +def generate_client_id(length=30, chars=CLIENT_ID_CHARACTER_SET): + """Generates an OAuth client_id + + OAuth 2 specify the format of client_id in + https://tools.ietf.org/html/rfc6749#appendix-A. + """ + return generate_token(length, chars) + + +def add_params_to_qs(query, params): + """Extend a query with a list of two-tuples.""" + if isinstance(params, dict): + params = params.items() + queryparams = urlparse.parse_qsl(query, keep_blank_values=True) + queryparams.extend(params) + return urlencode(queryparams) + + +def add_params_to_uri(uri, params, fragment=False): + """Add a list of two-tuples to the uri query components.""" + sch, net, path, par, query, fra = urlparse.urlparse(uri) + if fragment: + fra = add_params_to_qs(fra, params) + else: + query = add_params_to_qs(query, params) + return urlparse.urlunparse((sch, net, path, par, query, fra)) + + +def safe_string_equals(a, b): + """ Near-constant time string comparison. + + Used in order to avoid timing attacks on sensitive information such + as secret keys during request verification (`rootLabs`_). + + .. _`rootLabs`: http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ + + """ + if len(a) != len(b): + return False + + result = 0 + for x, y in zip(a, b): + result |= ord(x) ^ ord(y) + return result == 0 + + +def to_unicode(data, encoding='UTF-8'): + """Convert a number of different types of objects to unicode.""" + if isinstance(data, str): + return data + + if isinstance(data, bytes): + return str(data, encoding=encoding) + + if hasattr(data, '__iter__'): + try: + dict(data) + except TypeError: + pass + except ValueError: + # Assume it's a one dimensional data structure + return (to_unicode(i, encoding) for i in data) + else: + # We support 2.6 which lacks dict comprehensions + if hasattr(data, 'items'): + data = data.items() + return {to_unicode(k, encoding): to_unicode(v, encoding) for k, v in data} + + return data + + +class CaseInsensitiveDict(dict): + + """Basic case insensitive dict with strings only keys.""" + + proxy = {} + + def __init__(self, data): + self.proxy = {k.lower(): k for k in data} + for k in data: + self[k] = data[k] + + def __contains__(self, k): + return k.lower() in self.proxy + + def __delitem__(self, k): + key = self.proxy[k.lower()] + super().__delitem__(key) + del self.proxy[k.lower()] + + def __getitem__(self, k): + key = self.proxy[k.lower()] + return super().__getitem__(key) + + def get(self, k, default=None): + return self[k] if k in self else default + + def __setitem__(self, k, v): + super().__setitem__(k, v) + self.proxy[k.lower()] = k + + def update(self, *args, **kwargs): + super().update(*args, **kwargs) + for k in dict(*args, **kwargs): + self.proxy[k.lower()] = k + + +class Request: + + """A malleable representation of a signable HTTP request. + + Body argument may contain any data, but parameters will only be decoded if + they are one of: + + * urlencoded query string + * dict + * list of 2-tuples + + Anything else will be treated as raw body data to be passed through + unmolested. + """ + + def __init__(self, uri, http_method='GET', body=None, headers=None, + encoding='utf-8'): + # Convert to unicode using encoding if given, else assume unicode + encode = lambda x: to_unicode(x, encoding) if encoding else x + + self.uri = encode(uri) + self.http_method = encode(http_method) + self.headers = CaseInsensitiveDict(encode(headers or {})) + self.body = encode(body) + self.decoded_body = extract_params(self.body) + self.oauth_params = [] + self.validator_log = {} + + self._params = { + "access_token": None, + "client": None, + "client_id": None, + "client_secret": None, + "code": None, + "code_challenge": None, + "code_challenge_method": None, + "code_verifier": None, + "extra_credentials": None, + "grant_type": None, + "redirect_uri": None, + "refresh_token": None, + "request_token": None, + "response_type": None, + "scope": None, + "scopes": None, + "state": None, + "token": None, + "user": None, + "token_type_hint": None, + + # OpenID Connect + "response_mode": None, + "nonce": None, + "display": None, + "prompt": None, + "claims": None, + "max_age": None, + "ui_locales": None, + "id_token_hint": None, + "login_hint": None, + "acr_values": None + } + self._params.update(dict(urldecode(self.uri_query))) + self._params.update(dict(self.decoded_body or [])) + + def __getattr__(self, name): + if name in self._params: + return self._params[name] + else: + raise AttributeError(name) + + def __repr__(self): + if not get_debug(): + return "<oauthlib.Request SANITIZED>" + body = self.body + headers = self.headers.copy() + if body: + body = SANITIZE_PATTERN.sub('\1<SANITIZED>', str(body)) + if 'Authorization' in headers: + headers['Authorization'] = '<SANITIZED>' + return '<oauthlib.Request url="{}", http_method="{}", headers="{}", body="{}">'.format( + self.uri, self.http_method, headers, body) + + @property + def uri_query(self): + return urlparse.urlparse(self.uri).query + + @property + def uri_query_params(self): + if not self.uri_query: + return [] + return urlparse.parse_qsl(self.uri_query, keep_blank_values=True, + strict_parsing=True) + + @property + def duplicate_params(self): + seen_keys = collections.defaultdict(int) + all_keys = (p[0] + for p in (self.decoded_body or []) + self.uri_query_params) + for k in all_keys: + seen_keys[k] += 1 + return [k for k, c in seen_keys.items() if c > 1] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9caf12a90d878efa4460811310818ee3572fcdd4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__init__.py @@ -0,0 +1,23 @@ +""" +oauthlib.oauth1 +~~~~~~~~~~~~~~ + +This module is a wrapper for the most recent implementation of OAuth 1.0 Client +and Server classes. +""" +from .rfc5849 import ( + SIGNATURE_HMAC, SIGNATURE_HMAC_SHA1, SIGNATURE_HMAC_SHA256, + SIGNATURE_HMAC_SHA512, SIGNATURE_PLAINTEXT, SIGNATURE_RSA, + SIGNATURE_RSA_SHA1, SIGNATURE_RSA_SHA256, SIGNATURE_RSA_SHA512, + SIGNATURE_TYPE_AUTH_HEADER, SIGNATURE_TYPE_BODY, SIGNATURE_TYPE_QUERY, + Client, +) +from .rfc5849.endpoints import ( + AccessTokenEndpoint, AuthorizationEndpoint, RequestTokenEndpoint, + ResourceEndpoint, SignatureOnlyEndpoint, WebApplicationServer, +) +from .rfc5849.errors import ( + InsecureTransportError, InvalidClientError, InvalidRequestError, + InvalidSignatureMethodError, OAuth1Error, +) +from .rfc5849.request_validator import RequestValidator diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63624892aae6d40c61c4180599adb07b74aba294 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c559251fedab0a72fc959a8cb856605c20831e55 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__init__.py @@ -0,0 +1,365 @@ +""" +oauthlib.oauth1.rfc5849 +~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 1.0 RFC 5849 requests. + +It supports all three standard signature methods defined in RFC 5849: + +- HMAC-SHA1 +- RSA-SHA1 +- PLAINTEXT + +It also supports signature methods that are not defined in RFC 5849. These are +based on the standard ones but replace SHA-1 with the more secure SHA-256: + +- HMAC-SHA256 +- RSA-SHA256 + +""" +import base64 +import hashlib +import logging +import urllib.parse as urlparse + +from oauthlib.common import ( + Request, generate_nonce, generate_timestamp, to_unicode, urlencode, +) + +from . import parameters, signature + +log = logging.getLogger(__name__) + +# Available signature methods +# +# Note: SIGNATURE_HMAC and SIGNATURE_RSA are kept for backward compatibility +# with previous versions of this library, when it the only HMAC-based and +# RSA-based signature methods were HMAC-SHA1 and RSA-SHA1. But now that it +# supports other hashing algorithms besides SHA1, explicitly identifying which +# hashing algorithm is being used is recommended. +# +# Note: if additional values are defined here, don't forget to update the +# imports in "../__init__.py" so they are available outside this module. + +SIGNATURE_HMAC_SHA1 = "HMAC-SHA1" +SIGNATURE_HMAC_SHA256 = "HMAC-SHA256" +SIGNATURE_HMAC_SHA512 = "HMAC-SHA512" +SIGNATURE_HMAC = SIGNATURE_HMAC_SHA1 # deprecated variable for HMAC-SHA1 + +SIGNATURE_RSA_SHA1 = "RSA-SHA1" +SIGNATURE_RSA_SHA256 = "RSA-SHA256" +SIGNATURE_RSA_SHA512 = "RSA-SHA512" +SIGNATURE_RSA = SIGNATURE_RSA_SHA1 # deprecated variable for RSA-SHA1 + +SIGNATURE_PLAINTEXT = "PLAINTEXT" + +SIGNATURE_METHODS = ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_HMAC_SHA256, + SIGNATURE_HMAC_SHA512, + SIGNATURE_RSA_SHA1, + SIGNATURE_RSA_SHA256, + SIGNATURE_RSA_SHA512, + SIGNATURE_PLAINTEXT +) + +SIGNATURE_TYPE_AUTH_HEADER = 'AUTH_HEADER' +SIGNATURE_TYPE_QUERY = 'QUERY' +SIGNATURE_TYPE_BODY = 'BODY' + +CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' + + +class Client: + + """A client used to sign OAuth 1.0 RFC 5849 requests.""" + SIGNATURE_METHODS = { + SIGNATURE_HMAC_SHA1: signature.sign_hmac_sha1_with_client, + SIGNATURE_HMAC_SHA256: signature.sign_hmac_sha256_with_client, + SIGNATURE_HMAC_SHA512: signature.sign_hmac_sha512_with_client, + SIGNATURE_RSA_SHA1: signature.sign_rsa_sha1_with_client, + SIGNATURE_RSA_SHA256: signature.sign_rsa_sha256_with_client, + SIGNATURE_RSA_SHA512: signature.sign_rsa_sha512_with_client, + SIGNATURE_PLAINTEXT: signature.sign_plaintext_with_client + } + + @classmethod + def register_signature_method(cls, method_name, method_callback): + cls.SIGNATURE_METHODS[method_name] = method_callback + + def __init__(self, client_key, + client_secret=None, + resource_owner_key=None, + resource_owner_secret=None, + callback_uri=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_AUTH_HEADER, + rsa_key=None, verifier=None, realm=None, + encoding='utf-8', decoding=None, + nonce=None, timestamp=None): + """Create an OAuth 1 client. + + :param client_key: Client key (consumer key), mandatory. + :param resource_owner_key: Resource owner key (oauth token). + :param resource_owner_secret: Resource owner secret (oauth token secret). + :param callback_uri: Callback used when obtaining request token. + :param signature_method: SIGNATURE_HMAC, SIGNATURE_RSA or SIGNATURE_PLAINTEXT. + :param signature_type: SIGNATURE_TYPE_AUTH_HEADER (default), + SIGNATURE_TYPE_QUERY or SIGNATURE_TYPE_BODY + depending on where you want to embed the oauth + credentials. + :param rsa_key: RSA key used with SIGNATURE_RSA. + :param verifier: Verifier used when obtaining an access token. + :param realm: Realm (scope) to which access is being requested. + :param encoding: If you provide non-unicode input you may use this + to have oauthlib automatically convert. + :param decoding: If you wish that the returned uri, headers and body + from sign be encoded back from unicode, then set + decoding to your preferred encoding, i.e. utf-8. + :param nonce: Use this nonce instead of generating one. (Mainly for testing) + :param timestamp: Use this timestamp instead of using current. (Mainly for testing) + """ + # Convert to unicode using encoding if given, else assume unicode + encode = lambda x: to_unicode(x, encoding) if encoding else x + + self.client_key = encode(client_key) + self.client_secret = encode(client_secret) + self.resource_owner_key = encode(resource_owner_key) + self.resource_owner_secret = encode(resource_owner_secret) + self.signature_method = encode(signature_method) + self.signature_type = encode(signature_type) + self.callback_uri = encode(callback_uri) + self.rsa_key = encode(rsa_key) + self.verifier = encode(verifier) + self.realm = encode(realm) + self.encoding = encode(encoding) + self.decoding = encode(decoding) + self.nonce = encode(nonce) + self.timestamp = encode(timestamp) + + def __repr__(self): + attrs = vars(self).copy() + attrs['client_secret'] = '****' if attrs['client_secret'] else None + attrs['rsa_key'] = '****' if attrs['rsa_key'] else None + attrs[ + 'resource_owner_secret'] = '****' if attrs['resource_owner_secret'] else None + attribute_str = ', '.join('{}={}'.format(k, v) for k, v in attrs.items()) + return '<{} {}>'.format(self.__class__.__name__, attribute_str) + + def get_oauth_signature(self, request): + """Get an OAuth signature to be used in signing a request + + To satisfy `section 3.4.1.2`_ item 2, if the request argument's + headers dict attribute contains a Host item, its value will + replace any netloc part of the request argument's uri attribute + value. + + .. _`section 3.4.1.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + """ + if self.signature_method == SIGNATURE_PLAINTEXT: + # fast-path + return signature.sign_plaintext(self.client_secret, + self.resource_owner_secret) + + uri, headers, body = self._render(request) + + collected_params = signature.collect_parameters( + uri_query=urlparse.urlparse(uri).query, + body=body, + headers=headers) + log.debug("Collected params: {}".format(collected_params)) + + normalized_params = signature.normalize_parameters(collected_params) + normalized_uri = signature.base_string_uri(uri, headers.get('Host', None)) + log.debug("Normalized params: {}".format(normalized_params)) + log.debug("Normalized URI: {}".format(normalized_uri)) + + base_string = signature.signature_base_string(request.http_method, + normalized_uri, normalized_params) + + log.debug("Signing: signature base string: {}".format(base_string)) + + if self.signature_method not in self.SIGNATURE_METHODS: + raise ValueError('Invalid signature method.') + + sig = self.SIGNATURE_METHODS[self.signature_method](base_string, self) + + log.debug("Signature: {}".format(sig)) + return sig + + def get_oauth_params(self, request): + """Get the basic OAuth parameters to be used in generating a signature. + """ + nonce = (generate_nonce() + if self.nonce is None else self.nonce) + timestamp = (generate_timestamp() + if self.timestamp is None else self.timestamp) + params = [ + ('oauth_nonce', nonce), + ('oauth_timestamp', timestamp), + ('oauth_version', '1.0'), + ('oauth_signature_method', self.signature_method), + ('oauth_consumer_key', self.client_key), + ] + if self.resource_owner_key: + params.append(('oauth_token', self.resource_owner_key)) + if self.callback_uri: + params.append(('oauth_callback', self.callback_uri)) + if self.verifier: + params.append(('oauth_verifier', self.verifier)) + + # providing body hash for requests other than x-www-form-urlencoded + # as described in https://tools.ietf.org/html/draft-eaton-oauth-bodyhash-00#section-4.1.1 + # 4.1.1. When to include the body hash + # * [...] MUST NOT include an oauth_body_hash parameter on requests with form-encoded request bodies + # * [...] SHOULD include the oauth_body_hash parameter on all other requests. + # Note that SHA-1 is vulnerable. The spec acknowledges that in https://tools.ietf.org/html/draft-eaton-oauth-bodyhash-00#section-6.2 + # At this time, no further effort has been made to replace SHA-1 for the OAuth Request Body Hash extension. + content_type = request.headers.get('Content-Type', None) + content_type_eligible = content_type and content_type.find('application/x-www-form-urlencoded') < 0 + if request.body is not None and content_type_eligible: + params.append(('oauth_body_hash', base64.b64encode(hashlib.sha1(request.body.encode('utf-8')).digest()).decode('utf-8'))) + + return params + + def _render(self, request, formencode=False, realm=None): + """Render a signed request according to signature type + + Returns a 3-tuple containing the request URI, headers, and body. + + If the formencode argument is True and the body contains parameters, it + is escaped and returned as a valid formencoded string. + """ + # TODO what if there are body params on a header-type auth? + # TODO what if there are query params on a body-type auth? + + uri, headers, body = request.uri, request.headers, request.body + + # TODO: right now these prepare_* methods are very narrow in scope--they + # only affect their little thing. In some cases (for example, with + # header auth) it might be advantageous to allow these methods to touch + # other parts of the request, like the headers—so the prepare_headers + # method could also set the Content-Type header to x-www-form-urlencoded + # like the spec requires. This would be a fundamental change though, and + # I'm not sure how I feel about it. + if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER: + headers = parameters.prepare_headers( + request.oauth_params, request.headers, realm=realm) + elif self.signature_type == SIGNATURE_TYPE_BODY and request.decoded_body is not None: + body = parameters.prepare_form_encoded_body( + request.oauth_params, request.decoded_body) + if formencode: + body = urlencode(body) + headers['Content-Type'] = 'application/x-www-form-urlencoded' + elif self.signature_type == SIGNATURE_TYPE_QUERY: + uri = parameters.prepare_request_uri_query( + request.oauth_params, request.uri) + else: + raise ValueError('Unknown signature type specified.') + + return uri, headers, body + + def sign(self, uri, http_method='GET', body=None, headers=None, realm=None): + """Sign a request + + Signs an HTTP request with the specified parts. + + Returns a 3-tuple of the signed request's URI, headers, and body. + Note that http_method is not returned as it is unaffected by the OAuth + signing process. Also worth noting is that duplicate parameters + will be included in the signature, regardless of where they are + specified (query, body). + + The body argument may be a dict, a list of 2-tuples, or a formencoded + string. The Content-Type header must be 'application/x-www-form-urlencoded' + if it is present. + + If the body argument is not one of the above, it will be returned + verbatim as it is unaffected by the OAuth signing process. Attempting to + sign a request with non-formencoded data using the OAuth body signature + type is invalid and will raise an exception. + + If the body does contain parameters, it will be returned as a properly- + formatted formencoded string. + + Body may not be included if the http_method is either GET or HEAD as + this changes the semantic meaning of the request. + + All string data MUST be unicode or be encoded with the same encoding + scheme supplied to the Client constructor, default utf-8. This includes + strings inside body dicts, for example. + """ + # normalize request data + request = Request(uri, http_method, body, headers, + encoding=self.encoding) + + # sanity check + content_type = request.headers.get('Content-Type', None) + multipart = content_type and content_type.startswith('multipart/') + should_have_params = content_type == CONTENT_TYPE_FORM_URLENCODED + has_params = request.decoded_body is not None + # 3.4.1.3.1. Parameter Sources + # [Parameters are collected from the HTTP request entity-body, but only + # if [...]: + # * The entity-body is single-part. + if multipart and has_params: + raise ValueError( + "Headers indicate a multipart body but body contains parameters.") + # * The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # [W3C.REC-html40-19980424]. + elif should_have_params and not has_params: + raise ValueError( + "Headers indicate a formencoded body but body was not decodable.") + # * The HTTP request entity-header includes the "Content-Type" + # header field set to "application/x-www-form-urlencoded". + elif not should_have_params and has_params: + raise ValueError( + "Body contains parameters but Content-Type header was {} " + "instead of {}".format(content_type or "not set", + CONTENT_TYPE_FORM_URLENCODED)) + + # 3.5.2. Form-Encoded Body + # Protocol parameters can be transmitted in the HTTP request entity- + # body, but only if the following REQUIRED conditions are met: + # o The entity-body is single-part. + # o The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # [W3C.REC-html40-19980424]. + # o The HTTP request entity-header includes the "Content-Type" header + # field set to "application/x-www-form-urlencoded". + elif self.signature_type == SIGNATURE_TYPE_BODY and not ( + should_have_params and has_params and not multipart): + raise ValueError( + 'Body signatures may only be used with form-urlencoded content') + + # We amend https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1 + # with the clause that parameters from body should only be included + # in non GET or HEAD requests. Extracting the request body parameters + # and including them in the signature base string would give semantic + # meaning to the body, which it should not have according to the + # HTTP 1.1 spec. + elif http_method.upper() in ('GET', 'HEAD') and has_params: + raise ValueError('GET/HEAD requests should not include body.') + + # generate the basic OAuth parameters + request.oauth_params = self.get_oauth_params(request) + + # generate the signature + request.oauth_params.append( + ('oauth_signature', self.get_oauth_signature(request))) + + # render the signed request and return it + uri, headers, body = self._render(request, formencode=True, + realm=(realm or self.realm)) + + if self.decoding: + log.debug('Encoding URI, headers and body to %s.', self.decoding) + uri = uri.encode(self.decoding) + body = body.encode(self.decoding) if body else body + new_headers = {} + for k, v in headers.items(): + new_headers[k.encode(self.decoding)] = v.encode(self.decoding) + headers = new_headers + return uri, headers, body diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a9b20f6807db1a3247005c513728f5983675e5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/errors.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/errors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfa7c2f2de2da7c21087d8fb61c25a7dc1e9ff4b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/errors.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/parameters.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/parameters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96d927e4f60d74938c18398df16f54b3116d4d5e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/parameters.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/request_validator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/request_validator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45d9513ac526ca67d7d5754c0ec65d9335a14c58 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/request_validator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/signature.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/signature.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df0b67997a4dae858fae67c4784650429e7ec925 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/signature.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d65724757b8961f8dfe5cea1421ac16a8f05535 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9f30389f239929754078e3f59688de418d986e29 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py @@ -0,0 +1,8 @@ +from .access_token import AccessTokenEndpoint +from .authorization import AuthorizationEndpoint +from .base import BaseEndpoint +from .request_token import RequestTokenEndpoint +from .resource import ResourceEndpoint +from .signature_only import SignatureOnlyEndpoint + +from .pre_configured import WebApplicationServer # isort:skip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a9c56071b41afaa4b1f4ca5db31fad36b10a418 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/access_token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/access_token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5dd6a9a8feb70667b6d6db74283608c3e5926145 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/access_token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/authorization.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/authorization.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34c3d51ef91568bc2664abffd6f88585d1399b27 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/authorization.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7d68cf0da738db721b1dd706eb8d624b24a40c9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/pre_configured.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/pre_configured.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d4da632f19023a6ba9c5554126fc0ba4dce7cea Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/pre_configured.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/request_token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/request_token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19272b7db85548d04b04f5d2e9783fd5963cb2ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/request_token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/resource.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/resource.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78e953f0498efafab01b0b4a61ba854fbe93b204 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/resource.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/signature_only.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/signature_only.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93808b6a3c5145f23b3c0b9fc53f971fbd6b4b09 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/__pycache__/signature_only.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py new file mode 100644 index 0000000000000000000000000000000000000000..13665db08fda810cfc46fa45448d06fe9ec99ae9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py @@ -0,0 +1,215 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.access_token +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of the access token provider logic of +OAuth 1.0 RFC 5849. It validates the correctness of access token requests, +creates and persists tokens as well as create the proper response to be +returned to the client. +""" +import logging + +from oauthlib.common import urlencode + +from .. import errors +from .base import BaseEndpoint + +log = logging.getLogger(__name__) + + +class AccessTokenEndpoint(BaseEndpoint): + + """An endpoint responsible for providing OAuth 1 access tokens. + + Typical use is to instantiate with a request validator and invoke the + ``create_access_token_response`` from a view function. The tuple returned + has all information necessary (body, status, headers) to quickly form + and return a proper response. See :doc:`/oauth1/validator` for details on which + validator methods to implement for this endpoint. + """ + + def create_access_token(self, request, credentials): + """Create and save a new access token. + + Similar to OAuth 2, indication of granted scopes will be included as a + space separated list in ``oauth_authorized_realms``. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The token as an urlencoded string. + """ + request.realms = self.request_validator.get_realms( + request.resource_owner_key, request) + token = { + 'oauth_token': self.token_generator(), + 'oauth_token_secret': self.token_generator(), + # Backport the authorized scopes indication used in OAuth2 + 'oauth_authorized_realms': ' '.join(request.realms) + } + token.update(credentials) + self.request_validator.save_access_token(token, request) + return urlencode(token.items()) + + def create_access_token_response(self, uri, http_method='GET', body=None, + headers=None, credentials=None): + """Create an access token response, with a new request token if valid. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :param credentials: A list of extra credentials to include in the token. + :returns: A tuple of 3 elements. + 1. A dict of headers to set on the response. + 2. The response body as a string. + 3. The response status code as an integer. + + An example of a valid request:: + + >>> from your_validator import your_validator + >>> from oauthlib.oauth1 import AccessTokenEndpoint + >>> endpoint = AccessTokenEndpoint(your_validator) + >>> h, b, s = endpoint.create_access_token_response( + ... 'https://your.provider/access_token?foo=bar', + ... headers={ + ... 'Authorization': 'OAuth oauth_token=234lsdkf....' + ... }, + ... credentials={ + ... 'my_specific': 'argument', + ... }) + >>> h + {'Content-Type': 'application/x-www-form-urlencoded'} + >>> b + 'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_authorized_realms=movies+pics&my_specific=argument' + >>> s + 200 + + An response to invalid request would have a different body and status:: + + >>> b + 'error=invalid_request&description=missing+resource+owner+key' + >>> s + 400 + + The same goes for an an unauthorized request: + + >>> b + '' + >>> s + 401 + """ + resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'} + try: + request = self._create_request(uri, http_method, body, headers) + valid, processed_request = self.validate_access_token_request( + request) + if valid: + token = self.create_access_token(request, credentials or {}) + self.request_validator.invalidate_request_token( + request.client_key, + request.resource_owner_key, + request) + return resp_headers, token, 200 + else: + return {}, None, 401 + except errors.OAuth1Error as e: + return resp_headers, e.urlencoded, e.status_code + + def validate_access_token_request(self, request): + """Validate an access token request. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :raises: OAuth1Error if the request is invalid. + :returns: A tuple of 2 elements. + 1. The validation result (True or False). + 2. The request object. + """ + self._check_transport_security(request) + self._check_mandatory_parameters(request) + + if not request.resource_owner_key: + raise errors.InvalidRequestError( + description='Missing resource owner.') + + if not self.request_validator.check_request_token( + request.resource_owner_key): + raise errors.InvalidRequestError( + description='Invalid resource owner key format.') + + if not request.verifier: + raise errors.InvalidRequestError( + description='Missing verifier.') + + if not self.request_validator.check_verifier(request.verifier): + raise errors.InvalidRequestError( + description='Invalid verifier format.') + + if not self.request_validator.validate_timestamp_and_nonce( + request.client_key, request.timestamp, request.nonce, request, + request_token=request.resource_owner_key): + return False, request + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid client credentials. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy client is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable client enumeration + valid_client = self.request_validator.validate_client_key( + request.client_key, request) + if not valid_client: + request.client_key = self.request_validator.dummy_client + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid or expired token. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy token is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable resource owner enumeration + valid_resource_owner = self.request_validator.validate_request_token( + request.client_key, request.resource_owner_key, request) + if not valid_resource_owner: + request.resource_owner_key = self.request_validator.dummy_request_token + + # The server MUST verify (Section 3.2) the validity of the request, + # ensure that the resource owner has authorized the provisioning of + # token credentials to the client, and ensure that the temporary + # credentials have not expired or been used before. The server MUST + # also verify the verification code received from the client. + # .. _`Section 3.2`: https://tools.ietf.org/html/rfc5849#section-3.2 + # + # Note that early exit would enable resource owner authorization + # verifier enumertion. + valid_verifier = self.request_validator.validate_verifier( + request.client_key, + request.resource_owner_key, + request.verifier, + request) + + valid_signature = self._check_signature(request, is_token_request=True) + + # log the results to the validator_log + # this lets us handle internal reporting and analysis + request.validator_log['client'] = valid_client + request.validator_log['resource_owner'] = valid_resource_owner + request.validator_log['verifier'] = valid_verifier + request.validator_log['signature'] = valid_signature + + # We delay checking validity until the very end, using dummy values for + # calculations and fetching secrets/keys to ensure the flow of every + # request remains almost identical regardless of whether valid values + # have been supplied. This ensures near constant time execution and + # prevents malicious users from guessing sensitive information + v = all((valid_client, valid_resource_owner, valid_verifier, + valid_signature)) + if not v: + log.info("[Failure] request verification failed.") + log.info("Valid client:, %s", valid_client) + log.info("Valid token:, %s", valid_resource_owner) + log.info("Valid verifier:, %s", valid_verifier) + log.info("Valid signature:, %s", valid_signature) + return v, request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py new file mode 100644 index 0000000000000000000000000000000000000000..00d9576b01ecd9879a4485cf083c2affa79a520c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.authorization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 1.0 RFC 5849 requests. +""" +from urllib.parse import urlencode + +from oauthlib.common import add_params_to_uri + +from .. import errors +from .base import BaseEndpoint + + +class AuthorizationEndpoint(BaseEndpoint): + + """An endpoint responsible for letting authenticated users authorize access + to their protected resources to a client. + + Typical use would be to have two views, one for displaying the authorization + form and one to process said form on submission. + + The first view will want to utilize ``get_realms_and_credentials`` to fetch + requested realms and useful client credentials, such as name and + description, to be used when creating the authorization form. + + During form processing you can use ``create_authorization_response`` to + validate the request, create a verifier as well as prepare the final + redirection URI used to send the user back to the client. + + See :doc:`/oauth1/validator` for details on which validator methods to implement + for this endpoint. + """ + + def create_verifier(self, request, credentials): + """Create and save a new request token. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param credentials: A dict of extra token credentials. + :returns: The verifier as a dict. + """ + verifier = { + 'oauth_token': request.resource_owner_key, + 'oauth_verifier': self.token_generator(), + } + verifier.update(credentials) + self.request_validator.save_verifier( + request.resource_owner_key, verifier, request) + return verifier + + def create_authorization_response(self, uri, http_method='GET', body=None, + headers=None, realms=None, credentials=None): + """Create an authorization response, with a new request token if valid. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :param credentials: A list of credentials to include in the verifier. + :returns: A tuple of 3 elements. + 1. A dict of headers to set on the response. + 2. The response body as a string. + 3. The response status code as an integer. + + If the callback URI tied to the current token is "oob", a response with + a 200 status code will be returned. In this case, it may be desirable to + modify the response to better display the verifier to the client. + + An example of an authorization request:: + + >>> from your_validator import your_validator + >>> from oauthlib.oauth1 import AuthorizationEndpoint + >>> endpoint = AuthorizationEndpoint(your_validator) + >>> h, b, s = endpoint.create_authorization_response( + ... 'https://your.provider/authorize?oauth_token=...', + ... credentials={ + ... 'extra': 'argument', + ... }) + >>> h + {'Location': 'https://the.client/callback?oauth_verifier=...&extra=argument'} + >>> b + None + >>> s + 302 + + An example of a request with an "oob" callback:: + + >>> from your_validator import your_validator + >>> from oauthlib.oauth1 import AuthorizationEndpoint + >>> endpoint = AuthorizationEndpoint(your_validator) + >>> h, b, s = endpoint.create_authorization_response( + ... 'https://your.provider/authorize?foo=bar', + ... credentials={ + ... 'extra': 'argument', + ... }) + >>> h + {'Content-Type': 'application/x-www-form-urlencoded'} + >>> b + 'oauth_verifier=...&extra=argument' + >>> s + 200 + """ + request = self._create_request(uri, http_method=http_method, body=body, + headers=headers) + + if not request.resource_owner_key: + raise errors.InvalidRequestError( + 'Missing mandatory parameter oauth_token.') + if not self.request_validator.verify_request_token( + request.resource_owner_key, request): + raise errors.InvalidClientError() + + request.realms = realms + if (request.realms and not self.request_validator.verify_realms( + request.resource_owner_key, request.realms, request)): + raise errors.InvalidRequestError( + description=('User granted access to realms outside of ' + 'what the client may request.')) + + verifier = self.create_verifier(request, credentials or {}) + redirect_uri = self.request_validator.get_redirect_uri( + request.resource_owner_key, request) + if redirect_uri == 'oob': + response_headers = { + 'Content-Type': 'application/x-www-form-urlencoded'} + response_body = urlencode(verifier) + return response_headers, response_body, 200 + else: + populated_redirect = add_params_to_uri( + redirect_uri, verifier.items()) + return {'Location': populated_redirect}, None, 302 + + def get_realms_and_credentials(self, uri, http_method='GET', body=None, + headers=None): + """Fetch realms and credentials for the presented request token. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :returns: A tuple of 2 elements. + 1. A list of request realms. + 2. A dict of credentials which may be useful in creating the + authorization form. + """ + request = self._create_request(uri, http_method=http_method, body=body, + headers=headers) + + if not self.request_validator.verify_request_token( + request.resource_owner_key, request): + raise errors.InvalidClientError() + + realms = self.request_validator.get_realms( + request.resource_owner_key, request) + return realms, {'resource_owner_key': request.resource_owner_key} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py new file mode 100644 index 0000000000000000000000000000000000000000..7831be7c5e1cc47c2a4551dbd35df43adf96ad04 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py @@ -0,0 +1,244 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.base +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 1.0 RFC 5849 requests. +""" +import time + +from oauthlib.common import CaseInsensitiveDict, Request, generate_token + +from .. import ( + CONTENT_TYPE_FORM_URLENCODED, SIGNATURE_HMAC_SHA1, SIGNATURE_HMAC_SHA256, + SIGNATURE_HMAC_SHA512, SIGNATURE_PLAINTEXT, SIGNATURE_RSA_SHA1, + SIGNATURE_RSA_SHA256, SIGNATURE_RSA_SHA512, SIGNATURE_TYPE_AUTH_HEADER, + SIGNATURE_TYPE_BODY, SIGNATURE_TYPE_QUERY, errors, signature, utils, +) + + +class BaseEndpoint: + + def __init__(self, request_validator, token_generator=None): + self.request_validator = request_validator + self.token_generator = token_generator or generate_token + + def _get_signature_type_and_params(self, request): + """Extracts parameters from query, headers and body. Signature type + is set to the source in which parameters were found. + """ + # Per RFC5849, only the Authorization header may contain the 'realm' + # optional parameter. + header_params = signature.collect_parameters(headers=request.headers, + exclude_oauth_signature=False, with_realm=True) + body_params = signature.collect_parameters(body=request.body, + exclude_oauth_signature=False) + query_params = signature.collect_parameters(uri_query=request.uri_query, + exclude_oauth_signature=False) + + params = [] + params.extend(header_params) + params.extend(body_params) + params.extend(query_params) + signature_types_with_oauth_params = list(filter(lambda s: s[2], ( + (SIGNATURE_TYPE_AUTH_HEADER, params, + utils.filter_oauth_params(header_params)), + (SIGNATURE_TYPE_BODY, params, + utils.filter_oauth_params(body_params)), + (SIGNATURE_TYPE_QUERY, params, + utils.filter_oauth_params(query_params)) + ))) + + if len(signature_types_with_oauth_params) > 1: + found_types = [s[0] for s in signature_types_with_oauth_params] + raise errors.InvalidRequestError( + description=('oauth_ params must come from only 1 signature' + 'type but were found in %s', + ', '.join(found_types))) + + try: + signature_type, params, oauth_params = signature_types_with_oauth_params[ + 0] + except IndexError: + raise errors.InvalidRequestError( + description='Missing mandatory OAuth parameters.') + + return signature_type, params, oauth_params + + def _create_request(self, uri, http_method, body, headers): + # Only include body data from x-www-form-urlencoded requests + headers = CaseInsensitiveDict(headers or {}) + if ("Content-Type" in headers and + CONTENT_TYPE_FORM_URLENCODED in headers["Content-Type"]): + request = Request(uri, http_method, body, headers) + else: + request = Request(uri, http_method, '', headers) + + signature_type, params, oauth_params = ( + self._get_signature_type_and_params(request)) + + # The server SHOULD return a 400 (Bad Request) status code when + # receiving a request with duplicated protocol parameters. + if len(dict(oauth_params)) != len(oauth_params): + raise errors.InvalidRequestError( + description='Duplicate OAuth1 entries.') + + oauth_params = dict(oauth_params) + request.signature = oauth_params.get('oauth_signature') + request.client_key = oauth_params.get('oauth_consumer_key') + request.resource_owner_key = oauth_params.get('oauth_token') + request.nonce = oauth_params.get('oauth_nonce') + request.timestamp = oauth_params.get('oauth_timestamp') + request.redirect_uri = oauth_params.get('oauth_callback') + request.verifier = oauth_params.get('oauth_verifier') + request.signature_method = oauth_params.get('oauth_signature_method') + request.realm = dict(params).get('realm') + request.oauth_params = oauth_params + + # Parameters to Client depend on signature method which may vary + # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters + request.params = [(k, v) for k, v in params if k != "oauth_signature"] + + if 'realm' in request.headers.get('Authorization', ''): + request.params = [(k, v) + for k, v in request.params if k != "realm"] + + return request + + def _check_transport_security(self, request): + # TODO: move into oauthlib.common from oauth2.utils + if (self.request_validator.enforce_ssl and + not request.uri.lower().startswith("https://")): + raise errors.InsecureTransportError() + + def _check_mandatory_parameters(self, request): + # The server SHOULD return a 400 (Bad Request) status code when + # receiving a request with missing parameters. + if not all((request.signature, request.client_key, + request.nonce, request.timestamp, + request.signature_method)): + raise errors.InvalidRequestError( + description='Missing mandatory OAuth parameters.') + + # OAuth does not mandate a particular signature method, as each + # implementation can have its own unique requirements. Servers are + # free to implement and document their own custom methods. + # Recommending any particular method is beyond the scope of this + # specification. Implementers should review the Security + # Considerations section (`Section 4`_) before deciding on which + # method to support. + # .. _`Section 4`: https://tools.ietf.org/html/rfc5849#section-4 + if (not request.signature_method in + self.request_validator.allowed_signature_methods): + raise errors.InvalidSignatureMethodError( + description="Invalid signature, {} not in {!r}.".format( + request.signature_method, + self.request_validator.allowed_signature_methods)) + + # Servers receiving an authenticated request MUST validate it by: + # If the "oauth_version" parameter is present, ensuring its value is + # "1.0". + if ('oauth_version' in request.oauth_params and + request.oauth_params['oauth_version'] != '1.0'): + raise errors.InvalidRequestError( + description='Invalid OAuth version.') + + # The timestamp value MUST be a positive integer. Unless otherwise + # specified by the server's documentation, the timestamp is expressed + # in the number of seconds since January 1, 1970 00:00:00 GMT. + if len(request.timestamp) != 10: + raise errors.InvalidRequestError( + description='Invalid timestamp size') + + try: + ts = int(request.timestamp) + + except ValueError: + raise errors.InvalidRequestError( + description='Timestamp must be an integer.') + + else: + # To avoid the need to retain an infinite number of nonce values for + # future checks, servers MAY choose to restrict the time period after + # which a request with an old timestamp is rejected. + if abs(time.time() - ts) > self.request_validator.timestamp_lifetime: + raise errors.InvalidRequestError( + description=('Timestamp given is invalid, differ from ' + 'allowed by over %s seconds.' % ( + self.request_validator.timestamp_lifetime))) + + # Provider specific validation of parameters, used to enforce + # restrictions such as character set and length. + if not self.request_validator.check_client_key(request.client_key): + raise errors.InvalidRequestError( + description='Invalid client key format.') + + if not self.request_validator.check_nonce(request.nonce): + raise errors.InvalidRequestError( + description='Invalid nonce format.') + + def _check_signature(self, request, is_token_request=False): + # ---- RSA Signature verification ---- + if request.signature_method == SIGNATURE_RSA_SHA1 or \ + request.signature_method == SIGNATURE_RSA_SHA256 or \ + request.signature_method == SIGNATURE_RSA_SHA512: + # RSA-based signature method + + # The server verifies the signature per `[RFC3447] section 8.2.2`_ + # .. _`[RFC3447] section 8.2.2`: https://tools.ietf.org/html/rfc3447#section-8.2.1 + + rsa_key = self.request_validator.get_rsa_key( + request.client_key, request) + + if request.signature_method == SIGNATURE_RSA_SHA1: + valid_signature = signature.verify_rsa_sha1(request, rsa_key) + elif request.signature_method == SIGNATURE_RSA_SHA256: + valid_signature = signature.verify_rsa_sha256(request, rsa_key) + elif request.signature_method == SIGNATURE_RSA_SHA512: + valid_signature = signature.verify_rsa_sha512(request, rsa_key) + else: + valid_signature = False + + # ---- HMAC or Plaintext Signature verification ---- + else: + # Non-RSA based signature method + + # Servers receiving an authenticated request MUST validate it by: + # Recalculating the request signature independently as described in + # `Section 3.4`_ and comparing it to the value received from the + # client via the "oauth_signature" parameter. + # .. _`Section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4 + + client_secret = self.request_validator.get_client_secret( + request.client_key, request) + + resource_owner_secret = None + if request.resource_owner_key: + if is_token_request: + resource_owner_secret = \ + self.request_validator.get_request_token_secret( + request.client_key, request.resource_owner_key, + request) + else: + resource_owner_secret = \ + self.request_validator.get_access_token_secret( + request.client_key, request.resource_owner_key, + request) + + if request.signature_method == SIGNATURE_HMAC_SHA1: + valid_signature = signature.verify_hmac_sha1( + request, client_secret, resource_owner_secret) + elif request.signature_method == SIGNATURE_HMAC_SHA256: + valid_signature = signature.verify_hmac_sha256( + request, client_secret, resource_owner_secret) + elif request.signature_method == SIGNATURE_HMAC_SHA512: + valid_signature = signature.verify_hmac_sha512( + request, client_secret, resource_owner_secret) + elif request.signature_method == SIGNATURE_PLAINTEXT: + valid_signature = signature.verify_plaintext( + request, client_secret, resource_owner_secret) + else: + valid_signature = False + + return valid_signature diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py new file mode 100644 index 0000000000000000000000000000000000000000..23e3cfc84e0ee61cd461f476c435ef318945ff66 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py @@ -0,0 +1,14 @@ +from . import ( + AccessTokenEndpoint, AuthorizationEndpoint, RequestTokenEndpoint, + ResourceEndpoint, +) + + +class WebApplicationServer(RequestTokenEndpoint, AuthorizationEndpoint, + AccessTokenEndpoint, ResourceEndpoint): + + def __init__(self, request_validator): + RequestTokenEndpoint.__init__(self, request_validator) + AuthorizationEndpoint.__init__(self, request_validator) + AccessTokenEndpoint.__init__(self, request_validator) + ResourceEndpoint.__init__(self, request_validator) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py new file mode 100644 index 0000000000000000000000000000000000000000..0323cfb845a7836eab0e181cc9229031788e957e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.request_token +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of the request token provider logic of +OAuth 1.0 RFC 5849. It validates the correctness of request token requests, +creates and persists tokens as well as create the proper response to be +returned to the client. +""" +import logging + +from oauthlib.common import urlencode + +from .. import errors +from .base import BaseEndpoint + +log = logging.getLogger(__name__) + + +class RequestTokenEndpoint(BaseEndpoint): + + """An endpoint responsible for providing OAuth 1 request tokens. + + Typical use is to instantiate with a request validator and invoke the + ``create_request_token_response`` from a view function. The tuple returned + has all information necessary (body, status, headers) to quickly form + and return a proper response. See :doc:`/oauth1/validator` for details on which + validator methods to implement for this endpoint. + """ + + def create_request_token(self, request, credentials): + """Create and save a new request token. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param credentials: A dict of extra token credentials. + :returns: The token as an urlencoded string. + """ + token = { + 'oauth_token': self.token_generator(), + 'oauth_token_secret': self.token_generator(), + 'oauth_callback_confirmed': 'true' + } + token.update(credentials) + self.request_validator.save_request_token(token, request) + return urlencode(token.items()) + + def create_request_token_response(self, uri, http_method='GET', body=None, + headers=None, credentials=None): + """Create a request token response, with a new request token if valid. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :param credentials: A list of extra credentials to include in the token. + :returns: A tuple of 3 elements. + 1. A dict of headers to set on the response. + 2. The response body as a string. + 3. The response status code as an integer. + + An example of a valid request:: + + >>> from your_validator import your_validator + >>> from oauthlib.oauth1 import RequestTokenEndpoint + >>> endpoint = RequestTokenEndpoint(your_validator) + >>> h, b, s = endpoint.create_request_token_response( + ... 'https://your.provider/request_token?foo=bar', + ... headers={ + ... 'Authorization': 'OAuth realm=movies user, oauth_....' + ... }, + ... credentials={ + ... 'my_specific': 'argument', + ... }) + >>> h + {'Content-Type': 'application/x-www-form-urlencoded'} + >>> b + 'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_callback_confirmed=true&my_specific=argument' + >>> s + 200 + + An response to invalid request would have a different body and status:: + + >>> b + 'error=invalid_request&description=missing+callback+uri' + >>> s + 400 + + The same goes for an an unauthorized request: + + >>> b + '' + >>> s + 401 + """ + resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'} + try: + request = self._create_request(uri, http_method, body, headers) + valid, processed_request = self.validate_request_token_request( + request) + if valid: + token = self.create_request_token(request, credentials or {}) + return resp_headers, token, 200 + else: + return {}, None, 401 + except errors.OAuth1Error as e: + return resp_headers, e.urlencoded, e.status_code + + def validate_request_token_request(self, request): + """Validate a request token request. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :raises: OAuth1Error if the request is invalid. + :returns: A tuple of 2 elements. + 1. The validation result (True or False). + 2. The request object. + """ + self._check_transport_security(request) + self._check_mandatory_parameters(request) + + if request.realm: + request.realms = request.realm.split(' ') + else: + request.realms = self.request_validator.get_default_realms( + request.client_key, request) + if not self.request_validator.check_realms(request.realms): + raise errors.InvalidRequestError( + description='Invalid realm {}. Allowed are {!r}.'.format( + request.realms, self.request_validator.realms)) + + if not request.redirect_uri: + raise errors.InvalidRequestError( + description='Missing callback URI.') + + if not self.request_validator.validate_timestamp_and_nonce( + request.client_key, request.timestamp, request.nonce, request, + request_token=request.resource_owner_key): + return False, request + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid client credentials. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy client is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable client enumeration + valid_client = self.request_validator.validate_client_key( + request.client_key, request) + if not valid_client: + request.client_key = self.request_validator.dummy_client + + # Note that `realm`_ is only used in authorization headers and how + # it should be interpreted is not included in the OAuth spec. + # However they could be seen as a scope or realm to which the + # client has access and as such every client should be checked + # to ensure it is authorized access to that scope or realm. + # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2 + # + # Note that early exit would enable client realm access enumeration. + # + # The require_realm indicates this is the first step in the OAuth + # workflow where a client requests access to a specific realm. + # This first step (obtaining request token) need not require a realm + # and can then be identified by checking the require_resource_owner + # flag and absence of realm. + # + # Clients obtaining an access token will not supply a realm and it will + # not be checked. Instead the previously requested realm should be + # transferred from the request token to the access token. + # + # Access to protected resources will always validate the realm but note + # that the realm is now tied to the access token and not provided by + # the client. + valid_realm = self.request_validator.validate_requested_realms( + request.client_key, request.realms, request) + + # Callback is normally never required, except for requests for + # a Temporary Credential as described in `Section 2.1`_ + # .._`Section 2.1`: https://tools.ietf.org/html/rfc5849#section-2.1 + valid_redirect = self.request_validator.validate_redirect_uri( + request.client_key, request.redirect_uri, request) + if not request.redirect_uri: + raise NotImplementedError('Redirect URI must either be provided ' + 'or set to a default during validation.') + + valid_signature = self._check_signature(request) + + # log the results to the validator_log + # this lets us handle internal reporting and analysis + request.validator_log['client'] = valid_client + request.validator_log['realm'] = valid_realm + request.validator_log['callback'] = valid_redirect + request.validator_log['signature'] = valid_signature + + # We delay checking validity until the very end, using dummy values for + # calculations and fetching secrets/keys to ensure the flow of every + # request remains almost identical regardless of whether valid values + # have been supplied. This ensures near constant time execution and + # prevents malicious users from guessing sensitive information + v = all((valid_client, valid_realm, valid_redirect, valid_signature)) + if not v: + log.info("[Failure] request verification failed.") + log.info("Valid client: %s.", valid_client) + log.info("Valid realm: %s.", valid_realm) + log.info("Valid callback: %s.", valid_redirect) + log.info("Valid signature: %s.", valid_signature) + return v, request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py new file mode 100644 index 0000000000000000000000000000000000000000..8641152e4ee765c889ab608080ae3c6aee3e58e8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.resource +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of the resource protection provider logic of +OAuth 1.0 RFC 5849. +""" +import logging + +from .. import errors +from .base import BaseEndpoint + +log = logging.getLogger(__name__) + + +class ResourceEndpoint(BaseEndpoint): + + """An endpoint responsible for protecting resources. + + Typical use is to instantiate with a request validator and invoke the + ``validate_protected_resource_request`` in a decorator around a view + function. If the request is valid, invoke and return the response of the + view. If invalid create and return an error response directly from the + decorator. + + See :doc:`/oauth1/validator` for details on which validator methods to implement + for this endpoint. + + An example decorator:: + + from functools import wraps + from your_validator import your_validator + from oauthlib.oauth1 import ResourceEndpoint + endpoint = ResourceEndpoint(your_validator) + + def require_oauth(realms=None): + def decorator(f): + @wraps(f) + def wrapper(request, *args, **kwargs): + v, r = provider.validate_protected_resource_request( + request.url, + http_method=request.method, + body=request.data, + headers=request.headers, + realms=realms or []) + if v: + return f(*args, **kwargs) + else: + return abort(403) + """ + + def validate_protected_resource_request(self, uri, http_method='GET', + body=None, headers=None, realms=None): + """Create a request token response, with a new request token if valid. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :param realms: A list of realms the resource is protected under. + This will be supplied to the ``validate_realms`` + method of the request validator. + :returns: A tuple of 2 elements. + 1. True if valid, False otherwise. + 2. An oauthlib.common.Request object. + """ + try: + request = self._create_request(uri, http_method, body, headers) + except errors.OAuth1Error: + return False, None + + try: + self._check_transport_security(request) + self._check_mandatory_parameters(request) + except errors.OAuth1Error: + return False, request + + if not request.resource_owner_key: + return False, request + + if not self.request_validator.check_access_token( + request.resource_owner_key): + return False, request + + if not self.request_validator.validate_timestamp_and_nonce( + request.client_key, request.timestamp, request.nonce, request, + access_token=request.resource_owner_key): + return False, request + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid client credentials. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy client is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable client enumeration + valid_client = self.request_validator.validate_client_key( + request.client_key, request) + if not valid_client: + request.client_key = self.request_validator.dummy_client + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid or expired token. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy token is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable resource owner enumeration + valid_resource_owner = self.request_validator.validate_access_token( + request.client_key, request.resource_owner_key, request) + if not valid_resource_owner: + request.resource_owner_key = self.request_validator.dummy_access_token + + # Note that `realm`_ is only used in authorization headers and how + # it should be interpreted is not included in the OAuth spec. + # However they could be seen as a scope or realm to which the + # client has access and as such every client should be checked + # to ensure it is authorized access to that scope or realm. + # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2 + # + # Note that early exit would enable client realm access enumeration. + # + # The require_realm indicates this is the first step in the OAuth + # workflow where a client requests access to a specific realm. + # This first step (obtaining request token) need not require a realm + # and can then be identified by checking the require_resource_owner + # flag and absence of realm. + # + # Clients obtaining an access token will not supply a realm and it will + # not be checked. Instead the previously requested realm should be + # transferred from the request token to the access token. + # + # Access to protected resources will always validate the realm but note + # that the realm is now tied to the access token and not provided by + # the client. + valid_realm = self.request_validator.validate_realms(request.client_key, + request.resource_owner_key, request, uri=request.uri, + realms=realms) + + valid_signature = self._check_signature(request) + + # log the results to the validator_log + # this lets us handle internal reporting and analysis + request.validator_log['client'] = valid_client + request.validator_log['resource_owner'] = valid_resource_owner + request.validator_log['realm'] = valid_realm + request.validator_log['signature'] = valid_signature + + # We delay checking validity until the very end, using dummy values for + # calculations and fetching secrets/keys to ensure the flow of every + # request remains almost identical regardless of whether valid values + # have been supplied. This ensures near constant time execution and + # prevents malicious users from guessing sensitive information + v = all((valid_client, valid_resource_owner, valid_realm, + valid_signature)) + if not v: + log.info("[Failure] request verification failed.") + log.info("Valid client: %s", valid_client) + log.info("Valid token: %s", valid_resource_owner) + log.info("Valid realm: %s", valid_realm) + log.info("Valid signature: %s", valid_signature) + return v, request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py new file mode 100644 index 0000000000000000000000000000000000000000..d693ccb7f6bf368754223f822a143dc81b8232df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth1.rfc5849.endpoints.signature_only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of the signing logic of OAuth 1.0 RFC 5849. +""" + +import logging + +from .. import errors +from .base import BaseEndpoint + +log = logging.getLogger(__name__) + + +class SignatureOnlyEndpoint(BaseEndpoint): + + """An endpoint only responsible for verifying an oauth signature.""" + + def validate_request(self, uri, http_method='GET', + body=None, headers=None): + """Validate a signed OAuth request. + + :param uri: The full URI of the token request. + :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. + :param body: The request body as a string. + :param headers: The request headers as a dict. + :returns: A tuple of 2 elements. + 1. True if valid, False otherwise. + 2. An oauthlib.common.Request object. + """ + try: + request = self._create_request(uri, http_method, body, headers) + except errors.OAuth1Error as err: + log.info( + 'Exception caught while validating request, %s.' % err) + return False, None + + try: + self._check_transport_security(request) + self._check_mandatory_parameters(request) + except errors.OAuth1Error as err: + log.info( + 'Exception caught while validating request, %s.' % err) + return False, request + + if not self.request_validator.validate_timestamp_and_nonce( + request.client_key, request.timestamp, request.nonce, request): + log.debug('[Failure] verification failed: timestamp/nonce') + return False, request + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid client credentials. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy client is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable client enumeration + valid_client = self.request_validator.validate_client_key( + request.client_key, request) + if not valid_client: + request.client_key = self.request_validator.dummy_client + + valid_signature = self._check_signature(request) + + # log the results to the validator_log + # this lets us handle internal reporting and analysis + request.validator_log['client'] = valid_client + request.validator_log['signature'] = valid_signature + + # We delay checking validity until the very end, using dummy values for + # calculations and fetching secrets/keys to ensure the flow of every + # request remains almost identical regardless of whether valid values + # have been supplied. This ensures near constant time execution and + # prevents malicious users from guessing sensitive information + v = all((valid_client, valid_signature)) + if not v: + log.info("[Failure] request verification failed.") + log.info("Valid client: %s", valid_client) + log.info("Valid signature: %s", valid_signature) + return v, request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/errors.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/errors.py new file mode 100644 index 0000000000000000000000000000000000000000..8774d40741b4b26a3721be545c66513505aaa8d1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/errors.py @@ -0,0 +1,76 @@ +""" +oauthlib.oauth1.rfc5849.errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Error used both by OAuth 1 clients and provicers to represent the spec +defined error responses for all four core grant types. +""" +from oauthlib.common import add_params_to_uri, urlencode + + +class OAuth1Error(Exception): + error = None + description = '' + + def __init__(self, description=None, uri=None, status_code=400, + request=None): + """ + description: A human-readable ASCII [USASCII] text providing + additional information, used to assist the client + developer in understanding the error that occurred. + Values for the "error_description" parameter MUST NOT + include characters outside the set + x20-21 / x23-5B / x5D-7E. + + uri: A URI identifying a human-readable web page with information + about the error, used to provide the client developer with + additional information about the error. Values for the + "error_uri" parameter MUST conform to the URI- Reference + syntax, and thus MUST NOT include characters outside the set + x21 / x23-5B / x5D-7E. + + state: A CSRF protection value received from the client. + + request: Oauthlib Request object + """ + self.description = description or self.description + message = '({}) {}'.format(self.error, self.description) + if request: + message += ' ' + repr(request) + super().__init__(message) + + self.uri = uri + self.status_code = status_code + + def in_uri(self, uri): + return add_params_to_uri(uri, self.twotuples) + + @property + def twotuples(self): + error = [('error', self.error)] + if self.description: + error.append(('error_description', self.description)) + if self.uri: + error.append(('error_uri', self.uri)) + return error + + @property + def urlencoded(self): + return urlencode(self.twotuples) + + +class InsecureTransportError(OAuth1Error): + error = 'insecure_transport_protocol' + description = 'Only HTTPS connections are permitted.' + + +class InvalidSignatureMethodError(OAuth1Error): + error = 'invalid_signature_method' + + +class InvalidRequestError(OAuth1Error): + error = 'invalid_request' + + +class InvalidClientError(OAuth1Error): + error = 'invalid_client' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/parameters.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/parameters.py new file mode 100644 index 0000000000000000000000000000000000000000..2163772df3c7f53d539fa8cb0b73cc0e547614f2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/parameters.py @@ -0,0 +1,133 @@ +""" +oauthlib.parameters +~~~~~~~~~~~~~~~~~~~ + +This module contains methods related to `section 3.5`_ of the OAuth 1.0a spec. + +.. _`section 3.5`: https://tools.ietf.org/html/rfc5849#section-3.5 +""" +from urllib.parse import urlparse, urlunparse + +from oauthlib.common import extract_params, urlencode + +from . import utils + + +# TODO: do we need filter_params now that oauth_params are handled by Request? +# We can easily pass in just oauth protocol params. +@utils.filter_params +def prepare_headers(oauth_params, headers=None, realm=None): + """**Prepare the Authorization header.** + Per `section 3.5.1`_ of the spec. + + Protocol parameters can be transmitted using the HTTP "Authorization" + header field as defined by `RFC2617`_ with the auth-scheme name set to + "OAuth" (case insensitive). + + For example:: + + Authorization: OAuth realm="Example", + oauth_consumer_key="0685bd9184jfhq22", + oauth_token="ad180jjd733klru7", + oauth_signature_method="HMAC-SHA1", + oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", + oauth_timestamp="137131200", + oauth_nonce="4572616e48616d6d65724c61686176", + oauth_version="1.0" + + + .. _`section 3.5.1`: https://tools.ietf.org/html/rfc5849#section-3.5.1 + .. _`RFC2617`: https://tools.ietf.org/html/rfc2617 + """ + headers = headers or {} + + # Protocol parameters SHALL be included in the "Authorization" header + # field as follows: + authorization_header_parameters_parts = [] + for oauth_parameter_name, value in oauth_params: + # 1. Parameter names and values are encoded per Parameter Encoding + # (`Section 3.6`_) + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + escaped_name = utils.escape(oauth_parameter_name) + escaped_value = utils.escape(value) + + # 2. Each parameter's name is immediately followed by an "=" character + # (ASCII code 61), a """ character (ASCII code 34), the parameter + # value (MAY be empty), and another """ character (ASCII code 34). + part = '{}="{}"'.format(escaped_name, escaped_value) + + authorization_header_parameters_parts.append(part) + + # 3. Parameters are separated by a "," character (ASCII code 44) and + # OPTIONAL linear whitespace per `RFC2617`_. + # + # .. _`RFC2617`: https://tools.ietf.org/html/rfc2617 + authorization_header_parameters = ', '.join( + authorization_header_parameters_parts) + + # 4. The OPTIONAL "realm" parameter MAY be added and interpreted per + # `RFC2617 section 1.2`_. + # + # .. _`RFC2617 section 1.2`: https://tools.ietf.org/html/rfc2617#section-1.2 + if realm: + # NOTE: realm should *not* be escaped + authorization_header_parameters = ('realm="%s", ' % realm + + authorization_header_parameters) + + # the auth-scheme name set to "OAuth" (case insensitive). + authorization_header = 'OAuth %s' % authorization_header_parameters + + # contribute the Authorization header to the given headers + full_headers = {} + full_headers.update(headers) + full_headers['Authorization'] = authorization_header + return full_headers + + +def _append_params(oauth_params, params): + """Append OAuth params to an existing set of parameters. + + Both params and oauth_params is must be lists of 2-tuples. + + Per `section 3.5.2`_ and `3.5.3`_ of the spec. + + .. _`section 3.5.2`: https://tools.ietf.org/html/rfc5849#section-3.5.2 + .. _`3.5.3`: https://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + merged = list(params) + merged.extend(oauth_params) + # The request URI / entity-body MAY include other request-specific + # parameters, in which case, the protocol parameters SHOULD be appended + # following the request-specific parameters, properly separated by an "&" + # character (ASCII code 38) + merged.sort(key=lambda i: i[0].startswith('oauth_')) + return merged + + +def prepare_form_encoded_body(oauth_params, body): + """Prepare the Form-Encoded Body. + + Per `section 3.5.2`_ of the spec. + + .. _`section 3.5.2`: https://tools.ietf.org/html/rfc5849#section-3.5.2 + + """ + # append OAuth params to the existing body + return _append_params(oauth_params, body) + + +def prepare_request_uri_query(oauth_params, uri): + """Prepare the Request URI Query. + + Per `section 3.5.3`_ of the spec. + + .. _`section 3.5.3`: https://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + # append OAuth params to the existing set of query components + sch, net, path, par, query, fra = urlparse(uri) + query = urlencode( + _append_params(oauth_params, extract_params(query) or [])) + return urlunparse((sch, net, path, par, query, fra)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/request_validator.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/request_validator.py new file mode 100644 index 0000000000000000000000000000000000000000..e937aabf4082850d8e966e75530dde6ff0becb13 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/request_validator.py @@ -0,0 +1,849 @@ +""" +oauthlib.oauth1.rfc5849 +~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 1.0 RFC 5849 requests. +""" +from . import SIGNATURE_METHODS, utils + + +class RequestValidator: + + """A validator/datastore interaction base class for OAuth 1 providers. + + OAuth providers should inherit from RequestValidator and implement the + methods and properties outlined below. Further details are provided in the + documentation for each method and property. + + Methods used to check the format of input parameters. Common tests include + length, character set, membership, range or pattern. These tests are + referred to as `whitelisting or blacklisting`_. Whitelisting is better + but blacklisting can be useful to spot malicious activity. + The following have methods a default implementation: + + - check_client_key + - check_request_token + - check_access_token + - check_nonce + - check_verifier + - check_realms + + The methods above default to whitelist input parameters, checking that they + are alphanumerical and between a minimum and maximum length. Rather than + overloading the methods a few properties can be used to configure these + methods. + + * @safe_characters -> (character set) + * @client_key_length -> (min, max) + * @request_token_length -> (min, max) + * @access_token_length -> (min, max) + * @nonce_length -> (min, max) + * @verifier_length -> (min, max) + * @realms -> [list, of, realms] + + Methods used to validate/invalidate input parameters. These checks usually + hit either persistent or temporary storage such as databases or the + filesystem. See each methods documentation for detailed usage. + The following methods must be implemented: + + - validate_client_key + - validate_request_token + - validate_access_token + - validate_timestamp_and_nonce + - validate_redirect_uri + - validate_requested_realms + - validate_realms + - validate_verifier + - invalidate_request_token + + Methods used to retrieve sensitive information from storage. + The following methods must be implemented: + + - get_client_secret + - get_request_token_secret + - get_access_token_secret + - get_rsa_key + - get_realms + - get_default_realms + - get_redirect_uri + + Methods used to save credentials. + The following methods must be implemented: + + - save_request_token + - save_verifier + - save_access_token + + Methods used to verify input parameters. This methods are used during + authorizing request token by user (AuthorizationEndpoint), to check if + parameters are valid. During token authorization request is not signed, + thus 'validation' methods can not be used. The following methods must be + implemented: + + - verify_realms + - verify_request_token + + To prevent timing attacks it is necessary to not exit early even if the + client key or resource owner key is invalid. Instead dummy values should + be used during the remaining verification process. It is very important + that the dummy client and token are valid input parameters to the methods + get_client_secret, get_rsa_key and get_(access/request)_token_secret and + that the running time of those methods when given a dummy value remain + equivalent to the running time when given a valid client/resource owner. + The following properties must be implemented: + + * @dummy_client + * @dummy_request_token + * @dummy_access_token + + Example implementations have been provided, note that the database used is + a simple dictionary and serves only an illustrative purpose. Use whichever + database suits your project and how to access it is entirely up to you. + The methods are introduced in an order which should make understanding + their use more straightforward and as such it could be worth reading what + follows in chronological order. + + .. _`whitelisting or blacklisting`: https://www.schneier.com/blog/archives/2011/01/whitelisting_vs.html + """ + + def __init__(self): + pass + + @property + def allowed_signature_methods(self): + return SIGNATURE_METHODS + + @property + def safe_characters(self): + return set(utils.UNICODE_ASCII_CHARACTER_SET) + + @property + def client_key_length(self): + return 20, 30 + + @property + def request_token_length(self): + return 20, 30 + + @property + def access_token_length(self): + return 20, 30 + + @property + def timestamp_lifetime(self): + return 600 + + @property + def nonce_length(self): + return 20, 30 + + @property + def verifier_length(self): + return 20, 30 + + @property + def realms(self): + return [] + + @property + def enforce_ssl(self): + return True + + def check_client_key(self, client_key): + """Check that the client key only contains safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.client_key_length + return (set(client_key) <= self.safe_characters and + lower <= len(client_key) <= upper) + + def check_request_token(self, request_token): + """Checks that the request token contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.request_token_length + return (set(request_token) <= self.safe_characters and + lower <= len(request_token) <= upper) + + def check_access_token(self, request_token): + """Checks that the token contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.access_token_length + return (set(request_token) <= self.safe_characters and + lower <= len(request_token) <= upper) + + def check_nonce(self, nonce): + """Checks that the nonce only contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.nonce_length + return (set(nonce) <= self.safe_characters and + lower <= len(nonce) <= upper) + + def check_verifier(self, verifier): + """Checks that the verifier contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.verifier_length + return (set(verifier) <= self.safe_characters and + lower <= len(verifier) <= upper) + + def check_realms(self, realms): + """Check that the realm is one of a set allowed realms.""" + return all(r in self.realms for r in realms) + + def _subclass_must_implement(self, fn): + """ + Returns a NotImplementedError for a function that should be implemented. + :param fn: name of the function + """ + m = "Missing function implementation in {}: {}".format(type(self), fn) + return NotImplementedError(m) + + @property + def dummy_client(self): + """Dummy client used when an invalid client key is supplied. + + :returns: The dummy client key string. + + The dummy client should be associated with either a client secret, + a rsa key or both depending on which signature methods are supported. + Providers should make sure that + + get_client_secret(dummy_client) + get_rsa_key(dummy_client) + + return a valid secret or key for the dummy client. + + This method is used by + + * AccessTokenEndpoint + * RequestTokenEndpoint + * ResourceEndpoint + * SignatureOnlyEndpoint + """ + raise self._subclass_must_implement("dummy_client") + + @property + def dummy_request_token(self): + """Dummy request token used when an invalid token was supplied. + + :returns: The dummy request token string. + + The dummy request token should be associated with a request token + secret such that get_request_token_secret(.., dummy_request_token) + returns a valid secret. + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("dummy_request_token") + + @property + def dummy_access_token(self): + """Dummy access token used when an invalid token was supplied. + + :returns: The dummy access token string. + + The dummy access token should be associated with an access token + secret such that get_access_token_secret(.., dummy_access_token) + returns a valid secret. + + This method is used by + + * ResourceEndpoint + """ + raise self._subclass_must_implement("dummy_access_token") + + def get_client_secret(self, client_key, request): + """Retrieves the client secret associated with the client key. + + :param client_key: The client/consumer key. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The client secret as a string. + + This method must allow the use of a dummy client_key value. + Fetching the secret using the dummy key must take the same amount of + time as fetching a secret for a valid client:: + + # Unlikely to be near constant time as it uses two database + # lookups for a valid client, and only one for an invalid. + from your_datastore import ClientSecret + if ClientSecret.has(client_key): + return ClientSecret.get(client_key) + else: + return 'dummy' + + # Aim to mimic number of latency inducing operations no matter + # whether the client is valid or not. + from your_datastore import ClientSecret + return ClientSecret.get(client_key, 'dummy') + + Note that the returned key must be in plaintext. + + This method is used by + + * AccessTokenEndpoint + * RequestTokenEndpoint + * ResourceEndpoint + * SignatureOnlyEndpoint + """ + raise self._subclass_must_implement('get_client_secret') + + def get_request_token_secret(self, client_key, token, request): + """Retrieves the shared secret associated with the request token. + + :param client_key: The client/consumer key. + :param token: The request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The token secret as a string. + + This method must allow the use of a dummy values and the running time + must be roughly equivalent to that of the running time of valid values:: + + # Unlikely to be near constant time as it uses two database + # lookups for a valid client, and only one for an invalid. + from your_datastore import RequestTokenSecret + if RequestTokenSecret.has(client_key): + return RequestTokenSecret.get((client_key, request_token)) + else: + return 'dummy' + + # Aim to mimic number of latency inducing operations no matter + # whether the client is valid or not. + from your_datastore import RequestTokenSecret + return ClientSecret.get((client_key, request_token), 'dummy') + + Note that the returned key must be in plaintext. + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement('get_request_token_secret') + + def get_access_token_secret(self, client_key, token, request): + """Retrieves the shared secret associated with the access token. + + :param client_key: The client/consumer key. + :param token: The access token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The token secret as a string. + + This method must allow the use of a dummy values and the running time + must be roughly equivalent to that of the running time of valid values:: + + # Unlikely to be near constant time as it uses two database + # lookups for a valid client, and only one for an invalid. + from your_datastore import AccessTokenSecret + if AccessTokenSecret.has(client_key): + return AccessTokenSecret.get((client_key, request_token)) + else: + return 'dummy' + + # Aim to mimic number of latency inducing operations no matter + # whether the client is valid or not. + from your_datastore import AccessTokenSecret + return ClientSecret.get((client_key, request_token), 'dummy') + + Note that the returned key must be in plaintext. + + This method is used by + + * ResourceEndpoint + """ + raise self._subclass_must_implement("get_access_token_secret") + + def get_default_realms(self, client_key, request): + """Get the default realms for a client. + + :param client_key: The client/consumer key. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The list of default realms associated with the client. + + The list of default realms will be set during client registration and + is outside the scope of OAuthLib. + + This method is used by + + * RequestTokenEndpoint + """ + raise self._subclass_must_implement("get_default_realms") + + def get_realms(self, token, request): + """Get realms associated with a request token. + + :param token: The request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The list of realms associated with the request token. + + This method is used by + + * AuthorizationEndpoint + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("get_realms") + + def get_redirect_uri(self, token, request): + """Get the redirect URI associated with a request token. + + :param token: The request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The redirect URI associated with the request token. + + It may be desirable to return a custom URI if the redirect is set to "oob". + In this case, the user will be redirected to the returned URI and at that + endpoint the verifier can be displayed. + + This method is used by + + * AuthorizationEndpoint + """ + raise self._subclass_must_implement("get_redirect_uri") + + def get_rsa_key(self, client_key, request): + """Retrieves a previously stored client provided RSA key. + + :param client_key: The client/consumer key. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: The rsa public key as a string. + + This method must allow the use of a dummy client_key value. Fetching + the rsa key using the dummy key must take the same amount of time + as fetching a key for a valid client. The dummy key must also be of + the same bit length as client keys. + + Note that the key must be returned in plaintext. + + This method is used by + + * AccessTokenEndpoint + * RequestTokenEndpoint + * ResourceEndpoint + * SignatureOnlyEndpoint + """ + raise self._subclass_must_implement("get_rsa_key") + + def invalidate_request_token(self, client_key, request_token, request): + """Invalidates a used request token. + + :param client_key: The client/consumer key. + :param request_token: The request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: None + + Per `Section 2.3`_ of the spec: + + "The server MUST (...) ensure that the temporary + credentials have not expired or been used before." + + .. _`Section 2.3`: https://tools.ietf.org/html/rfc5849#section-2.3 + + This method should ensure that provided token won't validate anymore. + It can be simply removing RequestToken from storage or setting + specific flag that makes it invalid (note that such flag should be + also validated during request token validation). + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("invalidate_request_token") + + def validate_client_key(self, client_key, request): + """Validates that supplied client key is a registered and valid client. + + :param client_key: The client/consumer key. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + Note that if the dummy client is supplied it should validate in same + or nearly the same amount of time as a valid one. + + Ensure latency inducing tasks are mimiced even for dummy clients. + For example, use:: + + from your_datastore import Client + try: + return Client.exists(client_key, access_token) + except DoesNotExist: + return False + + Rather than:: + + from your_datastore import Client + if access_token == self.dummy_access_token: + return False + else: + return Client.exists(client_key, access_token) + + This method is used by + + * AccessTokenEndpoint + * RequestTokenEndpoint + * ResourceEndpoint + * SignatureOnlyEndpoint + """ + raise self._subclass_must_implement("validate_client_key") + + def validate_request_token(self, client_key, token, request): + """Validates that supplied request token is registered and valid. + + :param client_key: The client/consumer key. + :param token: The request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + Note that if the dummy request_token is supplied it should validate in + the same nearly the same amount of time as a valid one. + + Ensure latency inducing tasks are mimiced even for dummy clients. + For example, use:: + + from your_datastore import RequestToken + try: + return RequestToken.exists(client_key, access_token) + except DoesNotExist: + return False + + Rather than:: + + from your_datastore import RequestToken + if access_token == self.dummy_access_token: + return False + else: + return RequestToken.exists(client_key, access_token) + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("validate_request_token") + + def validate_access_token(self, client_key, token, request): + """Validates that supplied access token is registered and valid. + + :param client_key: The client/consumer key. + :param token: The access token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + Note that if the dummy access token is supplied it should validate in + the same or nearly the same amount of time as a valid one. + + Ensure latency inducing tasks are mimiced even for dummy clients. + For example, use:: + + from your_datastore import AccessToken + try: + return AccessToken.exists(client_key, access_token) + except DoesNotExist: + return False + + Rather than:: + + from your_datastore import AccessToken + if access_token == self.dummy_access_token: + return False + else: + return AccessToken.exists(client_key, access_token) + + This method is used by + + * ResourceEndpoint + """ + raise self._subclass_must_implement("validate_access_token") + + def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, + request, request_token=None, access_token=None): + """Validates that the nonce has not been used before. + + :param client_key: The client/consumer key. + :param timestamp: The ``oauth_timestamp`` parameter. + :param nonce: The ``oauth_nonce`` parameter. + :param request_token: Request token string, if any. + :param access_token: Access token string, if any. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + Per `Section 3.3`_ of the spec. + + "A nonce is a random string, uniquely generated by the client to allow + the server to verify that a request has never been made before and + helps prevent replay attacks when requests are made over a non-secure + channel. The nonce value MUST be unique across all requests with the + same timestamp, client credentials, and token combinations." + + .. _`Section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3 + + One of the first validation checks that will be made is for the validity + of the nonce and timestamp, which are associated with a client key and + possibly a token. If invalid then immediately fail the request + by returning False. If the nonce/timestamp pair has been used before and + you may just have detected a replay attack. Therefore it is an essential + part of OAuth security that you not allow nonce/timestamp reuse. + Note that this validation check is done before checking the validity of + the client and token.:: + + nonces_and_timestamps_database = [ + (u'foo', 1234567890, u'rannoMstrInghere', u'bar') + ] + + def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, + request_token=None, access_token=None): + + return ((client_key, timestamp, nonce, request_token or access_token) + not in self.nonces_and_timestamps_database) + + This method is used by + + * AccessTokenEndpoint + * RequestTokenEndpoint + * ResourceEndpoint + * SignatureOnlyEndpoint + """ + raise self._subclass_must_implement("validate_timestamp_and_nonce") + + def validate_redirect_uri(self, client_key, redirect_uri, request): + """Validates the client supplied redirection URI. + + :param client_key: The client/consumer key. + :param redirect_uri: The URI the client which to redirect back to after + authorization is successful. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + It is highly recommended that OAuth providers require their clients + to register all redirection URIs prior to using them in requests and + register them as absolute URIs. See `CWE-601`_ for more information + about open redirection attacks. + + By requiring registration of all redirection URIs it should be + straightforward for the provider to verify whether the supplied + redirect_uri is valid or not. + + Alternatively per `Section 2.1`_ of the spec: + + "If the client is unable to receive callbacks or a callback URI has + been established via other means, the parameter value MUST be set to + "oob" (case sensitive), to indicate an out-of-band configuration." + + .. _`CWE-601`: http://cwe.mitre.org/top25/index.html#CWE-601 + .. _`Section 2.1`: https://tools.ietf.org/html/rfc5849#section-2.1 + + This method is used by + + * RequestTokenEndpoint + """ + raise self._subclass_must_implement("validate_redirect_uri") + + def validate_requested_realms(self, client_key, realms, request): + """Validates that the client may request access to the realm. + + :param client_key: The client/consumer key. + :param realms: The list of realms that client is requesting access to. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + This method is invoked when obtaining a request token and should + tie a realm to the request token and after user authorization + this realm restriction should transfer to the access token. + + This method is used by + + * RequestTokenEndpoint + """ + raise self._subclass_must_implement("validate_requested_realms") + + def validate_realms(self, client_key, token, request, uri=None, + realms=None): + """Validates access to the request realm. + + :param client_key: The client/consumer key. + :param token: A request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param uri: The URI the realms is protecting. + :param realms: A list of realms that must have been granted to + the access token. + :returns: True or False + + How providers choose to use the realm parameter is outside the OAuth + specification but it is commonly used to restrict access to a subset + of protected resources such as "photos". + + realms is a convenience parameter which can be used to provide + a per view method pre-defined list of allowed realms. + + Can be as simple as:: + + from your_datastore import RequestToken + request_token = RequestToken.get(token, None) + + if not request_token: + return False + return set(request_token.realms).issuperset(set(realms)) + + This method is used by + + * ResourceEndpoint + """ + raise self._subclass_must_implement("validate_realms") + + def validate_verifier(self, client_key, token, verifier, request): + """Validates a verification code. + + :param client_key: The client/consumer key. + :param token: A request token string. + :param verifier: The authorization verifier string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + OAuth providers issue a verification code to clients after the + resource owner authorizes access. This code is used by the client to + obtain token credentials and the provider must verify that the + verifier is valid and associated with the client as well as the + resource owner. + + Verifier validation should be done in near constant time + (to avoid verifier enumeration). To achieve this we need a + constant time string comparison which is provided by OAuthLib + in ``oauthlib.common.safe_string_equals``:: + + from your_datastore import Verifier + correct_verifier = Verifier.get(client_key, request_token) + from oauthlib.common import safe_string_equals + return safe_string_equals(verifier, correct_verifier) + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("validate_verifier") + + def verify_request_token(self, token, request): + """Verify that the given OAuth1 request token is valid. + + :param token: A request token string. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + This method is used only in AuthorizationEndpoint to check whether the + oauth_token given in the authorization URL is valid or not. + This request is not signed and thus similar ``validate_request_token`` + method can not be used. + + This method is used by + + * AuthorizationEndpoint + """ + raise self._subclass_must_implement("verify_request_token") + + def verify_realms(self, token, realms, request): + """Verify authorized realms to see if they match those given to token. + + :param token: An access token string. + :param realms: A list of realms the client attempts to access. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :returns: True or False + + This prevents the list of authorized realms sent by the client during + the authorization step to be altered to include realms outside what + was bound with the request token. + + Can be as simple as:: + + valid_realms = self.get_realms(token) + return all((r in valid_realms for r in realms)) + + This method is used by + + * AuthorizationEndpoint + """ + raise self._subclass_must_implement("verify_realms") + + def save_access_token(self, token, request): + """Save an OAuth1 access token. + + :param token: A dict with token credentials. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + The token dictionary will at minimum include + + * ``oauth_token`` the access token string. + * ``oauth_token_secret`` the token specific secret used in signing. + * ``oauth_authorized_realms`` a space separated list of realms. + + Client key can be obtained from ``request.client_key``. + + The list of realms (not joined string) can be obtained from + ``request.realm``. + + This method is used by + + * AccessTokenEndpoint + """ + raise self._subclass_must_implement("save_access_token") + + def save_request_token(self, token, request): + """Save an OAuth1 request token. + + :param token: A dict with token credentials. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + The token dictionary will at minimum include + + * ``oauth_token`` the request token string. + * ``oauth_token_secret`` the token specific secret used in signing. + * ``oauth_callback_confirmed`` the string ``true``. + + Client key can be obtained from ``request.client_key``. + + This method is used by + + * RequestTokenEndpoint + """ + raise self._subclass_must_implement("save_request_token") + + def save_verifier(self, token, verifier, request): + """Associate an authorization verifier with a request token. + + :param token: A request token string. + :param verifier: A dictionary containing the oauth_verifier and + oauth_token + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + We need to associate verifiers with tokens for validation during the + access token request. + + Note that unlike save_x_token token here is the ``oauth_token`` token + string from the request token saved previously. + + This method is used by + + * AuthorizationEndpoint + """ + raise self._subclass_must_implement("save_verifier") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/signature.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/signature.py new file mode 100644 index 0000000000000000000000000000000000000000..9cb1a517ee8545c7648471d11c87da437bf1b968 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/signature.py @@ -0,0 +1,852 @@ +""" +This module is an implementation of `section 3.4`_ of RFC 5849. + +**Usage** + +Steps for signing a request: + +1. Collect parameters from the request using ``collect_parameters``. +2. Normalize those parameters using ``normalize_parameters``. +3. Create the *base string URI* using ``base_string_uri``. +4. Create the *signature base string* from the above three components + using ``signature_base_string``. +5. Pass the *signature base string* and the client credentials to one of the + sign-with-client functions. The HMAC-based signing functions needs + client credentials with secrets. The RSA-based signing functions needs + client credentials with an RSA private key. + +To verify a request, pass the request and credentials to one of the verify +functions. The HMAC-based signing functions needs the shared secrets. The +RSA-based verify functions needs the RSA public key. + +**Scope** + +All of the functions in this module should be considered internal to OAuthLib, +since they are not imported into the "oauthlib.oauth1" module. Programs using +OAuthLib should not use directly invoke any of the functions in this module. + +**Deprecated functions** + +The "sign_" methods that are not "_with_client" have been deprecated. They may +be removed in a future release. Since they are all internal functions, this +should have no impact on properly behaving programs. + +.. _`section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4 +""" + +import binascii +import hashlib +import hmac +import ipaddress +import logging +import urllib.parse as urlparse +import warnings + +from oauthlib.common import extract_params, safe_string_equals, urldecode + +from . import utils + +log = logging.getLogger(__name__) + + +# ==== Common functions ========================================== + +def signature_base_string( + http_method: str, + base_str_uri: str, + normalized_encoded_request_parameters: str) -> str: + """ + Construct the signature base string. + + The *signature base string* is the value that is calculated and signed by + the client. It is also independently calculated by the server to verify + the signature, and therefore must produce the exact same value at both + ends or the signature won't verify. + + The rules for calculating the *signature base string* are defined in + section 3.4.1.1`_ of RFC 5849. + + .. _`section 3.4.1.1`: https://tools.ietf.org/html/rfc5849#section-3.4.1.1 + """ + + # The signature base string is constructed by concatenating together, + # in order, the following HTTP request elements: + + # 1. The HTTP request method in uppercase. For example: "HEAD", + # "GET", "POST", etc. If the request uses a custom HTTP method, it + # MUST be encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + base_string = utils.escape(http_method.upper()) + + # 2. An "&" character (ASCII code 38). + base_string += '&' + + # 3. The base string URI from `Section 3.4.1.2`_, after being encoded + # (`Section 3.6`_). + # + # .. _`Section 3.4.1.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + base_string += utils.escape(base_str_uri) + + # 4. An "&" character (ASCII code 38). + base_string += '&' + + # 5. The request parameters as normalized in `Section 3.4.1.3.2`_, after + # being encoded (`Section 3.6`). + # + # .. _`Sec 3.4.1.3.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + base_string += utils.escape(normalized_encoded_request_parameters) + + return base_string + + +def base_string_uri(uri: str, host: str = None) -> str: + """ + Calculates the _base string URI_. + + The *base string URI* is one of the components that make up the + *signature base string*. + + The ``host`` is optional. If provided, it is used to override any host and + port values in the ``uri``. The value for ``host`` is usually extracted from + the "Host" request header from the HTTP request. Its value may be just the + hostname, or the hostname followed by a colon and a TCP/IP port number + (hostname:port). If a value for the``host`` is provided but it does not + contain a port number, the default port number is used (i.e. if the ``uri`` + contained a port number, it will be discarded). + + The rules for calculating the *base string URI* are defined in + section 3.4.1.2`_ of RFC 5849. + + .. _`section 3.4.1.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + + :param uri: URI + :param host: hostname with optional port number, separated by a colon + :return: base string URI + """ + + if not isinstance(uri, str): + raise ValueError('uri must be a string.') + + # FIXME: urlparse does not support unicode + output = urlparse.urlparse(uri) + scheme = output.scheme + hostname = output.hostname + port = output.port + path = output.path + params = output.params + + # The scheme, authority, and path of the request resource URI `RFC3986` + # are included by constructing an "http" or "https" URI representing + # the request resource (without the query or fragment) as follows: + # + # .. _`RFC3986`: https://tools.ietf.org/html/rfc3986 + + if not scheme: + raise ValueError('missing scheme') + + # Per `RFC 2616 section 5.1.2`_: + # + # Note that the absolute path cannot be empty; if none is present in + # the original URI, it MUST be given as "/" (the server root). + # + # .. _`RFC 2616 5.1.2`: https://tools.ietf.org/html/rfc2616#section-5.1.2 + if not path: + path = '/' + + # 1. The scheme and host MUST be in lowercase. + scheme = scheme.lower() + # Note: if ``host`` is used, it will be converted to lowercase below + if hostname is not None: + hostname = hostname.lower() + + # 2. The host and port values MUST match the content of the HTTP + # request "Host" header field. + if host is not None: + # NOTE: override value in uri with provided host + # Host argument is equal to netloc. It means it's missing scheme. + # Add it back, before parsing. + + host = host.lower() + host = f"{scheme}://{host}" + output = urlparse.urlparse(host) + hostname = output.hostname + port = output.port + + # 3. The port MUST be included if it is not the default port for the + # scheme, and MUST be excluded if it is the default. Specifically, + # the port MUST be excluded when making an HTTP request `RFC2616`_ + # to port 80 or when making an HTTPS request `RFC2818`_ to port 443. + # All other non-default port numbers MUST be included. + # + # .. _`RFC2616`: https://tools.ietf.org/html/rfc2616 + # .. _`RFC2818`: https://tools.ietf.org/html/rfc2818 + + if hostname is None: + raise ValueError('missing host') + + # NOTE: Try guessing if we're dealing with IP or hostname + try: + hostname = ipaddress.ip_address(hostname) + except ValueError: + pass + + if isinstance(hostname, ipaddress.IPv6Address): + hostname = f"[{hostname}]" + elif isinstance(hostname, ipaddress.IPv4Address): + hostname = f"{hostname}" + + if port is not None and not (0 < port <= 65535): + raise ValueError('port out of range') # 16-bit unsigned ints + if (scheme, port) in (('http', 80), ('https', 443)): + netloc = hostname # default port for scheme: exclude port num + elif port: + netloc = f"{hostname}:{port}" # use hostname:port + else: + netloc = hostname + + v = urlparse.urlunparse((scheme, netloc, path, params, '', '')) + + # RFC 5849 does not specify which characters are encoded in the + # "base string URI", nor how they are encoded - which is very bad, since + # the signatures won't match if there are any differences. Fortunately, + # most URIs only use characters that are clearly not encoded (e.g. digits + # and A-Z, a-z), so have avoided any differences between implementations. + # + # The example from its section 3.4.1.2 illustrates that spaces in + # the path are percent encoded. But it provides no guidance as to what other + # characters (if any) must be encoded (nor how); nor if characters in the + # other components are to be encoded or not. + # + # This implementation **assumes** that **only** the space is percent-encoded + # and it is done to the entire value (not just to spaces in the path). + # + # This code may need to be changed if it is discovered that other characters + # are expected to be encoded. + # + # Note: the "base string URI" returned by this function will be encoded + # again before being concatenated into the "signature base string". So any + # spaces in the URI will actually appear in the "signature base string" + # as "%2520" (the "%20" further encoded according to section 3.6). + + return v.replace(' ', '%20') + + +def collect_parameters(uri_query='', body=None, headers=None, + exclude_oauth_signature=True, with_realm=False): + """ + Gather the request parameters from all the parameter sources. + + This function is used to extract all the parameters, which are then passed + to ``normalize_parameters`` to produce one of the components that make up + the *signature base string*. + + Parameters starting with `oauth_` will be unescaped. + + Body parameters must be supplied as a dict, a list of 2-tuples, or a + form encoded query string. + + Headers must be supplied as a dict. + + The rules where the parameters must be sourced from are defined in + `section 3.4.1.3.1`_ of RFC 5849. + + .. _`Sec 3.4.1.3.1`: https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1 + """ + if body is None: + body = [] + headers = headers or {} + params = [] + + # The parameters from the following sources are collected into a single + # list of name/value pairs: + + # * The query component of the HTTP request URI as defined by + # `RFC3986, Section 3.4`_. The query component is parsed into a list + # of name/value pairs by treating it as an + # "application/x-www-form-urlencoded" string, separating the names + # and values and decoding them as defined by W3C.REC-html40-19980424 + # `W3C-HTML-4.0`_, Section 17.13.4. + # + # .. _`RFC3986, Sec 3.4`: https://tools.ietf.org/html/rfc3986#section-3.4 + # .. _`W3C-HTML-4.0`: https://www.w3.org/TR/1998/REC-html40-19980424/ + if uri_query: + params.extend(urldecode(uri_query)) + + # * The OAuth HTTP "Authorization" header field (`Section 3.5.1`_) if + # present. The header's content is parsed into a list of name/value + # pairs excluding the "realm" parameter if present. The parameter + # values are decoded as defined by `Section 3.5.1`_. + # + # .. _`Section 3.5.1`: https://tools.ietf.org/html/rfc5849#section-3.5.1 + if headers: + headers_lower = {k.lower(): v for k, v in headers.items()} + authorization_header = headers_lower.get('authorization') + if authorization_header is not None: + params.extend([i for i in utils.parse_authorization_header( + authorization_header) if with_realm or i[0] != 'realm']) + + # * The HTTP request entity-body, but only if all of the following + # conditions are met: + # * The entity-body is single-part. + # + # * The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # W3C.REC-html40-19980424 `W3C-HTML-4.0`_. + + # * The HTTP request entity-header includes the "Content-Type" + # header field set to "application/x-www-form-urlencoded". + # + # .. _`W3C-HTML-4.0`: https://www.w3.org/TR/1998/REC-html40-19980424/ + + # TODO: enforce header param inclusion conditions + bodyparams = extract_params(body) or [] + params.extend(bodyparams) + + # ensure all oauth params are unescaped + unescaped_params = [] + for k, v in params: + if k.startswith('oauth_'): + v = utils.unescape(v) + unescaped_params.append((k, v)) + + # The "oauth_signature" parameter MUST be excluded from the signature + # base string if present. + if exclude_oauth_signature: + unescaped_params = list(filter(lambda i: i[0] != 'oauth_signature', + unescaped_params)) + + return unescaped_params + + +def normalize_parameters(params) -> str: + """ + Calculate the normalized request parameters. + + The *normalized request parameters* is one of the components that make up + the *signature base string*. + + The rules for parameter normalization are defined in `section 3.4.1.3.2`_ of + RFC 5849. + + .. _`Sec 3.4.1.3.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 + """ + + # The parameters collected in `Section 3.4.1.3`_ are normalized into a + # single string as follows: + # + # .. _`Section 3.4.1.3`: https://tools.ietf.org/html/rfc5849#section-3.4.1.3 + + # 1. First, the name and value of each parameter are encoded + # (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key_values = [(utils.escape(k), utils.escape(v)) for k, v in params] + + # 2. The parameters are sorted by name, using ascending byte value + # ordering. If two or more parameters share the same name, they + # are sorted by their value. + key_values.sort() + + # 3. The name of each parameter is concatenated to its corresponding + # value using an "=" character (ASCII code 61) as a separator, even + # if the value is empty. + parameter_parts = ['{}={}'.format(k, v) for k, v in key_values] + + # 4. The sorted name/value pairs are concatenated together into a + # single string by using an "&" character (ASCII code 38) as + # separator. + return '&'.join(parameter_parts) + + +# ==== Common functions for HMAC-based signature methods ========= + +def _sign_hmac(hash_algorithm_name: str, + sig_base_str: str, + client_secret: str, + resource_owner_secret: str): + """ + **HMAC-SHA256** + + The "HMAC-SHA256" signature method uses the HMAC-SHA256 signature + algorithm as defined in `RFC4634`_:: + + digest = HMAC-SHA256 (key, text) + + Per `section 3.4.2`_ of the spec. + + .. _`RFC4634`: https://tools.ietf.org/html/rfc4634 + .. _`section 3.4.2`: https://tools.ietf.org/html/rfc5849#section-3.4.2 + """ + + # The HMAC-SHA256 function variables are used in following way: + + # text is set to the value of the signature base string from + # `Section 3.4.1.1`_. + # + # .. _`Section 3.4.1.1`: https://tools.ietf.org/html/rfc5849#section-3.4.1.1 + text = sig_base_str + + # key is set to the concatenated values of: + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key = utils.escape(client_secret or '') + + # 2. An "&" character (ASCII code 38), which MUST be included + # even when either secret is empty. + key += '&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key += utils.escape(resource_owner_secret or '') + + # Get the hashing algorithm to use + + m = { + 'SHA-1': hashlib.sha1, + 'SHA-256': hashlib.sha256, + 'SHA-512': hashlib.sha512, + } + hash_alg = m[hash_algorithm_name] + + # Calculate the signature + + # FIXME: HMAC does not support unicode! + key_utf8 = key.encode('utf-8') + text_utf8 = text.encode('utf-8') + signature = hmac.new(key_utf8, text_utf8, hash_alg) + + # digest is used to set the value of the "oauth_signature" protocol + # parameter, after the result octet string is base64-encoded + # per `RFC2045, Section 6.8`. + # + # .. _`RFC2045, Sec 6.8`: https://tools.ietf.org/html/rfc2045#section-6.8 + return binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') + + +def _verify_hmac(hash_algorithm_name: str, + request, + client_secret=None, + resource_owner_secret=None): + """Verify a HMAC-SHA1 signature. + + Per `section 3.4`_ of the spec. + + .. _`section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4 + + To satisfy `RFC2616 section 5.2`_ item 1, the request argument's uri + attribute MUST be an absolute URI whose netloc part identifies the + origin server or gateway on which the resource resides. Any Host + item of the request argument's headers dict attribute will be + ignored. + + .. _`RFC2616 section 5.2`: https://tools.ietf.org/html/rfc2616#section-5.2 + + """ + norm_params = normalize_parameters(request.params) + bs_uri = base_string_uri(request.uri) + sig_base_str = signature_base_string(request.http_method, bs_uri, + norm_params) + signature = _sign_hmac(hash_algorithm_name, sig_base_str, + client_secret, resource_owner_secret) + match = safe_string_equals(signature, request.signature) + if not match: + log.debug('Verify HMAC failed: signature base string: %s', sig_base_str) + return match + + +# ==== HMAC-SHA1 ================================================= + +def sign_hmac_sha1_with_client(sig_base_str, client): + return _sign_hmac('SHA-1', sig_base_str, + client.client_secret, client.resource_owner_secret) + + +def verify_hmac_sha1(request, client_secret=None, resource_owner_secret=None): + return _verify_hmac('SHA-1', request, client_secret, resource_owner_secret) + + +def sign_hmac_sha1(base_string, client_secret, resource_owner_secret): + """ + Deprecated function for calculating a HMAC-SHA1 signature. + + This function has been replaced by invoking ``sign_hmac`` with "SHA-1" + as the hash algorithm name. + + This function was invoked by sign_hmac_sha1_with_client and + test_signatures.py, but does any application invoke it directly? If not, + it can be removed. + """ + warnings.warn('use sign_hmac_sha1_with_client instead of sign_hmac_sha1', + DeprecationWarning) + + # For some unknown reason, the original implementation assumed base_string + # could either be bytes or str. The signature base string calculating + # function always returned a str, so the new ``sign_rsa`` only expects that. + + base_string = base_string.decode('ascii') \ + if isinstance(base_string, bytes) else base_string + + return _sign_hmac('SHA-1', base_string, + client_secret, resource_owner_secret) + + +# ==== HMAC-SHA256 =============================================== + +def sign_hmac_sha256_with_client(sig_base_str, client): + return _sign_hmac('SHA-256', sig_base_str, + client.client_secret, client.resource_owner_secret) + + +def verify_hmac_sha256(request, client_secret=None, resource_owner_secret=None): + return _verify_hmac('SHA-256', request, + client_secret, resource_owner_secret) + + +def sign_hmac_sha256(base_string, client_secret, resource_owner_secret): + """ + Deprecated function for calculating a HMAC-SHA256 signature. + + This function has been replaced by invoking ``sign_hmac`` with "SHA-256" + as the hash algorithm name. + + This function was invoked by sign_hmac_sha256_with_client and + test_signatures.py, but does any application invoke it directly? If not, + it can be removed. + """ + warnings.warn( + 'use sign_hmac_sha256_with_client instead of sign_hmac_sha256', + DeprecationWarning) + + # For some unknown reason, the original implementation assumed base_string + # could either be bytes or str. The signature base string calculating + # function always returned a str, so the new ``sign_rsa`` only expects that. + + base_string = base_string.decode('ascii') \ + if isinstance(base_string, bytes) else base_string + + return _sign_hmac('SHA-256', base_string, + client_secret, resource_owner_secret) + + +# ==== HMAC-SHA512 =============================================== + +def sign_hmac_sha512_with_client(sig_base_str: str, + client): + return _sign_hmac('SHA-512', sig_base_str, + client.client_secret, client.resource_owner_secret) + + +def verify_hmac_sha512(request, + client_secret: str = None, + resource_owner_secret: str = None): + return _verify_hmac('SHA-512', request, + client_secret, resource_owner_secret) + + +# ==== Common functions for RSA-based signature methods ========== + +_jwt_rsa = {} # cache of RSA-hash implementations from PyJWT jwt.algorithms + + +def _get_jwt_rsa_algorithm(hash_algorithm_name: str): + """ + Obtains an RSAAlgorithm object that implements RSA with the hash algorithm. + + This method maintains the ``_jwt_rsa`` cache. + + Returns a jwt.algorithm.RSAAlgorithm. + """ + if hash_algorithm_name in _jwt_rsa: + # Found in cache: return it + return _jwt_rsa[hash_algorithm_name] + else: + # Not in cache: instantiate a new RSAAlgorithm + + # PyJWT has some nice pycrypto/cryptography abstractions + import jwt.algorithms as jwt_algorithms + m = { + 'SHA-1': jwt_algorithms.hashes.SHA1, + 'SHA-256': jwt_algorithms.hashes.SHA256, + 'SHA-512': jwt_algorithms.hashes.SHA512, + } + v = jwt_algorithms.RSAAlgorithm(m[hash_algorithm_name]) + + _jwt_rsa[hash_algorithm_name] = v # populate cache + + return v + + +def _prepare_key_plus(alg, keystr): + """ + Prepare a PEM encoded key (public or private), by invoking the `prepare_key` + method on alg with the keystr. + + The keystr should be a string or bytes. If the keystr is bytes, it is + decoded as UTF-8 before being passed to prepare_key. Otherwise, it + is passed directly. + """ + if isinstance(keystr, bytes): + keystr = keystr.decode('utf-8') + return alg.prepare_key(keystr) + + +def _sign_rsa(hash_algorithm_name: str, + sig_base_str: str, + rsa_private_key: str): + """ + Calculate the signature for an RSA-based signature method. + + The ``alg`` is used to calculate the digest over the signature base string. + For the "RSA_SHA1" signature method, the alg must be SHA-1. While OAuth 1.0a + only defines the RSA-SHA1 signature method, this function can be used for + other non-standard signature methods that only differ from RSA-SHA1 by the + digest algorithm. + + Signing for the RSA-SHA1 signature method is defined in + `section 3.4.3`_ of RFC 5849. + + The RSASSA-PKCS1-v1_5 signature algorithm used defined by + `RFC3447, Section 8.2`_ (also known as PKCS#1), with the `alg` as the + hash function for EMSA-PKCS1-v1_5. To + use this method, the client MUST have established client credentials + with the server that included its RSA public key (in a manner that is + beyond the scope of this specification). + + .. _`section 3.4.3`: https://tools.ietf.org/html/rfc5849#section-3.4.3 + .. _`RFC3447, Section 8.2`: https://tools.ietf.org/html/rfc3447#section-8.2 + """ + + # Get the implementation of RSA-hash + + alg = _get_jwt_rsa_algorithm(hash_algorithm_name) + + # Check private key + + if not rsa_private_key: + raise ValueError('rsa_private_key required for RSA with ' + + alg.hash_alg.name + ' signature method') + + # Convert the "signature base string" into a sequence of bytes (M) + # + # The signature base string, by definition, only contain printable US-ASCII + # characters. So encoding it as 'ascii' will always work. It will raise a + # ``UnicodeError`` if it can't encode the value, which will never happen + # if the signature base string was created correctly. Therefore, using + # 'ascii' encoding provides an extra level of error checking. + + m = sig_base_str.encode('ascii') + + # Perform signing: S = RSASSA-PKCS1-V1_5-SIGN (K, M) + + key = _prepare_key_plus(alg, rsa_private_key) + s = alg.sign(m, key) + + # base64-encoded per RFC2045 section 6.8. + # + # 1. While b2a_base64 implements base64 defined by RFC 3548. As used here, + # it is the same as base64 defined by RFC 2045. + # 2. b2a_base64 includes a "\n" at the end of its result ([:-1] removes it) + # 3. b2a_base64 produces a binary string. Use decode to produce a str. + # It should only contain only printable US-ASCII characters. + + return binascii.b2a_base64(s)[:-1].decode('ascii') + + +def _verify_rsa(hash_algorithm_name: str, + request, + rsa_public_key: str): + """ + Verify a base64 encoded signature for a RSA-based signature method. + + The ``alg`` is used to calculate the digest over the signature base string. + For the "RSA_SHA1" signature method, the alg must be SHA-1. While OAuth 1.0a + only defines the RSA-SHA1 signature method, this function can be used for + other non-standard signature methods that only differ from RSA-SHA1 by the + digest algorithm. + + Verification for the RSA-SHA1 signature method is defined in + `section 3.4.3`_ of RFC 5849. + + .. _`section 3.4.3`: https://tools.ietf.org/html/rfc5849#section-3.4.3 + + To satisfy `RFC2616 section 5.2`_ item 1, the request argument's uri + attribute MUST be an absolute URI whose netloc part identifies the + origin server or gateway on which the resource resides. Any Host + item of the request argument's headers dict attribute will be + ignored. + + .. _`RFC2616 Sec 5.2`: https://tools.ietf.org/html/rfc2616#section-5.2 + """ + + try: + # Calculate the *signature base string* of the actual received request + + norm_params = normalize_parameters(request.params) + bs_uri = base_string_uri(request.uri) + sig_base_str = signature_base_string( + request.http_method, bs_uri, norm_params) + + # Obtain the signature that was received in the request + + sig = binascii.a2b_base64(request.signature.encode('ascii')) + + # Get the implementation of RSA-with-hash algorithm to use + + alg = _get_jwt_rsa_algorithm(hash_algorithm_name) + + # Verify the received signature was produced by the private key + # corresponding to the `rsa_public_key`, signing exact same + # *signature base string*. + # + # RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S) + + key = _prepare_key_plus(alg, rsa_public_key) + + # The signature base string only contain printable US-ASCII characters. + # The ``encode`` method with the default "strict" error handling will + # raise a ``UnicodeError`` if it can't encode the value. So using + # "ascii" will always work. + + verify_ok = alg.verify(sig_base_str.encode('ascii'), key, sig) + + if not verify_ok: + log.debug('Verify failed: RSA with ' + alg.hash_alg.name + + ': signature base string=%s' + sig_base_str) + return verify_ok + + except UnicodeError: + # A properly encoded signature will only contain printable US-ASCII + # characters. The ``encode`` method with the default "strict" error + # handling will raise a ``UnicodeError`` if it can't decode the value. + # So using "ascii" will work with all valid signatures. But an + # incorrectly or maliciously produced signature could contain other + # bytes. + # + # This implementation treats that situation as equivalent to the + # signature verification having failed. + # + # Note: simply changing the encode to use 'utf-8' will not remove this + # case, since an incorrect or malicious request can contain bytes which + # are invalid as UTF-8. + return False + + +# ==== RSA-SHA1 ================================================== + +def sign_rsa_sha1_with_client(sig_base_str, client): + # For some reason, this function originally accepts both str and bytes. + # This behaviour is preserved here. But won't be done for the newer + # sign_rsa_sha256_with_client and sign_rsa_sha512_with_client functions, + # which will only accept strings. The function to calculate a + # "signature base string" always produces a string, so it is not clear + # why support for bytes would ever be needed. + sig_base_str = sig_base_str.decode('ascii')\ + if isinstance(sig_base_str, bytes) else sig_base_str + + return _sign_rsa('SHA-1', sig_base_str, client.rsa_key) + + +def verify_rsa_sha1(request, rsa_public_key: str): + return _verify_rsa('SHA-1', request, rsa_public_key) + + +def sign_rsa_sha1(base_string, rsa_private_key): + """ + Deprecated function for calculating a RSA-SHA1 signature. + + This function has been replaced by invoking ``sign_rsa`` with "SHA-1" + as the hash algorithm name. + + This function was invoked by sign_rsa_sha1_with_client and + test_signatures.py, but does any application invoke it directly? If not, + it can be removed. + """ + warnings.warn('use _sign_rsa("SHA-1", ...) instead of sign_rsa_sha1', + DeprecationWarning) + + if isinstance(base_string, bytes): + base_string = base_string.decode('ascii') + + return _sign_rsa('SHA-1', base_string, rsa_private_key) + + +# ==== RSA-SHA256 ================================================ + +def sign_rsa_sha256_with_client(sig_base_str: str, client): + return _sign_rsa('SHA-256', sig_base_str, client.rsa_key) + + +def verify_rsa_sha256(request, rsa_public_key: str): + return _verify_rsa('SHA-256', request, rsa_public_key) + + +# ==== RSA-SHA512 ================================================ + +def sign_rsa_sha512_with_client(sig_base_str: str, client): + return _sign_rsa('SHA-512', sig_base_str, client.rsa_key) + + +def verify_rsa_sha512(request, rsa_public_key: str): + return _verify_rsa('SHA-512', request, rsa_public_key) + + +# ==== PLAINTEXT ================================================= + +def sign_plaintext_with_client(_signature_base_string, client): + # _signature_base_string is not used because the signature with PLAINTEXT + # is just the secret: it isn't a real signature. + return sign_plaintext(client.client_secret, client.resource_owner_secret) + + +def sign_plaintext(client_secret, resource_owner_secret): + """Sign a request using plaintext. + + Per `section 3.4.4`_ of the spec. + + The "PLAINTEXT" method does not employ a signature algorithm. It + MUST be used with a transport-layer mechanism such as TLS or SSL (or + sent over a secure channel with equivalent protections). It does not + utilize the signature base string or the "oauth_timestamp" and + "oauth_nonce" parameters. + + .. _`section 3.4.4`: https://tools.ietf.org/html/rfc5849#section-3.4.4 + + """ + + # The "oauth_signature" protocol parameter is set to the concatenated + # value of: + + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + signature = utils.escape(client_secret or '') + + # 2. An "&" character (ASCII code 38), which MUST be included even + # when either secret is empty. + signature += '&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + signature += utils.escape(resource_owner_secret or '') + + return signature + + +def verify_plaintext(request, client_secret=None, resource_owner_secret=None): + """Verify a PLAINTEXT signature. + + Per `section 3.4`_ of the spec. + + .. _`section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4 + """ + signature = sign_plaintext(client_secret, resource_owner_secret) + match = safe_string_equals(signature, request.signature) + if not match: + log.debug('Verify PLAINTEXT failed') + return match diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..8fb8302e306948f5822997d39ba3b7ff0ae0cdef --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth1/rfc5849/utils.py @@ -0,0 +1,83 @@ +""" +oauthlib.utils +~~~~~~~~~~~~~~ + +This module contains utility methods used by various parts of the OAuth +spec. +""" +import urllib.request as urllib2 + +from oauthlib.common import quote, unquote + +UNICODE_ASCII_CHARACTER_SET = ('abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789') + + +def filter_params(target): + """Decorator which filters params to remove non-oauth_* parameters + + Assumes the decorated method takes a params dict or list of tuples as its + first argument. + """ + def wrapper(params, *args, **kwargs): + params = filter_oauth_params(params) + return target(params, *args, **kwargs) + + wrapper.__doc__ = target.__doc__ + return wrapper + + +def filter_oauth_params(params): + """Removes all non oauth parameters from a dict or a list of params.""" + is_oauth = lambda kv: kv[0].startswith("oauth_") + if isinstance(params, dict): + return list(filter(is_oauth, list(params.items()))) + else: + return list(filter(is_oauth, params)) + + +def escape(u): + """Escape a unicode string in an OAuth-compatible fashion. + + Per `section 3.6`_ of the spec. + + .. _`section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + + """ + if not isinstance(u, str): + raise ValueError('Only unicode objects are escapable. ' + + 'Got {!r} of type {}.'.format(u, type(u))) + # Letters, digits, and the characters '_.-' are already treated as safe + # by urllib.quote(). We need to add '~' to fully support rfc5849. + return quote(u, safe=b'~') + + +def unescape(u): + if not isinstance(u, str): + raise ValueError('Only unicode objects are unescapable.') + return unquote(u) + + +def parse_keqv_list(l): + """A unicode-safe version of urllib2.parse_keqv_list""" + # With Python 2.6, parse_http_list handles unicode fine + return urllib2.parse_keqv_list(l) + + +def parse_http_list(u): + """A unicode-safe version of urllib2.parse_http_list""" + # With Python 2.6, parse_http_list handles unicode fine + return urllib2.parse_http_list(u) + + +def parse_authorization_header(authorization_header): + """Parse an OAuth authorization header into a list of 2-tuples""" + auth_scheme = 'OAuth '.lower() + if authorization_header[:len(auth_scheme)].lower().startswith(auth_scheme): + items = parse_http_list(authorization_header[len(auth_scheme):]) + try: + return list(parse_keqv_list(items).items()) + except (IndexError, ValueError): + pass + raise ValueError('Malformed authorization header') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..deefb1af78687bfc4f5e44cc6eb917fc08318b14 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__init__.py @@ -0,0 +1,36 @@ +""" +oauthlib.oauth2 +~~~~~~~~~~~~~~ + +This module is a wrapper for the most recent implementation of OAuth 2.0 Client +and Server classes. +""" +from .rfc6749.clients import ( + BackendApplicationClient, Client, LegacyApplicationClient, + MobileApplicationClient, ServiceApplicationClient, WebApplicationClient, +) +from .rfc6749.endpoints import ( + AuthorizationEndpoint, BackendApplicationServer, IntrospectEndpoint, + LegacyApplicationServer, MetadataEndpoint, MobileApplicationServer, + ResourceEndpoint, RevocationEndpoint, Server, TokenEndpoint, + WebApplicationServer, +) +from .rfc6749.errors import ( + AccessDeniedError, FatalClientError, InsecureTransportError, + InvalidClientError, InvalidClientIdError, InvalidGrantError, + InvalidRedirectURIError, InvalidRequestError, InvalidRequestFatalError, + InvalidScopeError, MismatchingRedirectURIError, MismatchingStateError, + MissingClientIdError, MissingCodeError, MissingRedirectURIError, + MissingResponseTypeError, MissingTokenError, MissingTokenTypeError, + OAuth2Error, ServerError, TemporarilyUnavailableError, TokenExpiredError, + UnauthorizedClientError, UnsupportedGrantTypeError, + UnsupportedResponseTypeError, UnsupportedTokenTypeError, +) +from .rfc6749.grant_types import ( + AuthorizationCodeGrant, ClientCredentialsGrant, ImplicitGrant, + RefreshTokenGrant, ResourceOwnerPasswordCredentialsGrant, +) +from .rfc6749.request_validator import RequestValidator +from .rfc6749.tokens import BearerToken, OAuth2Token +from .rfc6749.utils import is_secure_transport +from .rfc8628.clients import DeviceClient diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6eb1cd78cc373cb39c7534f518948c98ddad5615 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4b75a8a196c6d9e3ff0815c97a7feccf95d9fcd9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__init__.py @@ -0,0 +1,16 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import functools +import logging + +from .endpoints.base import BaseEndpoint, catch_errors_and_unavailability +from .errors import ( + FatalClientError, OAuth2Error, ServerError, TemporarilyUnavailableError, +) + +log = logging.getLogger(__name__) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efdca7400fd703ad3d5a906d747c965e75236bc9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/errors.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/errors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd98a355923f38523db2abf14b61d2bed42e7e3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/errors.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/parameters.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/parameters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f80be0ce260db0666ed1f1ab46845e51efec8ee6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/parameters.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/request_validator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/request_validator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d683534957177a2af80f8ff57e1a3d9093d093f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/request_validator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/tokens.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/tokens.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02febc58be4aa9027ceade17a2ac53b225ca9531 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/tokens.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad856203721fafc3c2df89444fea27383c4d8590 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8fc6c955a24dfecd3181f2a2e876fb587299266e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__init__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming OAuth 2.0 RFC6749. +""" +from .backend_application import BackendApplicationClient +from .base import AUTH_HEADER, BODY, URI_QUERY, Client +from .legacy_application import LegacyApplicationClient +from .mobile_application import MobileApplicationClient +from .service_application import ServiceApplicationClient +from .web_application import WebApplicationClient diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15d25540c29f29f8925b97a95cb330057c6844e1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/backend_application.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/backend_application.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bbe94f7d7258808b7dbe9124488c6b433342431 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/backend_application.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d10ca20b08e055ef4983320498dc9bffb84fd6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/legacy_application.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/legacy_application.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42e3197bc9fbfce633b8f1bd8ebc63a499e76724 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/legacy_application.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/mobile_application.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/mobile_application.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df3e624fd798d50d111088d73a3d0da2413f4943 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/mobile_application.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/service_application.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/service_application.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1c543b05bc28c0b9c90201125cd7acddb11b155 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/service_application.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/web_application.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/web_application.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21c656daa9844870db21d994df475337eee0757d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/__pycache__/web_application.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/backend_application.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/backend_application.py new file mode 100644 index 0000000000000000000000000000000000000000..e11e8fae380fc88784c0d429488b67aac3447dd3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/backend_application.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +from ..parameters import prepare_token_request +from .base import Client + + +class BackendApplicationClient(Client): + + """A public client utilizing the client credentials grant workflow. + + The client can request an access token using only its client + credentials (or other supported means of authentication) when the + client is requesting access to the protected resources under its + control, or those of another resource owner which has been previously + arranged with the authorization server (the method of which is beyond + the scope of this specification). + + The client credentials grant type MUST only be used by confidential + clients. + + Since the client authentication is used as the authorization grant, + no additional authorization request is needed. + """ + + grant_type = 'client_credentials' + + def prepare_request_body(self, body='', scope=None, + include_client_id=False, **kwargs): + """Add the client credentials to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per `Appendix B`_ in the HTTP request entity-body: + + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + :param scope: The scope of the access request as described by + `Section 3.3`_. + + :param include_client_id: `True` to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in + `Section 3.2.1`_. False otherwise (default). + :type include_client_id: Boolean + + :param kwargs: Extra credentials to include in the token request. + + The client MUST authenticate with the authorization server as + described in `Section 3.2.1`_. + + The prepared body will include all provided credentials as well as + the ``grant_type`` parameter set to ``client_credentials``:: + + >>> from oauthlib.oauth2 import BackendApplicationClient + >>> client = BackendApplicationClient('your_id') + >>> client.prepare_request_body(scope=['hello', 'world']) + 'grant_type=client_credentials&scope=hello+world' + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 + """ + kwargs['client_id'] = self.client_id + kwargs['include_client_id'] = include_client_id + scope = self.scope if scope is None else scope + return prepare_token_request(self.grant_type, body=body, + scope=scope, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/base.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/base.py new file mode 100644 index 0000000000000000000000000000000000000000..d5eb0cc15ff2f465d7c2e007d27fbd03eb46eda9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/base.py @@ -0,0 +1,604 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming OAuth 2.0 RFC6749. +""" +import base64 +import hashlib +import re +import secrets +import time +import warnings + +from oauthlib.common import generate_token +from oauthlib.oauth2.rfc6749 import tokens +from oauthlib.oauth2.rfc6749.errors import ( + InsecureTransportError, TokenExpiredError, +) +from oauthlib.oauth2.rfc6749.parameters import ( + parse_token_response, prepare_token_request, + prepare_token_revocation_request, +) +from oauthlib.oauth2.rfc6749.utils import is_secure_transport + +AUTH_HEADER = 'auth_header' +URI_QUERY = 'query' +BODY = 'body' + +FORM_ENC_HEADERS = { + 'Content-Type': 'application/x-www-form-urlencoded' +} + + +class Client: + """Base OAuth2 client responsible for access token management. + + This class also acts as a generic interface providing methods common to all + client types such as ``prepare_authorization_request`` and + ``prepare_token_revocation_request``. The ``prepare_x_request`` methods are + the recommended way of interacting with clients (as opposed to the abstract + prepare uri/body/etc methods). They are recommended over the older set + because they are easier to use (more consistent) and add a few additional + security checks, such as HTTPS and state checking. + + Some of these methods require further implementation only provided by the + specific purpose clients such as + :py:class:`oauthlib.oauth2.MobileApplicationClient` and thus you should always + seek to use the client class matching the OAuth workflow you need. For + Python, this is usually :py:class:`oauthlib.oauth2.WebApplicationClient`. + + """ + refresh_token_key = 'refresh_token' + + def __init__(self, client_id, + default_token_placement=AUTH_HEADER, + token_type='Bearer', + access_token=None, + refresh_token=None, + mac_key=None, + mac_algorithm=None, + token=None, + scope=None, + state=None, + redirect_url=None, + state_generator=generate_token, + code_verifier=None, + code_challenge=None, + code_challenge_method=None, + **kwargs): + """Initialize a client with commonly used attributes. + + :param client_id: Client identifier given by the OAuth provider upon + registration. + + :param default_token_placement: Tokens can be supplied in the Authorization + header (default), the URL query component (``query``) or the request + body (``body``). + + :param token_type: OAuth 2 token type. Defaults to Bearer. Change this + if you specify the ``access_token`` parameter and know it is of a + different token type, such as a MAC, JWT or SAML token. Can + also be supplied as ``token_type`` inside the ``token`` dict parameter. + + :param access_token: An access token (string) used to authenticate + requests to protected resources. Can also be supplied inside the + ``token`` dict parameter. + + :param refresh_token: A refresh token (string) used to refresh expired + tokens. Can also be supplied inside the ``token`` dict parameter. + + :param mac_key: Encryption key used with MAC tokens. + + :param mac_algorithm: Hashing algorithm for MAC tokens. + + :param token: A dict of token attributes such as ``access_token``, + ``token_type`` and ``expires_at``. + + :param scope: A list of default scopes to request authorization for. + + :param state: A CSRF protection string used during authorization. + + :param redirect_url: The redirection endpoint on the client side to which + the user returns after authorization. + + :param state_generator: A no argument state generation callable. Defaults + to :py:meth:`oauthlib.common.generate_token`. + + :param code_verifier: PKCE parameter. A cryptographically random string that is used to correlate the + authorization request to the token request. + + :param code_challenge: PKCE parameter. A challenge derived from the code verifier that is sent in the + authorization request, to be verified against later. + + :param code_challenge_method: PKCE parameter. A method that was used to derive code challenge. + Defaults to "plain" if not present in the request. + """ + + self.client_id = client_id + self.default_token_placement = default_token_placement + self.token_type = token_type + self.access_token = access_token + self.refresh_token = refresh_token + self.mac_key = mac_key + self.mac_algorithm = mac_algorithm + self.token = token or {} + self.scope = scope + self.state_generator = state_generator + self.state = state + self.redirect_url = redirect_url + self.code_verifier = code_verifier + self.code_challenge = code_challenge + self.code_challenge_method = code_challenge_method + self.code = None + self.expires_in = None + self._expires_at = None + self.populate_token_attributes(self.token) + + @property + def token_types(self): + """Supported token types and their respective methods + + Additional tokens can be supported by extending this dictionary. + + The Bearer token spec is stable and safe to use. + + The MAC token spec is not yet stable and support for MAC tokens + is experimental and currently matching version 00 of the spec. + """ + return { + 'Bearer': self._add_bearer_token, + 'MAC': self._add_mac_token + } + + def prepare_request_uri(self, *args, **kwargs): + """Abstract method used to create request URIs.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def prepare_request_body(self, *args, **kwargs): + """Abstract method used to create request bodies.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def parse_request_uri_response(self, *args, **kwargs): + """Abstract method used to parse redirection responses.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def add_token(self, uri, http_method='GET', body=None, headers=None, + token_placement=None, **kwargs): + """Add token to the request uri, body or authorization header. + + The access token type provides the client with the information + required to successfully utilize the access token to make a protected + resource request (along with type-specific attributes). The client + MUST NOT use an access token if it does not understand the token + type. + + For example, the "bearer" token type defined in + [`I-D.ietf-oauth-v2-bearer`_] is utilized by simply including the access + token string in the request: + + .. code-block:: http + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: Bearer mF_9.B5f-4.1JqM + + while the "mac" token type defined in [`I-D.ietf-oauth-v2-http-mac`_] is + utilized by issuing a MAC key together with the access token which is + used to sign certain components of the HTTP requests: + + .. code-block:: http + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: MAC id="h480djs93hd8", + nonce="274312:dj83hs9s", + mac="kDZvddkndxvhGRXZhvuDjEWhGeE=" + + .. _`I-D.ietf-oauth-v2-bearer`: https://tools.ietf.org/html/rfc6749#section-12.2 + .. _`I-D.ietf-oauth-v2-http-mac`: https://tools.ietf.org/html/rfc6749#section-12.2 + """ + if not is_secure_transport(uri): + raise InsecureTransportError() + + token_placement = token_placement or self.default_token_placement + + case_insensitive_token_types = { + k.lower(): v for k, v in self.token_types.items()} + if not self.token_type.lower() in case_insensitive_token_types: + raise ValueError("Unsupported token type: %s" % self.token_type) + + if not (self.access_token or self.token.get('access_token')): + raise ValueError("Missing access token.") + + if self._expires_at and self._expires_at < time.time(): + raise TokenExpiredError() + + return case_insensitive_token_types[self.token_type.lower()](uri, http_method, body, + headers, token_placement, **kwargs) + + def prepare_authorization_request(self, authorization_url, state=None, + redirect_url=None, scope=None, **kwargs): + """Prepare the authorization request. + + This is the first step in many OAuth flows in which the user is + redirected to a certain authorization URL. This method adds + required parameters to the authorization URL. + + :param authorization_url: Provider authorization endpoint URL. + :param state: CSRF protection string. Will be automatically created if + not provided. The generated state is available via the ``state`` + attribute. Clients should verify that the state is unchanged and + present in the authorization response. This verification is done + automatically if using the ``authorization_response`` parameter + with ``prepare_token_request``. + :param redirect_url: Redirect URL to which the user will be returned + after authorization. Must be provided unless previously setup with + the provider. If provided then it must also be provided in the + token request. + :param scope: List of scopes to request. Must be equal to + or a subset of the scopes granted when obtaining the refresh + token. If none is provided, the ones provided in the constructor are + used. + :param kwargs: Additional parameters to included in the request. + :returns: The prepared request tuple with (url, headers, body). + """ + if not is_secure_transport(authorization_url): + raise InsecureTransportError() + + self.state = state or self.state_generator() + self.redirect_url = redirect_url or self.redirect_url + # do not assign scope to self automatically anymore + scope = self.scope if scope is None else scope + auth_url = self.prepare_request_uri( + authorization_url, redirect_uri=self.redirect_url, + scope=scope, state=self.state, **kwargs) + return auth_url, FORM_ENC_HEADERS, '' + + def prepare_token_request(self, token_url, authorization_response=None, + redirect_url=None, state=None, body='', **kwargs): + """Prepare a token creation request. + + Note that these requests usually require client authentication, either + by including client_id or a set of provider specific authentication + credentials. + + :param token_url: Provider token creation endpoint URL. + :param authorization_response: The full redirection URL string, i.e. + the location to which the user was redirected after successful + authorization. Used to mine credentials needed to obtain a token + in this step, such as authorization code. + :param redirect_url: The redirect_url supplied with the authorization + request (if there was one). + :param state: + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + :param kwargs: Additional parameters to included in the request. + :returns: The prepared request tuple with (url, headers, body). + """ + if not is_secure_transport(token_url): + raise InsecureTransportError() + + state = state or self.state + if authorization_response: + self.parse_request_uri_response( + authorization_response, state=state) + self.redirect_url = redirect_url or self.redirect_url + body = self.prepare_request_body(body=body, + redirect_uri=self.redirect_url, **kwargs) + + return token_url, FORM_ENC_HEADERS, body + + def prepare_refresh_token_request(self, token_url, refresh_token=None, + body='', scope=None, **kwargs): + """Prepare an access token refresh request. + + Expired access tokens can be replaced by new access tokens without + going through the OAuth dance if the client obtained a refresh token. + This refresh token and authentication credentials can be used to + obtain a new access token, and possibly a new refresh token. + + :param token_url: Provider token refresh endpoint URL. + :param refresh_token: Refresh token string. + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + :param scope: List of scopes to request. Must be equal to + or a subset of the scopes granted when obtaining the refresh + token. If none is provided, the ones provided in the constructor are + used. + :param kwargs: Additional parameters to included in the request. + :returns: The prepared request tuple with (url, headers, body). + """ + if not is_secure_transport(token_url): + raise InsecureTransportError() + + # do not assign scope to self automatically anymore + scope = self.scope if scope is None else scope + body = self.prepare_refresh_body(body=body, + refresh_token=refresh_token, scope=scope, **kwargs) + return token_url, FORM_ENC_HEADERS, body + + def prepare_token_revocation_request(self, revocation_url, token, + token_type_hint="access_token", body='', callback=None, **kwargs): + """Prepare a token revocation request. + + :param revocation_url: Provider token revocation endpoint URL. + :param token: The access or refresh token to be revoked (string). + :param token_type_hint: ``"access_token"`` (default) or + ``"refresh_token"``. This is optional and if you wish to not pass it you + must provide ``token_type_hint=None``. + :param body: + :param callback: A jsonp callback such as ``package.callback`` to be invoked + upon receiving the response. Not that it should not include a () suffix. + :param kwargs: Additional parameters to included in the request. + :returns: The prepared request tuple with (url, headers, body). + + Note that JSONP request may use GET requests as the parameters will + be added to the request URL query as opposed to the request body. + + An example of a revocation request + + .. code-block:: http + + POST /revoke HTTP/1.1 + Host: server.example.com + Content-Type: application/x-www-form-urlencoded + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + + token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token + + An example of a jsonp revocation request + + .. code-block:: http + + GET /revoke?token=agabcdefddddafdd&callback=package.myCallback HTTP/1.1 + Host: server.example.com + Content-Type: application/x-www-form-urlencoded + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + + and an error response + + .. code-block:: javascript + + package.myCallback({"error":"unsupported_token_type"}); + + Note that these requests usually require client credentials, client_id in + the case for public clients and provider specific authentication + credentials for confidential clients. + """ + if not is_secure_transport(revocation_url): + raise InsecureTransportError() + + return prepare_token_revocation_request(revocation_url, token, + token_type_hint=token_type_hint, body=body, callback=callback, + **kwargs) + + def parse_request_body_response(self, body, scope=None, **kwargs): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token as described in + `Section 5.1`_. A refresh token SHOULD NOT be included. If the request + failed client authentication or is invalid, the authorization server + returns an error response as described in `Section 5.2`_. + + :param body: The response body from the token request. + :param scope: Scopes originally requested. If none is provided, the ones + provided in the constructor are used. + :return: Dictionary of token parameters. + :raises: Warning if scope has changed. :py:class:`oauthlib.oauth2.errors.OAuth2Error` + if response is invalid. + + These response are json encoded and could easily be parsed without + the assistance of OAuthLib. However, there are a few subtle issues + to be aware of regarding the response which are helpfully addressed + through the raising of various errors. + + A successful response should always contain + + **access_token** + The access token issued by the authorization server. Often + a random string. + + **token_type** + The type of the token issued as described in `Section 7.1`_. + Commonly ``Bearer``. + + While it is not mandated it is recommended that the provider include + + **expires_in** + The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + **scope** + Providers may supply this in all responses but are required to only + if it has changed since the authorization request. + + .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 + .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 + .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 + """ + scope = self.scope if scope is None else scope + self.token = parse_token_response(body, scope=scope) + self.populate_token_attributes(self.token) + return self.token + + def prepare_refresh_body(self, body='', refresh_token=None, scope=None, **kwargs): + """Prepare an access token request, using a refresh token. + + If the authorization server issued a refresh token to the client, the + client makes a refresh request to the token endpoint by adding the + following parameters using the `application/x-www-form-urlencoded` + format in the HTTP request entity-body: + + :param refresh_token: REQUIRED. The refresh token issued to the client. + :param scope: OPTIONAL. The scope of the access request as described by + Section 3.3. The requested scope MUST NOT include any scope + not originally granted by the resource owner, and if omitted is + treated as equal to the scope originally granted by the + resource owner. Note that if none is provided, the ones provided + in the constructor are used if any. + """ + refresh_token = refresh_token or self.refresh_token + scope = self.scope if scope is None else scope + return prepare_token_request(self.refresh_token_key, body=body, scope=scope, + refresh_token=refresh_token, **kwargs) + + def _add_bearer_token(self, uri, http_method='GET', body=None, + headers=None, token_placement=None): + """Add a bearer token to the request uri, body or authorization header.""" + if token_placement == AUTH_HEADER: + headers = tokens.prepare_bearer_headers(self.access_token, headers) + + elif token_placement == URI_QUERY: + uri = tokens.prepare_bearer_uri(self.access_token, uri) + + elif token_placement == BODY: + body = tokens.prepare_bearer_body(self.access_token, body) + + else: + raise ValueError("Invalid token placement.") + return uri, headers, body + + def create_code_verifier(self, length): + """Create PKCE **code_verifier** used in computing **code_challenge**. + See `RFC7636 Section 4.1`_ + + :param length: REQUIRED. The length of the code_verifier. + + The client first creates a code verifier, "code_verifier", for each + OAuth 2.0 [RFC6749] Authorization Request, in the following manner: + + .. code-block:: text + + code_verifier = high-entropy cryptographic random STRING using the + unreserved characters [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" + from Section 2.3 of [RFC3986], with a minimum length of 43 characters + and a maximum length of 128 characters. + + .. _`RFC7636 Section 4.1`: https://tools.ietf.org/html/rfc7636#section-4.1 + """ + code_verifier = None + + if not length >= 43: + raise ValueError("Length must be greater than or equal to 43") + + if not length <= 128: + raise ValueError("Length must be less than or equal to 128") + + allowed_characters = re.compile('^[A-Zaa-z0-9-._~]') + code_verifier = secrets.token_urlsafe(length) + + if not re.search(allowed_characters, code_verifier): + raise ValueError("code_verifier contains invalid characters") + + self.code_verifier = code_verifier + + return code_verifier + + def create_code_challenge(self, code_verifier, code_challenge_method=None): + """Create PKCE **code_challenge** derived from the **code_verifier**. + See `RFC7636 Section 4.2`_ + + :param code_verifier: REQUIRED. The **code_verifier** generated from `create_code_verifier()`. + :param code_challenge_method: OPTIONAL. The method used to derive the **code_challenge**. Acceptable values include `S256`. DEFAULT is `plain`. + + The client then creates a code challenge derived from the code + verifier by using one of the following transformations on the code + verifier:: + + plain + code_challenge = code_verifier + S256 + code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) + + If the client is capable of using `S256`, it MUST use `S256`, as + `S256` is Mandatory To Implement (MTI) on the server. Clients are + permitted to use `plain` only if they cannot support `S256` for some + technical reason and know via out-of-band configuration that the + server supports `plain`. + + The plain transformation is for compatibility with existing + deployments and for constrained environments that can't use the S256 transformation. + + .. _`RFC7636 Section 4.2`: https://tools.ietf.org/html/rfc7636#section-4.2 + """ + code_challenge = None + + if code_verifier == None: + raise ValueError("Invalid code_verifier") + + if code_challenge_method == None: + code_challenge_method = "plain" + self.code_challenge_method = code_challenge_method + code_challenge = code_verifier + self.code_challenge = code_challenge + + if code_challenge_method == "S256": + h = hashlib.sha256() + h.update(code_verifier.encode(encoding='ascii')) + sha256_val = h.digest() + code_challenge = bytes.decode(base64.urlsafe_b64encode(sha256_val)) + # replace '+' with '-', '/' with '_', and remove trailing '=' + code_challenge = code_challenge.replace("+", "-").replace("/", "_").replace("=", "") + self.code_challenge = code_challenge + + return code_challenge + + def _add_mac_token(self, uri, http_method='GET', body=None, + headers=None, token_placement=AUTH_HEADER, ext=None, **kwargs): + """Add a MAC token to the request authorization header. + + Warning: MAC token support is experimental as the spec is not yet stable. + """ + if token_placement != AUTH_HEADER: + raise ValueError("Invalid token placement.") + + headers = tokens.prepare_mac_header(self.access_token, uri, + self.mac_key, http_method, headers=headers, body=body, ext=ext, + hash_algorithm=self.mac_algorithm, **kwargs) + return uri, headers, body + + def _populate_attributes(self, response): + warnings.warn("Please switch to the public method " + "populate_token_attributes.", DeprecationWarning) + return self.populate_token_attributes(response) + + def populate_code_attributes(self, response): + """Add attributes from an auth code response to self.""" + + if 'code' in response: + self.code = response.get('code') + + def populate_token_attributes(self, response): + """Add attributes from a token exchange response to self.""" + + if 'access_token' in response: + self.access_token = response.get('access_token') + + if 'refresh_token' in response: + self.refresh_token = response.get('refresh_token') + + if 'token_type' in response: + self.token_type = response.get('token_type') + + if 'expires_in' in response: + self.expires_in = response.get('expires_in') + self._expires_at = time.time() + int(self.expires_in) + + if 'expires_at' in response: + try: + self._expires_at = int(response.get('expires_at')) + except: + self._expires_at = None + + if 'mac_key' in response: + self.mac_key = response.get('mac_key') + + if 'mac_algorithm' in response: + self.mac_algorithm = response.get('mac_algorithm') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/legacy_application.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/legacy_application.py new file mode 100644 index 0000000000000000000000000000000000000000..9920981d2c601761492ac1511c3ecd7a6a6a2e51 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/legacy_application.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +from ..parameters import prepare_token_request +from .base import Client + + +class LegacyApplicationClient(Client): + + """A public client using the resource owner password and username directly. + + The resource owner password credentials grant type is suitable in + cases where the resource owner has a trust relationship with the + client, such as the device operating system or a highly privileged + application. The authorization server should take special care when + enabling this grant type, and only allow it when other flows are not + viable. + + The grant type is suitable for clients capable of obtaining the + resource owner's credentials (username and password, typically using + an interactive form). It is also used to migrate existing clients + using direct authentication schemes such as HTTP Basic or Digest + authentication to OAuth by converting the stored credentials to an + access token. + + The method through which the client obtains the resource owner + credentials is beyond the scope of this specification. The client + MUST discard the credentials once an access token has been obtained. + """ + + grant_type = 'password' + + def __init__(self, client_id, **kwargs): + super().__init__(client_id, **kwargs) + + def prepare_request_body(self, username, password, body='', scope=None, + include_client_id=False, **kwargs): + """Add the resource owner password and username to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per `Appendix B`_ in the HTTP request entity-body: + + :param username: The resource owner username. + :param password: The resource owner password. + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + :param scope: The scope of the access request as described by + `Section 3.3`_. + :param include_client_id: `True` to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in + `Section 3.2.1`_. False otherwise (default). + :type include_client_id: Boolean + :param kwargs: Extra credentials to include in the token request. + + If the client type is confidential or the client was issued client + credentials (or assigned other authentication requirements), the + client MUST authenticate with the authorization server as described + in `Section 3.2.1`_. + + The prepared body will include all provided credentials as well as + the ``grant_type`` parameter set to ``password``:: + + >>> from oauthlib.oauth2 import LegacyApplicationClient + >>> client = LegacyApplicationClient('your_id') + >>> client.prepare_request_body(username='foo', password='bar', scope=['hello', 'world']) + 'grant_type=password&username=foo&scope=hello+world&password=bar' + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 + """ + kwargs['client_id'] = self.client_id + kwargs['include_client_id'] = include_client_id + scope = self.scope if scope is None else scope + return prepare_token_request(self.grant_type, body=body, username=username, + password=password, scope=scope, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/mobile_application.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/mobile_application.py new file mode 100644 index 0000000000000000000000000000000000000000..b10b41ced3da18ebaef68bee00d31e46d90a62da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/mobile_application.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +from ..parameters import parse_implicit_response, prepare_grant_uri +from .base import Client + + +class MobileApplicationClient(Client): + + """A public client utilizing the implicit code grant workflow. + + A user-agent-based application is a public client in which the + client code is downloaded from a web server and executes within a + user-agent (e.g. web browser) on the device used by the resource + owner. Protocol data and credentials are easily accessible (and + often visible) to the resource owner. Since such applications + reside within the user-agent, they can make seamless use of the + user-agent capabilities when requesting authorization. + + The implicit grant type is used to obtain access tokens (it does not + support the issuance of refresh tokens) and is optimized for public + clients known to operate a particular redirection URI. These clients + are typically implemented in a browser using a scripting language + such as JavaScript. + + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + + Unlike the authorization code grant type in which the client makes + separate requests for authorization and access token, the client + receives the access token as the result of the authorization request. + + The implicit grant type does not include client authentication, and + relies on the presence of the resource owner and the registration of + the redirection URI. Because the access token is encoded into the + redirection URI, it may be exposed to the resource owner and other + applications residing on the same device. + """ + + response_type = 'token' + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, **kwargs): + """Prepare the implicit grant request URI. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format, per `Appendix B`_: + + :param redirect_uri: OPTIONAL. The redirect URI must be an absolute URI + and it should have been registered with the OAuth + provider prior to use. As described in `Section 3.1.2`_. + + :param scope: OPTIONAL. The scope of the access request as described by + Section 3.3`_. These may be any string but are commonly + URIs or various categories such as ``videos`` or ``documents``. + + :param state: RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + :param kwargs: Extra arguments to include in the request URI. + + In addition to supplied parameters, OAuthLib will append the ``client_id`` + that was provided in the constructor as well as the mandatory ``response_type`` + argument, set to ``token``:: + + >>> from oauthlib.oauth2 import MobileApplicationClient + >>> client = MobileApplicationClient('your_id') + >>> client.prepare_request_uri('https://example.com') + 'https://example.com?client_id=your_id&response_type=token' + >>> client.prepare_request_uri('https://example.com', redirect_uri='https://a.b/callback') + 'https://example.com?client_id=your_id&response_type=token&redirect_uri=https%3A%2F%2Fa.b%2Fcallback' + >>> client.prepare_request_uri('https://example.com', scope=['profile', 'pictures']) + 'https://example.com?client_id=your_id&response_type=token&scope=profile+pictures' + >>> client.prepare_request_uri('https://example.com', foo='bar') + 'https://example.com?client_id=your_id&response_type=token&foo=bar' + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + """ + scope = self.scope if scope is None else scope + return prepare_grant_uri(uri, self.client_id, self.response_type, + redirect_uri=redirect_uri, state=state, scope=scope, **kwargs) + + def parse_request_uri_response(self, uri, state=None, scope=None): + """Parse the response URI fragment. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the "application/x-www-form-urlencoded" format: + + :param uri: The callback URI that resulted from the user being redirected + back from the provider to you, the client. + :param state: The state provided in the authorization request. + :param scope: The scopes provided in the authorization request. + :return: Dictionary of token parameters. + :raises: OAuth2Error if response is invalid. + + A successful response should always contain + + **access_token** + The access token issued by the authorization server. Often + a random string. + + **token_type** + The type of the token issued as described in `Section 7.1`_. + Commonly ``Bearer``. + + **state** + If you provided the state parameter in the authorization phase, then + the provider is required to include that exact state value in the + response. + + While it is not mandated it is recommended that the provider include + + **expires_in** + The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + **scope** + Providers may supply this in all responses but are required to only + if it has changed since the authorization request. + + A few example responses can be seen below:: + + >>> response_uri = 'https://example.com/callback#access_token=sdlfkj452&state=ss345asyht&token_type=Bearer&scope=hello+world' + >>> from oauthlib.oauth2 import MobileApplicationClient + >>> client = MobileApplicationClient('your_id') + >>> client.parse_request_uri_response(response_uri) + { + 'access_token': 'sdlfkj452', + 'token_type': 'Bearer', + 'state': 'ss345asyht', + 'scope': [u'hello', u'world'] + } + >>> client.parse_request_uri_response(response_uri, state='other') + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "oauthlib/oauth2/rfc6749/__init__.py", line 598, in parse_request_uri_response + **scope** + File "oauthlib/oauth2/rfc6749/parameters.py", line 197, in parse_implicit_response + raise ValueError("Mismatching or missing state in params.") + ValueError: Mismatching or missing state in params. + >>> def alert_scope_changed(message, old, new): + ... print(message, old, new) + ... + >>> oauthlib.signals.scope_changed.connect(alert_scope_changed) + >>> client.parse_request_body_response(response_body, scope=['other']) + ('Scope has changed from "other" to "hello world".', ['other'], ['hello', 'world']) + + .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + """ + scope = self.scope if scope is None else scope + self.token = parse_implicit_response(uri, state=state, scope=scope) + self.populate_token_attributes(self.token) + return self.token diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/service_application.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/service_application.py new file mode 100644 index 0000000000000000000000000000000000000000..8fb173776d13e1a8f2db81904799adbf5b12e4dc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/service_application.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import time + +from oauthlib.common import to_unicode + +from ..parameters import prepare_token_request +from .base import Client + + +class ServiceApplicationClient(Client): + """A public client utilizing the JWT bearer grant. + + JWT bearer tokes can be used to request an access token when a client + wishes to utilize an existing trust relationship, expressed through the + semantics of (and digital signature or keyed message digest calculated + over) the JWT, without a direct user approval step at the authorization + server. + + This grant type does not involve an authorization step. It may be + used by both public and confidential clients. + """ + + grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer' + + def __init__(self, client_id, private_key=None, subject=None, issuer=None, + audience=None, **kwargs): + """Initialize a JWT client with defaults for implicit use later. + + :param client_id: Client identifier given by the OAuth provider upon + registration. + + :param private_key: Private key used for signing and encrypting. + Must be given as a string. + + :param subject: The principal that is the subject of the JWT, i.e. + which user is the token requested on behalf of. + For example, ``foo@example.com. + + :param issuer: The JWT MUST contain an "iss" (issuer) claim that + contains a unique identifier for the entity that issued + the JWT. For example, ``your-client@provider.com``. + + :param audience: A value identifying the authorization server as an + intended audience, e.g. + ``https://provider.com/oauth2/token``. + + :param kwargs: Additional arguments to pass to base client, such as + state and token. See ``Client.__init__.__doc__`` for + details. + """ + super().__init__(client_id, **kwargs) + self.private_key = private_key + self.subject = subject + self.issuer = issuer + self.audience = audience + + def prepare_request_body(self, + private_key=None, + subject=None, + issuer=None, + audience=None, + expires_at=None, + issued_at=None, + extra_claims=None, + body='', + scope=None, + include_client_id=False, + **kwargs): + """Create and add a JWT assertion to the request body. + + :param private_key: Private key used for signing and encrypting. + Must be given as a string. + + :param subject: (sub) The principal that is the subject of the JWT, + i.e. which user is the token requested on behalf of. + For example, ``foo@example.com. + + :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that + contains a unique identifier for the entity that issued + the JWT. For example, ``your-client@provider.com``. + + :param audience: (aud) A value identifying the authorization server as an + intended audience, e.g. + ``https://provider.com/oauth2/token``. + + :param expires_at: A unix expiration timestamp for the JWT. Defaults + to an hour from now, i.e. ``time.time() + 3600``. + + :param issued_at: A unix timestamp of when the JWT was created. + Defaults to now, i.e. ``time.time()``. + + :param extra_claims: A dict of additional claims to include in the JWT. + + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + + :param scope: The scope of the access request. + + :param include_client_id: `True` to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in + `Section 3.2.1`_. False otherwise (default). + :type include_client_id: Boolean + + :param not_before: A unix timestamp after which the JWT may be used. + Not included unless provided. * + + :param jwt_id: A unique JWT token identifier. Not included unless + provided. * + + :param kwargs: Extra credentials to include in the token request. + + Parameters marked with a `*` above are not explicit arguments in the + function signature, but are specially documented arguments for items + appearing in the generic `**kwargs` keyworded input. + + The "scope" parameter may be used, as defined in the Assertion + Framework for OAuth 2.0 Client Authentication and Authorization Grants + [I-D.ietf-oauth-assertions] specification, to indicate the requested + scope. + + Authentication of the client is optional, as described in + `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the + "client_id" is only needed when a form of client authentication that + relies on the parameter is used. + + The following non-normative example demonstrates an Access Token + Request with a JWT as an authorization grant (with extra line breaks + for display purposes only): + + .. code-block: http + + POST /token.oauth2 HTTP/1.1 + Host: as.example.com + Content-Type: application/x-www-form-urlencoded + + grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer + &assertion=eyJhbGciOiJFUzI1NiJ9. + eyJpc3Mi[...omitted for brevity...]. + J9l-ZhwP[...omitted for brevity...] + + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 + """ + import jwt + + key = private_key or self.private_key + if not key: + raise ValueError('An encryption key must be supplied to make JWT' + ' token requests.') + claim = { + 'iss': issuer or self.issuer, + 'aud': audience or self.audience, + 'sub': subject or self.subject, + 'exp': int(expires_at or time.time() + 3600), + 'iat': int(issued_at or time.time()), + } + + for attr in ('iss', 'aud', 'sub'): + if claim[attr] is None: + raise ValueError( + 'Claim must include %s but none was given.' % attr) + + if 'not_before' in kwargs: + claim['nbf'] = kwargs.pop('not_before') + + if 'jwt_id' in kwargs: + claim['jti'] = kwargs.pop('jwt_id') + + claim.update(extra_claims or {}) + + assertion = jwt.encode(claim, key, 'RS256') + assertion = to_unicode(assertion) + + kwargs['client_id'] = self.client_id + kwargs['include_client_id'] = include_client_id + scope = self.scope if scope is None else scope + return prepare_token_request(self.grant_type, + body=body, + assertion=assertion, + scope=scope, + **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py new file mode 100644 index 0000000000000000000000000000000000000000..50890fbf8a5149509ecd2238d915291f7fd01be9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import warnings + +from ..parameters import ( + parse_authorization_code_response, prepare_grant_uri, + prepare_token_request, +) +from .base import Client + + +class WebApplicationClient(Client): + + """A client utilizing the authorization code grant workflow. + + A web application is a confidential client running on a web + server. Resource owners access the client via an HTML user + interface rendered in a user-agent on the device used by the + resource owner. The client credentials as well as any access + token issued to the client are stored on the web server and are + not exposed to or accessible by the resource owner. + + The authorization code grant type is used to obtain both access + tokens and refresh tokens and is optimized for confidential clients. + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + """ + + grant_type = 'authorization_code' + + def __init__(self, client_id, code=None, **kwargs): + super().__init__(client_id, **kwargs) + self.code = code + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, code_challenge=None, code_challenge_method='plain', **kwargs): + """Prepare the authorization code request URI + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format, per `Appendix B`_: + + :param redirect_uri: OPTIONAL. The redirect URI must be an absolute URI + and it should have been registered with the OAuth + provider prior to use. As described in `Section 3.1.2`_. + + :param scope: OPTIONAL. The scope of the access request as described by + Section 3.3`_. These may be any string but are commonly + URIs or various categories such as ``videos`` or ``documents``. + + :param state: RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + :param code_challenge: OPTIONAL. PKCE parameter. REQUIRED if PKCE is enforced. + A challenge derived from the code_verifier that is sent in the + authorization request, to be verified against later. + + :param code_challenge_method: OPTIONAL. PKCE parameter. A method that was used to derive code challenge. + Defaults to "plain" if not present in the request. + + :param kwargs: Extra arguments to include in the request URI. + + In addition to supplied parameters, OAuthLib will append the ``client_id`` + that was provided in the constructor as well as the mandatory ``response_type`` + argument, set to ``code``:: + + >>> from oauthlib.oauth2 import WebApplicationClient + >>> client = WebApplicationClient('your_id') + >>> client.prepare_request_uri('https://example.com') + 'https://example.com?client_id=your_id&response_type=code' + >>> client.prepare_request_uri('https://example.com', redirect_uri='https://a.b/callback') + 'https://example.com?client_id=your_id&response_type=code&redirect_uri=https%3A%2F%2Fa.b%2Fcallback' + >>> client.prepare_request_uri('https://example.com', scope=['profile', 'pictures']) + 'https://example.com?client_id=your_id&response_type=code&scope=profile+pictures' + >>> client.prepare_request_uri('https://example.com', code_challenge='kjasBS523KdkAILD2k78NdcJSk2k3KHG6') + 'https://example.com?client_id=your_id&response_type=code&code_challenge=kjasBS523KdkAILD2k78NdcJSk2k3KHG6' + >>> client.prepare_request_uri('https://example.com', code_challenge_method='S256') + 'https://example.com?client_id=your_id&response_type=code&code_challenge_method=S256' + >>> client.prepare_request_uri('https://example.com', foo='bar') + 'https://example.com?client_id=your_id&response_type=code&foo=bar' + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + """ + scope = self.scope if scope is None else scope + return prepare_grant_uri(uri, self.client_id, 'code', + redirect_uri=redirect_uri, scope=scope, state=state, code_challenge=code_challenge, + code_challenge_method=code_challenge_method, **kwargs) + + def prepare_request_body(self, code=None, redirect_uri=None, body='', + include_client_id=True, code_verifier=None, **kwargs): + """Prepare the access token request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + :param code: REQUIRED. The authorization code received from the + authorization server. + + :param redirect_uri: REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in `Section 4.1.1`_, and their + values MUST be identical. + + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + + :param include_client_id: `True` (default) to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in `Section 3.2.1`_. + :type include_client_id: Boolean + + :param code_verifier: OPTIONAL. A cryptographically random string that is used to correlate the + authorization request to the token request. + + :param kwargs: Extra parameters to include in the token request. + + In addition OAuthLib will add the ``grant_type`` parameter set to + ``authorization_code``. + + If the client type is confidential or the client was issued client + credentials (or assigned other authentication requirements), the + client MUST authenticate with the authorization server as described + in `Section 3.2.1`_:: + + >>> from oauthlib.oauth2 import WebApplicationClient + >>> client = WebApplicationClient('your_id') + >>> client.prepare_request_body(code='sh35ksdf09sf') + 'grant_type=authorization_code&code=sh35ksdf09sf' + >>> client.prepare_request_body(code_verifier='KB46DCKJ873NCGXK5GD682NHDKK34GR') + 'grant_type=authorization_code&code_verifier=KB46DCKJ873NCGXK5GD682NHDKK34GR' + >>> client.prepare_request_body(code='sh35ksdf09sf', foo='bar') + 'grant_type=authorization_code&code=sh35ksdf09sf&foo=bar' + + `Section 3.2.1` also states: + In the "authorization_code" "grant_type" request to the token + endpoint, an unauthenticated client MUST send its "client_id" to + prevent itself from inadvertently accepting a code intended for a + client with a different "client_id". This protects the client from + substitution of the authentication code. (It provides no additional + security for the protected resource.) + + .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1 + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 + """ + code = code or self.code + if 'client_id' in kwargs: + warnings.warn("`client_id` has been deprecated in favor of " + "`include_client_id`, a boolean value which will " + "include the already configured `self.client_id`.", + DeprecationWarning) + if kwargs['client_id'] != self.client_id: + raise ValueError("`client_id` was supplied as an argument, but " + "it does not match `self.client_id`") + + kwargs['client_id'] = self.client_id + kwargs['include_client_id'] = include_client_id + return prepare_token_request(self.grant_type, code=code, body=body, + redirect_uri=redirect_uri, code_verifier=code_verifier, **kwargs) + + def parse_request_uri_response(self, uri, state=None): + """Parse the URI query for code and state. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format: + + :param uri: The callback URI that resulted from the user being redirected + back from the provider to you, the client. + :param state: The state provided in the authorization request. + + **code** + The authorization code generated by the authorization server. + The authorization code MUST expire shortly after it is issued + to mitigate the risk of leaks. A maximum authorization code + lifetime of 10 minutes is RECOMMENDED. The client MUST NOT + use the authorization code more than once. If an authorization + code is used more than once, the authorization server MUST deny + the request and SHOULD revoke (when possible) all tokens + previously issued based on that authorization code. + The authorization code is bound to the client identifier and + redirection URI. + + **state** + If the "state" parameter was present in the authorization request. + + This method is mainly intended to enforce strict state checking with + the added benefit of easily extracting parameters from the URI:: + + >>> from oauthlib.oauth2 import WebApplicationClient + >>> client = WebApplicationClient('your_id') + >>> uri = 'https://example.com/callback?code=sdfkjh345&state=sfetw45' + >>> client.parse_request_uri_response(uri, state='sfetw45') + {'state': 'sfetw45', 'code': 'sdfkjh345'} + >>> client.parse_request_uri_response(uri, state='other') + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "oauthlib/oauth2/rfc6749/__init__.py", line 357, in parse_request_uri_response + back from the provider to you, the client. + File "oauthlib/oauth2/rfc6749/parameters.py", line 153, in parse_authorization_code_response + raise MismatchingStateError() + oauthlib.oauth2.rfc6749.errors.MismatchingStateError + """ + response = parse_authorization_code_response(uri, state=state) + self.populate_code_attributes(response) + return response diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1695b41b663eded80893849ec0b4ecc6f69c0e5c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__init__.py @@ -0,0 +1,17 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +from .authorization import AuthorizationEndpoint +from .introspect import IntrospectEndpoint +from .metadata import MetadataEndpoint +from .pre_configured import ( + BackendApplicationServer, LegacyApplicationServer, MobileApplicationServer, + Server, WebApplicationServer, +) +from .resource import ResourceEndpoint +from .revocation import RevocationEndpoint +from .token import TokenEndpoint diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..248ac5c55081d21f7337465c09ad0d5bbf6f3d4d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/authorization.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/authorization.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44d8847b0cc436040c94cdaf91e784f075bb50b0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/authorization.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fffc92c04fb60c3e789f2bd363db38b303b9fee9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/introspect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/introspect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac83dbc00b72674687a331c456dc5eda07f30742 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/introspect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/metadata.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/metadata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..55bee8dd51faab74741d2e271e4ce4c5119abcfc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/metadata.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/pre_configured.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/pre_configured.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bc02b6e1df3e677513a90ad7a2e1db61b585bf1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/pre_configured.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/resource.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/resource.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f09ee6ba501019a98e498fce5fbff8805b7cbb04 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/resource.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/revocation.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/revocation.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3ae2ffde6332ce2db0cfd102089f76cd1beab18 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/revocation.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f44c6c222bd1939a18d42b025e6427ccb9af2843 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/__pycache__/token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/authorization.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/authorization.py new file mode 100644 index 0000000000000000000000000000000000000000..71967865dce4a1d6cc344036a732f7bc008dbaeb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/authorization.py @@ -0,0 +1,114 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import logging + +from oauthlib.common import Request +from oauthlib.oauth2.rfc6749 import utils + +from .base import BaseEndpoint, catch_errors_and_unavailability + +log = logging.getLogger(__name__) + + +class AuthorizationEndpoint(BaseEndpoint): + + """Authorization endpoint - used by the client to obtain authorization + from the resource owner via user-agent redirection. + + The authorization endpoint is used to interact with the resource + owner and obtain an authorization grant. The authorization server + MUST first verify the identity of the resource owner. The way in + which the authorization server authenticates the resource owner (e.g. + username and password login, session cookies) is beyond the scope of + this specification. + + The endpoint URI MAY include an "application/x-www-form-urlencoded" + formatted (per `Appendix B`_) query component, + which MUST be retained when adding additional query parameters. The + endpoint URI MUST NOT include a fragment component:: + + https://example.com/path?query=component # OK + https://example.com/path?query=component#fragment # Not OK + + Since requests to the authorization endpoint result in user + authentication and the transmission of clear-text credentials (in the + HTTP response), the authorization server MUST require the use of TLS + as described in Section 1.6 when sending requests to the + authorization endpoint:: + + # We will deny any request which URI schema is not with https + + The authorization server MUST support the use of the HTTP "GET" + method [RFC2616] for the authorization endpoint, and MAY support the + use of the "POST" method as well:: + + # HTTP method is currently not enforced + + Parameters sent without a value MUST be treated as if they were + omitted from the request. The authorization server MUST ignore + unrecognized request parameters. Request and response parameters + MUST NOT be included more than once:: + + # Enforced through the design of oauthlib.common.Request + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + """ + + def __init__(self, default_response_type, default_token_type, + response_types): + BaseEndpoint.__init__(self) + self._response_types = response_types + self._default_response_type = default_response_type + self._default_token_type = default_token_type + + @property + def response_types(self): + return self._response_types + + @property + def default_response_type(self): + return self._default_response_type + + @property + def default_response_type_handler(self): + return self.response_types.get(self.default_response_type) + + @property + def default_token_type(self): + return self._default_token_type + + @catch_errors_and_unavailability + def create_authorization_response(self, uri, http_method='GET', body=None, + headers=None, scopes=None, credentials=None): + """Extract response_type and route to the designated handler.""" + request = Request( + uri, http_method=http_method, body=body, headers=headers) + request.scopes = scopes + # TODO: decide whether this should be a required argument + request.user = None # TODO: explain this in docs + for k, v in (credentials or {}).items(): + setattr(request, k, v) + response_type_handler = self.response_types.get( + request.response_type, self.default_response_type_handler) + log.debug('Dispatching response_type %s request to %r.', + request.response_type, response_type_handler) + return response_type_handler.create_authorization_response( + request, self.default_token_type) + + @catch_errors_and_unavailability + def validate_authorization_request(self, uri, http_method='GET', body=None, + headers=None): + """Extract response_type and route to the designated handler.""" + request = Request( + uri, http_method=http_method, body=body, headers=headers) + + request.scopes = utils.scope_to_list(request.scope) + + response_type_handler = self.response_types.get( + request.response_type, self.default_response_type_handler) + return response_type_handler.validate_authorization_request(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/base.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/base.py new file mode 100644 index 0000000000000000000000000000000000000000..3f239917cba8c166778fedfe9d7037a3dd17989a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/base.py @@ -0,0 +1,113 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import functools +import logging + +from ..errors import ( + FatalClientError, InvalidClientError, InvalidRequestError, OAuth2Error, + ServerError, TemporarilyUnavailableError, UnsupportedTokenTypeError, +) + +log = logging.getLogger(__name__) + + +class BaseEndpoint: + + def __init__(self): + self._available = True + self._catch_errors = False + self._valid_request_methods = None + + @property + def valid_request_methods(self): + return self._valid_request_methods + + @valid_request_methods.setter + def valid_request_methods(self, valid_request_methods): + if valid_request_methods is not None: + valid_request_methods = [x.upper() for x in valid_request_methods] + self._valid_request_methods = valid_request_methods + + + @property + def available(self): + return self._available + + @available.setter + def available(self, available): + self._available = available + + @property + def catch_errors(self): + return self._catch_errors + + @catch_errors.setter + def catch_errors(self, catch_errors): + self._catch_errors = catch_errors + + def _raise_on_missing_token(self, request): + """Raise error on missing token.""" + if not request.token: + raise InvalidRequestError(request=request, + description='Missing token parameter.') + def _raise_on_invalid_client(self, request): + """Raise on failed client authentication.""" + if self.request_validator.client_authentication_required(request): + if not self.request_validator.authenticate_client(request): + log.debug('Client authentication failed, %r.', request) + raise InvalidClientError(request=request) + elif not self.request_validator.authenticate_client_id(request.client_id, request): + log.debug('Client authentication failed, %r.', request) + raise InvalidClientError(request=request) + + def _raise_on_unsupported_token(self, request): + """Raise on unsupported tokens.""" + if (request.token_type_hint and + request.token_type_hint in self.valid_token_types and + request.token_type_hint not in self.supported_token_types): + raise UnsupportedTokenTypeError(request=request) + + def _raise_on_bad_method(self, request): + if self.valid_request_methods is None: + raise ValueError('Configure "valid_request_methods" property first') + if request.http_method.upper() not in self.valid_request_methods: + raise InvalidRequestError(request=request, + description=('Unsupported request method %s' % request.http_method.upper())) + + def _raise_on_bad_post_request(self, request): + """Raise if invalid POST request received + """ + if request.http_method.upper() == 'POST': + query_params = request.uri_query or "" + if query_params: + raise InvalidRequestError(request=request, + description=('URL query parameters are not allowed')) + +def catch_errors_and_unavailability(f): + @functools.wraps(f) + def wrapper(endpoint, uri, *args, **kwargs): + if not endpoint.available: + e = TemporarilyUnavailableError() + log.info('Endpoint unavailable, ignoring request %s.' % uri) + return {}, e.json, 503 + + if endpoint.catch_errors: + try: + return f(endpoint, uri, *args, **kwargs) + except OAuth2Error: + raise + except FatalClientError: + raise + except Exception as e: + error = ServerError() + log.warning( + 'Exception caught while processing request, %s.' % e) + return {}, error.json, 500 + else: + return f(endpoint, uri, *args, **kwargs) + return wrapper diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/introspect.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/introspect.py new file mode 100644 index 0000000000000000000000000000000000000000..3cc61e6627124cd84ca26105503445f8086bc4a6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/introspect.py @@ -0,0 +1,120 @@ +""" +oauthlib.oauth2.rfc6749.endpoint.introspect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An implementation of the OAuth 2.0 `Token Introspection`. + +.. _`Token Introspection`: https://tools.ietf.org/html/rfc7662 +""" +import json +import logging + +from oauthlib.common import Request + +from ..errors import OAuth2Error +from .base import BaseEndpoint, catch_errors_and_unavailability + +log = logging.getLogger(__name__) + + +class IntrospectEndpoint(BaseEndpoint): + + """Introspect token endpoint. + + This endpoint defines a method to query an OAuth 2.0 authorization + server to determine the active state of an OAuth 2.0 token and to + determine meta-information about this token. OAuth 2.0 deployments + can use this method to convey information about the authorization + context of the token from the authorization server to the protected + resource. + + To prevent the values of access tokens from leaking into + server-side logs via query parameters, an authorization server + offering token introspection MAY disallow the use of HTTP GET on + the introspection endpoint and instead require the HTTP POST method + to be used at the introspection endpoint. + """ + + valid_token_types = ('access_token', 'refresh_token') + valid_request_methods = ('POST',) + + def __init__(self, request_validator, supported_token_types=None): + BaseEndpoint.__init__(self) + self.request_validator = request_validator + self.supported_token_types = ( + supported_token_types or self.valid_token_types) + + @catch_errors_and_unavailability + def create_introspect_response(self, uri, http_method='POST', body=None, + headers=None): + """Create introspect valid or invalid response + + If the authorization server is unable to determine the state + of the token without additional information, it SHOULD return + an introspection response indicating the token is not active + as described in Section 2.2. + """ + resp_headers = { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store', + 'Pragma': 'no-cache', + } + request = Request(uri, http_method, body, headers) + try: + self.validate_introspect_request(request) + log.debug('Token introspect valid for %r.', request) + except OAuth2Error as e: + log.debug('Client error during validation of %r. %r.', request, e) + resp_headers.update(e.headers) + return resp_headers, e.json, e.status_code + + claims = self.request_validator.introspect_token( + request.token, + request.token_type_hint, + request + ) + if claims is None: + return resp_headers, json.dumps(dict(active=False)), 200 + if "active" in claims: + claims.pop("active") + return resp_headers, json.dumps(dict(active=True, **claims)), 200 + + def validate_introspect_request(self, request): + """Ensure the request is valid. + + The protected resource calls the introspection endpoint using + an HTTP POST request with parameters sent as + "application/x-www-form-urlencoded". + + * token REQUIRED. The string value of the token. + * token_type_hint OPTIONAL. + + A hint about the type of the token submitted for + introspection. The protected resource MAY pass this parameter to + help the authorization server optimize the token lookup. If the + server is unable to locate the token using the given hint, it MUST + extend its search across all of its supported token types. An + authorization server MAY ignore this parameter, particularly if it + is able to detect the token type automatically. + + * access_token: An Access Token as defined in [`RFC6749`], `section 1.4`_ + * refresh_token: A Refresh Token as defined in [`RFC6749`], `section 1.5`_ + + The introspection endpoint MAY accept other OPTIONAL + parameters to provide further context to the query. For + instance, an authorization server may desire to know the IP + address of the client accessing the protected resource to + determine if the correct client is likely to be presenting the + token. The definition of this or any other parameters are + outside the scope of this specification, to be defined by + service documentation or extensions to this specification. + + .. _`section 1.4`: http://tools.ietf.org/html/rfc6749#section-1.4 + .. _`section 1.5`: http://tools.ietf.org/html/rfc6749#section-1.5 + .. _`RFC6749`: http://tools.ietf.org/html/rfc6749 + """ + self._raise_on_bad_method(request) + self._raise_on_bad_post_request(request) + self._raise_on_missing_token(request) + self._raise_on_invalid_client(request) + self._raise_on_unsupported_token(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/metadata.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..a2820f28a516abc332f87a121d9cb29c8ee00c97 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/metadata.py @@ -0,0 +1,238 @@ +""" +oauthlib.oauth2.rfc6749.endpoint.metadata +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An implementation of the `OAuth 2.0 Authorization Server Metadata`. + +.. _`OAuth 2.0 Authorization Server Metadata`: https://tools.ietf.org/html/rfc8414 +""" +import copy +import json +import logging + +from .. import grant_types, utils +from .authorization import AuthorizationEndpoint +from .base import BaseEndpoint, catch_errors_and_unavailability +from .introspect import IntrospectEndpoint +from .revocation import RevocationEndpoint +from .token import TokenEndpoint + +log = logging.getLogger(__name__) + + +class MetadataEndpoint(BaseEndpoint): + + """OAuth2.0 Authorization Server Metadata endpoint. + + This specification generalizes the metadata format defined by + `OpenID Connect Discovery 1.0` in a way that is compatible + with OpenID Connect Discovery while being applicable to a wider set + of OAuth 2.0 use cases. This is intentionally parallel to the way + that OAuth 2.0 Dynamic Client Registration Protocol [`RFC7591`_] + generalized the dynamic client registration mechanisms defined by + OpenID Connect Dynamic Client Registration 1.0 + in a way that is compatible with it. + + .. _`OpenID Connect Discovery 1.0`: https://openid.net/specs/openid-connect-discovery-1_0.html + .. _`RFC7591`: https://tools.ietf.org/html/rfc7591 + """ + + def __init__(self, endpoints, claims={}, raise_errors=True): + assert isinstance(claims, dict) + for endpoint in endpoints: + assert isinstance(endpoint, BaseEndpoint) + + BaseEndpoint.__init__(self) + self.raise_errors = raise_errors + self.endpoints = endpoints + self.initial_claims = claims + self.claims = self.validate_metadata_server() + + @catch_errors_and_unavailability + def create_metadata_response(self, uri, http_method='GET', body=None, + headers=None): + """Create metadata response + """ + headers = { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + } + return headers, json.dumps(self.claims), 200 + + def validate_metadata(self, array, key, is_required=False, is_list=False, is_url=False, is_issuer=False): + if not self.raise_errors: + return + + if key not in array: + if is_required: + raise ValueError("key {} is a mandatory metadata.".format(key)) + + elif is_issuer: + if not utils.is_secure_transport(array[key]): + raise ValueError("key {}: {} must be an HTTPS URL".format(key, array[key])) + if "?" in array[key] or "&" in array[key] or "#" in array[key]: + raise ValueError("key {}: {} must not contain query or fragment components".format(key, array[key])) + + elif is_url: + if not array[key].startswith("http"): + raise ValueError("key {}: {} must be an URL".format(key, array[key])) + + elif is_list: + if not isinstance(array[key], list): + raise ValueError("key {}: {} must be an Array".format(key, array[key])) + for elem in array[key]: + if not isinstance(elem, str): + raise ValueError("array {}: {} must contains only string (not {})".format(key, array[key], elem)) + + def validate_metadata_token(self, claims, endpoint): + """ + If the token endpoint is used in the grant type, the value of this + parameter MUST be the same as the value of the "grant_type" + parameter passed to the token endpoint defined in the grant type + definition. + """ + self._grant_types.extend(endpoint._grant_types.keys()) + claims.setdefault("token_endpoint_auth_methods_supported", ["client_secret_post", "client_secret_basic"]) + + self.validate_metadata(claims, "token_endpoint_auth_methods_supported", is_list=True) + self.validate_metadata(claims, "token_endpoint_auth_signing_alg_values_supported", is_list=True) + self.validate_metadata(claims, "token_endpoint", is_required=True, is_url=True) + + def validate_metadata_authorization(self, claims, endpoint): + claims.setdefault("response_types_supported", + list(filter(lambda x: x != "none", endpoint._response_types.keys()))) + claims.setdefault("response_modes_supported", ["query", "fragment"]) + + # The OAuth2.0 Implicit flow is defined as a "grant type" but it is not + # using the "token" endpoint, as such, we have to add it explicitly to + # the list of "grant_types_supported" when enabled. + if "token" in claims["response_types_supported"]: + self._grant_types.append("implicit") + + self.validate_metadata(claims, "response_types_supported", is_required=True, is_list=True) + self.validate_metadata(claims, "response_modes_supported", is_list=True) + if "code" in claims["response_types_supported"]: + code_grant = endpoint._response_types["code"] + if not isinstance(code_grant, grant_types.AuthorizationCodeGrant) and hasattr(code_grant, "default_grant"): + code_grant = code_grant.default_grant + + claims.setdefault("code_challenge_methods_supported", + list(code_grant._code_challenge_methods.keys())) + self.validate_metadata(claims, "code_challenge_methods_supported", is_list=True) + self.validate_metadata(claims, "authorization_endpoint", is_required=True, is_url=True) + + def validate_metadata_revocation(self, claims, endpoint): + claims.setdefault("revocation_endpoint_auth_methods_supported", + ["client_secret_post", "client_secret_basic"]) + + self.validate_metadata(claims, "revocation_endpoint_auth_methods_supported", is_list=True) + self.validate_metadata(claims, "revocation_endpoint_auth_signing_alg_values_supported", is_list=True) + self.validate_metadata(claims, "revocation_endpoint", is_required=True, is_url=True) + + def validate_metadata_introspection(self, claims, endpoint): + claims.setdefault("introspection_endpoint_auth_methods_supported", + ["client_secret_post", "client_secret_basic"]) + + self.validate_metadata(claims, "introspection_endpoint_auth_methods_supported", is_list=True) + self.validate_metadata(claims, "introspection_endpoint_auth_signing_alg_values_supported", is_list=True) + self.validate_metadata(claims, "introspection_endpoint", is_required=True, is_url=True) + + def validate_metadata_server(self): + """ + Authorization servers can have metadata describing their + configuration. The following authorization server metadata values + are used by this specification. More details can be found in + `RFC8414 section 2`_ : + + issuer + REQUIRED + + authorization_endpoint + URL of the authorization server's authorization endpoint + [`RFC6749#Authorization`_]. This is REQUIRED unless no grant types are supported + that use the authorization endpoint. + + token_endpoint + URL of the authorization server's token endpoint [`RFC6749#Token`_]. This + is REQUIRED unless only the implicit grant type is supported. + + scopes_supported + RECOMMENDED. + + response_types_supported + REQUIRED. + + Other OPTIONAL fields: + jwks_uri, + registration_endpoint, + response_modes_supported + + grant_types_supported + OPTIONAL. JSON array containing a list of the OAuth 2.0 grant + type values that this authorization server supports. The array + values used are the same as those used with the "grant_types" + parameter defined by "OAuth 2.0 Dynamic Client Registration + Protocol" [`RFC7591`_]. If omitted, the default value is + "["authorization_code", "implicit"]". + + token_endpoint_auth_methods_supported + + token_endpoint_auth_signing_alg_values_supported + + service_documentation + + ui_locales_supported + + op_policy_uri + + op_tos_uri + + revocation_endpoint + + revocation_endpoint_auth_methods_supported + + revocation_endpoint_auth_signing_alg_values_supported + + introspection_endpoint + + introspection_endpoint_auth_methods_supported + + introspection_endpoint_auth_signing_alg_values_supported + + code_challenge_methods_supported + + Additional authorization server metadata parameters MAY also be used. + Some are defined by other specifications, such as OpenID Connect + Discovery 1.0 [`OpenID.Discovery`_]. + + .. _`RFC8414 section 2`: https://tools.ietf.org/html/rfc8414#section-2 + .. _`RFC6749#Authorization`: https://tools.ietf.org/html/rfc6749#section-3.1 + .. _`RFC6749#Token`: https://tools.ietf.org/html/rfc6749#section-3.2 + .. _`RFC7591`: https://tools.ietf.org/html/rfc7591 + .. _`OpenID.Discovery`: https://openid.net/specs/openid-connect-discovery-1_0.html + """ + claims = copy.deepcopy(self.initial_claims) + self.validate_metadata(claims, "issuer", is_required=True, is_issuer=True) + self.validate_metadata(claims, "jwks_uri", is_url=True) + self.validate_metadata(claims, "scopes_supported", is_list=True) + self.validate_metadata(claims, "service_documentation", is_url=True) + self.validate_metadata(claims, "ui_locales_supported", is_list=True) + self.validate_metadata(claims, "op_policy_uri", is_url=True) + self.validate_metadata(claims, "op_tos_uri", is_url=True) + + self._grant_types = [] + for endpoint in self.endpoints: + if isinstance(endpoint, TokenEndpoint): + self.validate_metadata_token(claims, endpoint) + if isinstance(endpoint, AuthorizationEndpoint): + self.validate_metadata_authorization(claims, endpoint) + if isinstance(endpoint, RevocationEndpoint): + self.validate_metadata_revocation(claims, endpoint) + if isinstance(endpoint, IntrospectEndpoint): + self.validate_metadata_introspection(claims, endpoint) + + # "grant_types_supported" is a combination of all OAuth2 grant types + # allowed in the current provider implementation. + claims.setdefault("grant_types_supported", self._grant_types) + self.validate_metadata(claims, "grant_types_supported", is_list=True) + return claims diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py new file mode 100644 index 0000000000000000000000000000000000000000..d64a166391080921c61e1eeeb0c8fdb8c38295f8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py @@ -0,0 +1,216 @@ +""" +oauthlib.oauth2.rfc6749.endpoints.pre_configured +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various endpoints needed +for providing OAuth 2.0 RFC6749 servers. +""" +from ..grant_types import ( + AuthorizationCodeGrant, ClientCredentialsGrant, ImplicitGrant, + RefreshTokenGrant, ResourceOwnerPasswordCredentialsGrant, +) +from ..tokens import BearerToken +from .authorization import AuthorizationEndpoint +from .introspect import IntrospectEndpoint +from .resource import ResourceEndpoint +from .revocation import RevocationEndpoint +from .token import TokenEndpoint + + +class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint, + ResourceEndpoint, RevocationEndpoint): + + """An all-in-one endpoint featuring all four major grant types.""" + + def __init__(self, request_validator, token_expires_in=None, + token_generator=None, refresh_token_generator=None, + *args, **kwargs): + """Construct a new all-grants-in-one server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.auth_grant = AuthorizationCodeGrant(request_validator) + self.implicit_grant = ImplicitGrant(request_validator) + self.password_grant = ResourceOwnerPasswordCredentialsGrant( + request_validator) + self.credentials_grant = ClientCredentialsGrant(request_validator) + self.refresh_grant = RefreshTokenGrant(request_validator) + + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + + AuthorizationEndpoint.__init__(self, default_response_type='code', + response_types={ + 'code': self.auth_grant, + 'token': self.implicit_grant, + 'none': self.auth_grant + }, + default_token_type=self.bearer) + + TokenEndpoint.__init__(self, default_grant_type='authorization_code', + grant_types={ + 'authorization_code': self.auth_grant, + 'password': self.password_grant, + 'client_credentials': self.credentials_grant, + 'refresh_token': self.refresh_grant, + }, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer}) + RevocationEndpoint.__init__(self, request_validator) + IntrospectEndpoint.__init__(self, request_validator) + + +class WebApplicationServer(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint, + ResourceEndpoint, RevocationEndpoint): + + """An all-in-one endpoint featuring Authorization code grant and Bearer tokens.""" + + def __init__(self, request_validator, token_generator=None, + token_expires_in=None, refresh_token_generator=None, **kwargs): + """Construct a new web application server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.auth_grant = AuthorizationCodeGrant(request_validator) + self.refresh_grant = RefreshTokenGrant(request_validator) + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + AuthorizationEndpoint.__init__(self, default_response_type='code', + response_types={'code': self.auth_grant}, + default_token_type=self.bearer) + TokenEndpoint.__init__(self, default_grant_type='authorization_code', + grant_types={ + 'authorization_code': self.auth_grant, + 'refresh_token': self.refresh_grant, + }, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer}) + RevocationEndpoint.__init__(self, request_validator) + IntrospectEndpoint.__init__(self, request_validator) + + +class MobileApplicationServer(AuthorizationEndpoint, IntrospectEndpoint, + ResourceEndpoint, RevocationEndpoint): + + """An all-in-one endpoint featuring Implicit code grant and Bearer tokens.""" + + def __init__(self, request_validator, token_generator=None, + token_expires_in=None, refresh_token_generator=None, **kwargs): + """Construct a new implicit grant server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.implicit_grant = ImplicitGrant(request_validator) + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + AuthorizationEndpoint.__init__(self, default_response_type='token', + response_types={ + 'token': self.implicit_grant}, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer}) + RevocationEndpoint.__init__(self, request_validator, + supported_token_types=['access_token']) + IntrospectEndpoint.__init__(self, request_validator, + supported_token_types=['access_token']) + + +class LegacyApplicationServer(TokenEndpoint, IntrospectEndpoint, + ResourceEndpoint, RevocationEndpoint): + + """An all-in-one endpoint featuring Resource Owner Password Credentials grant and Bearer tokens.""" + + def __init__(self, request_validator, token_generator=None, + token_expires_in=None, refresh_token_generator=None, **kwargs): + """Construct a resource owner password credentials grant server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.password_grant = ResourceOwnerPasswordCredentialsGrant( + request_validator) + self.refresh_grant = RefreshTokenGrant(request_validator) + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + TokenEndpoint.__init__(self, default_grant_type='password', + grant_types={ + 'password': self.password_grant, + 'refresh_token': self.refresh_grant, + }, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer}) + RevocationEndpoint.__init__(self, request_validator) + IntrospectEndpoint.__init__(self, request_validator) + + +class BackendApplicationServer(TokenEndpoint, IntrospectEndpoint, + ResourceEndpoint, RevocationEndpoint): + + """An all-in-one endpoint featuring Client Credentials grant and Bearer tokens.""" + + def __init__(self, request_validator, token_generator=None, + token_expires_in=None, refresh_token_generator=None, **kwargs): + """Construct a client credentials grant server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.credentials_grant = ClientCredentialsGrant(request_validator) + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + TokenEndpoint.__init__(self, default_grant_type='client_credentials', + grant_types={ + 'client_credentials': self.credentials_grant}, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer}) + RevocationEndpoint.__init__(self, request_validator, + supported_token_types=['access_token']) + IntrospectEndpoint.__init__(self, request_validator, + supported_token_types=['access_token']) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/resource.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/resource.py new file mode 100644 index 0000000000000000000000000000000000000000..f7562255dff65d18aecd17dc3f33b108335cb404 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/resource.py @@ -0,0 +1,84 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import logging + +from oauthlib.common import Request + +from .base import BaseEndpoint, catch_errors_and_unavailability + +log = logging.getLogger(__name__) + + +class ResourceEndpoint(BaseEndpoint): + + """Authorizes access to protected resources. + + The client accesses protected resources by presenting the access + token to the resource server. The resource server MUST validate the + access token and ensure that it has not expired and that its scope + covers the requested resource. The methods used by the resource + server to validate the access token (as well as any error responses) + are beyond the scope of this specification but generally involve an + interaction or coordination between the resource server and the + authorization server:: + + # For most cases, returning a 403 should suffice. + + The method in which the client utilizes the access token to + authenticate with the resource server depends on the type of access + token issued by the authorization server. Typically, it involves + using the HTTP "Authorization" request header field [RFC2617] with an + authentication scheme defined by the specification of the access + token type used, such as [RFC6750]:: + + # Access tokens may also be provided in query and body + https://example.com/protected?access_token=kjfch2345sdf # Query + access_token=sdf23409df # Body + """ + + def __init__(self, default_token, token_types): + BaseEndpoint.__init__(self) + self._tokens = token_types + self._default_token = default_token + + @property + def default_token(self): + return self._default_token + + @property + def default_token_type_handler(self): + return self.tokens.get(self.default_token) + + @property + def tokens(self): + return self._tokens + + @catch_errors_and_unavailability + def verify_request(self, uri, http_method='GET', body=None, headers=None, + scopes=None): + """Validate client, code etc, return body + headers""" + request = Request(uri, http_method, body, headers) + request.token_type = self.find_token_type(request) + request.scopes = scopes + token_type_handler = self.tokens.get(request.token_type, + self.default_token_type_handler) + log.debug('Dispatching token_type %s request to %r.', + request.token_type, token_type_handler) + return token_type_handler.validate_request(request), request + + def find_token_type(self, request): + """Token type identification. + + RFC 6749 does not provide a method for easily differentiating between + different token types during protected resource access. We estimate + the most likely token type (if any) by asking each known token type + to give an estimation based on the request. + """ + estimates = sorted(((t.estimate_type(request), n) + for n, t in self.tokens.items()), reverse=True) + return estimates[0][1] if len(estimates) else None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/revocation.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/revocation.py new file mode 100644 index 0000000000000000000000000000000000000000..596d0860fae67017a86b1042fcf9edb674fdf38d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/revocation.py @@ -0,0 +1,126 @@ +""" +oauthlib.oauth2.rfc6749.endpoint.revocation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An implementation of the OAuth 2 `Token Revocation`_ spec (draft 11). + +.. _`Token Revocation`: https://tools.ietf.org/html/draft-ietf-oauth-revocation-11 +""" +import logging + +from oauthlib.common import Request + +from ..errors import OAuth2Error +from .base import BaseEndpoint, catch_errors_and_unavailability + +log = logging.getLogger(__name__) + + +class RevocationEndpoint(BaseEndpoint): + + """Token revocation endpoint. + + Endpoint used by authenticated clients to revoke access and refresh tokens. + Commonly this will be part of the Authorization Endpoint. + """ + + valid_token_types = ('access_token', 'refresh_token') + valid_request_methods = ('POST',) + + def __init__(self, request_validator, supported_token_types=None, + enable_jsonp=False): + BaseEndpoint.__init__(self) + self.request_validator = request_validator + self.supported_token_types = ( + supported_token_types or self.valid_token_types) + self.enable_jsonp = enable_jsonp + + @catch_errors_and_unavailability + def create_revocation_response(self, uri, http_method='POST', body=None, + headers=None): + """Revoke supplied access or refresh token. + + + The authorization server responds with HTTP status code 200 if the + token has been revoked successfully or if the client submitted an + invalid token. + + Note: invalid tokens do not cause an error response since the client + cannot handle such an error in a reasonable way. Moreover, the purpose + of the revocation request, invalidating the particular token, is + already achieved. + + The content of the response body is ignored by the client as all + necessary information is conveyed in the response code. + + An invalid token type hint value is ignored by the authorization server + and does not influence the revocation response. + """ + resp_headers = { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store', + 'Pragma': 'no-cache', + } + request = Request( + uri, http_method=http_method, body=body, headers=headers) + try: + self.validate_revocation_request(request) + log.debug('Token revocation valid for %r.', request) + except OAuth2Error as e: + log.debug('Client error during validation of %r. %r.', request, e) + response_body = e.json + if self.enable_jsonp and request.callback: + response_body = '{}({});'.format(request.callback, response_body) + resp_headers.update(e.headers) + return resp_headers, response_body, e.status_code + + self.request_validator.revoke_token(request.token, + request.token_type_hint, request) + + response_body = '' + if self.enable_jsonp and request.callback: + response_body = request.callback + '();' + return {}, response_body, 200 + + def validate_revocation_request(self, request): + """Ensure the request is valid. + + The client constructs the request by including the following parameters + using the "application/x-www-form-urlencoded" format in the HTTP + request entity-body: + + token (REQUIRED). The token that the client wants to get revoked. + + token_type_hint (OPTIONAL). A hint about the type of the token + submitted for revocation. Clients MAY pass this parameter in order to + help the authorization server to optimize the token lookup. If the + server is unable to locate the token using the given hint, it MUST + extend its search across all of its supported token types. An + authorization server MAY ignore this parameter, particularly if it is + able to detect the token type automatically. This specification + defines two such values: + + * access_token: An Access Token as defined in [RFC6749], + `section 1.4`_ + + * refresh_token: A Refresh Token as defined in [RFC6749], + `section 1.5`_ + + Specific implementations, profiles, and extensions of this + specification MAY define other values for this parameter using + the registry defined in `Section 4.1.2`_. + + The client also includes its authentication credentials as described in + `Section 2.3`_. of [`RFC6749`_]. + + .. _`section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4 + .. _`section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5 + .. _`section 2.3`: https://tools.ietf.org/html/rfc6749#section-2.3 + .. _`Section 4.1.2`: https://tools.ietf.org/html/draft-ietf-oauth-revocation-11#section-4.1.2 + .. _`RFC6749`: https://tools.ietf.org/html/rfc6749 + """ + self._raise_on_bad_method(request) + self._raise_on_bad_post_request(request) + self._raise_on_missing_token(request) + self._raise_on_invalid_client(request) + self._raise_on_unsupported_token(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/token.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/token.py new file mode 100644 index 0000000000000000000000000000000000000000..ab9e0918b30da3271335fbbac370d5667c9b1d61 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/endpoints/token.py @@ -0,0 +1,119 @@ +""" +oauthlib.oauth2.rfc6749 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 RFC6749. +""" +import logging + +from oauthlib.common import Request +from oauthlib.oauth2.rfc6749 import utils + +from .base import BaseEndpoint, catch_errors_and_unavailability + +log = logging.getLogger(__name__) + + +class TokenEndpoint(BaseEndpoint): + + """Token issuing endpoint. + + The token endpoint is used by the client to obtain an access token by + presenting its authorization grant or refresh token. The token + endpoint is used with every authorization grant except for the + implicit grant type (since an access token is issued directly). + + The means through which the client obtains the location of the token + endpoint are beyond the scope of this specification, but the location + is typically provided in the service documentation. + + The endpoint URI MAY include an "application/x-www-form-urlencoded" + formatted (per `Appendix B`_) query component, + which MUST be retained when adding additional query parameters. The + endpoint URI MUST NOT include a fragment component:: + + https://example.com/path?query=component # OK + https://example.com/path?query=component#fragment # Not OK + + Since requests to the token endpoint result in the transmission of + clear-text credentials (in the HTTP request and response), the + authorization server MUST require the use of TLS as described in + Section 1.6 when sending requests to the token endpoint:: + + # We will deny any request which URI schema is not with https + + The client MUST use the HTTP "POST" method when making access token + requests:: + + # HTTP method is currently not enforced + + Parameters sent without a value MUST be treated as if they were + omitted from the request. The authorization server MUST ignore + unrecognized request parameters. Request and response parameters + MUST NOT be included more than once:: + + # Delegated to each grant type. + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + """ + + valid_request_methods = ('POST',) + + def __init__(self, default_grant_type, default_token_type, grant_types): + BaseEndpoint.__init__(self) + self._grant_types = grant_types + self._default_token_type = default_token_type + self._default_grant_type = default_grant_type + + @property + def grant_types(self): + return self._grant_types + + @property + def default_grant_type(self): + return self._default_grant_type + + @property + def default_grant_type_handler(self): + return self.grant_types.get(self.default_grant_type) + + @property + def default_token_type(self): + return self._default_token_type + + @catch_errors_and_unavailability + def create_token_response(self, uri, http_method='POST', body=None, + headers=None, credentials=None, grant_type_for_scope=None, + claims=None): + """Extract grant_type and route to the designated handler.""" + request = Request( + uri, http_method=http_method, body=body, headers=headers) + self.validate_token_request(request) + # 'scope' is an allowed Token Request param in both the "Resource Owner Password Credentials Grant" + # and "Client Credentials Grant" flows + # https://tools.ietf.org/html/rfc6749#section-4.3.2 + # https://tools.ietf.org/html/rfc6749#section-4.4.2 + request.scopes = utils.scope_to_list(request.scope) + + request.extra_credentials = credentials + if grant_type_for_scope: + request.grant_type = grant_type_for_scope + + # OpenID Connect claims, if provided. The server using oauthlib might choose + # to implement the claims parameter of the Authorization Request. In this case + # it should retrieve those claims and pass them via the claims argument here, + # as a dict. + if claims: + request.claims = claims + + grant_type_handler = self.grant_types.get(request.grant_type, + self.default_grant_type_handler) + log.debug('Dispatching grant_type %s request to %r.', + request.grant_type, grant_type_handler) + return grant_type_handler.create_token_response( + request, self.default_token_type) + + def validate_token_request(self, request): + self._raise_on_bad_method(request) + self._raise_on_bad_post_request(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/errors.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/errors.py new file mode 100644 index 0000000000000000000000000000000000000000..da24feab7543577d52ab39cee5fc7f049168f916 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/errors.py @@ -0,0 +1,400 @@ +""" +oauthlib.oauth2.rfc6749.errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Error used both by OAuth 2 clients and providers to represent the spec +defined error responses for all four core grant types. +""" +import json + +from oauthlib.common import add_params_to_uri, urlencode + + +class OAuth2Error(Exception): + error = None + status_code = 400 + description = '' + + def __init__(self, description=None, uri=None, state=None, + status_code=None, request=None): + """ + :param description: A human-readable ASCII [USASCII] text providing + additional information, used to assist the client + developer in understanding the error that occurred. + Values for the "error_description" parameter + MUST NOT include characters outside the set + x20-21 / x23-5B / x5D-7E. + + :param uri: A URI identifying a human-readable web page with information + about the error, used to provide the client developer with + additional information about the error. Values for the + "error_uri" parameter MUST conform to the URI- Reference + syntax, and thus MUST NOT include characters outside the set + x21 / x23-5B / x5D-7E. + + :param state: A CSRF protection value received from the client. + + :param status_code: + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + if description is not None: + self.description = description + + message = '({}) {}'.format(self.error, self.description) + if request: + message += ' ' + repr(request) + super().__init__(message) + + self.uri = uri + self.state = state + + if status_code: + self.status_code = status_code + + if request: + self.redirect_uri = request.redirect_uri + self.client_id = request.client_id + self.scopes = request.scopes + self.response_type = request.response_type + self.response_mode = request.response_mode + self.grant_type = request.grant_type + if not state: + self.state = request.state + else: + self.redirect_uri = None + self.client_id = None + self.scopes = None + self.response_type = None + self.response_mode = None + self.grant_type = None + + def in_uri(self, uri): + fragment = self.response_mode == "fragment" + return add_params_to_uri(uri, self.twotuples, fragment) + + @property + def twotuples(self): + error = [('error', self.error)] + if self.description: + error.append(('error_description', self.description)) + if self.uri: + error.append(('error_uri', self.uri)) + if self.state: + error.append(('state', self.state)) + return error + + @property + def urlencoded(self): + return urlencode(self.twotuples) + + @property + def json(self): + return json.dumps(dict(self.twotuples)) + + @property + def headers(self): + if self.status_code == 401: + """ + https://tools.ietf.org/html/rfc6750#section-3 + + All challenges defined by this specification MUST use the auth-scheme + value "Bearer". This scheme MUST be followed by one or more + auth-param values. + """ + authvalues = ['error="{}"'.format(self.error)] + if self.description: + authvalues.append('error_description="{}"'.format(self.description)) + if self.uri: + authvalues.append('error_uri="{}"'.format(self.uri)) + return {"WWW-Authenticate": "Bearer " + ", ".join(authvalues)} + return {} + + +class TokenExpiredError(OAuth2Error): + error = 'token_expired' + + +class InsecureTransportError(OAuth2Error): + error = 'insecure_transport' + description = 'OAuth 2 MUST utilize https.' + + +class MismatchingStateError(OAuth2Error): + error = 'mismatching_state' + description = 'CSRF Warning! State not equal in request and response.' + + +class MissingCodeError(OAuth2Error): + error = 'missing_code' + + +class MissingTokenError(OAuth2Error): + error = 'missing_token' + + +class MissingTokenTypeError(OAuth2Error): + error = 'missing_token_type' + + +class FatalClientError(OAuth2Error): + """ + Errors during authorization where user should not be redirected back. + + If the request fails due to a missing, invalid, or mismatching + redirection URI, or if the client identifier is missing or invalid, + the authorization server SHOULD inform the resource owner of the + error and MUST NOT automatically redirect the user-agent to the + invalid redirection URI. + + Instead the user should be informed of the error by the provider itself. + """ + pass + + +class InvalidRequestFatalError(FatalClientError): + """ + For fatal errors, the request is missing a required parameter, includes + an invalid parameter value, includes a parameter more than once, or is + otherwise malformed. + """ + error = 'invalid_request' + + +class InvalidRedirectURIError(InvalidRequestFatalError): + description = 'Invalid redirect URI.' + + +class MissingRedirectURIError(InvalidRequestFatalError): + description = 'Missing redirect URI.' + + +class MismatchingRedirectURIError(InvalidRequestFatalError): + description = 'Mismatching redirect URI.' + + +class InvalidClientIdError(InvalidRequestFatalError): + description = 'Invalid client_id parameter value.' + + +class MissingClientIdError(InvalidRequestFatalError): + description = 'Missing client_id parameter.' + + +class InvalidRequestError(OAuth2Error): + """ + The request is missing a required parameter, includes an invalid + parameter value, includes a parameter more than once, or is + otherwise malformed. + """ + error = 'invalid_request' + + +class MissingResponseTypeError(InvalidRequestError): + description = 'Missing response_type parameter.' + + +class MissingCodeChallengeError(InvalidRequestError): + """ + If the server requires Proof Key for Code Exchange (PKCE) by OAuth + public clients and the client does not send the "code_challenge" in + the request, the authorization endpoint MUST return the authorization + error response with the "error" value set to "invalid_request". The + "error_description" or the response of "error_uri" SHOULD explain the + nature of error, e.g., code challenge required. + """ + description = 'Code challenge required.' + + +class MissingCodeVerifierError(InvalidRequestError): + """ + The request to the token endpoint, when PKCE is enabled, has + the parameter `code_verifier` REQUIRED. + """ + description = 'Code verifier required.' + + +class AccessDeniedError(OAuth2Error): + """ + The resource owner or authorization server denied the request. + """ + error = 'access_denied' + + +class UnsupportedResponseTypeError(OAuth2Error): + """ + The authorization server does not support obtaining an authorization + code using this method. + """ + error = 'unsupported_response_type' + + +class UnsupportedCodeChallengeMethodError(InvalidRequestError): + """ + If the server supporting PKCE does not support the requested + transformation, the authorization endpoint MUST return the + authorization error response with "error" value set to + "invalid_request". The "error_description" or the response of + "error_uri" SHOULD explain the nature of error, e.g., transform + algorithm not supported. + """ + description = 'Transform algorithm not supported.' + + +class InvalidScopeError(OAuth2Error): + """ + The requested scope is invalid, unknown, or malformed, or + exceeds the scope granted by the resource owner. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_scope' + + +class ServerError(OAuth2Error): + """ + The authorization server encountered an unexpected condition that + prevented it from fulfilling the request. (This error code is needed + because a 500 Internal Server Error HTTP status code cannot be returned + to the client via a HTTP redirect.) + """ + error = 'server_error' + + +class TemporarilyUnavailableError(OAuth2Error): + """ + The authorization server is currently unable to handle the request + due to a temporary overloading or maintenance of the server. + (This error code is needed because a 503 Service Unavailable HTTP + status code cannot be returned to the client via a HTTP redirect.) + """ + error = 'temporarily_unavailable' + + +class InvalidClientError(FatalClientError): + """ + Client authentication failed (e.g. unknown client, no client + authentication included, or unsupported authentication method). + The authorization server MAY return an HTTP 401 (Unauthorized) status + code to indicate which HTTP authentication schemes are supported. + If the client attempted to authenticate via the "Authorization" request + header field, the authorization server MUST respond with an + HTTP 401 (Unauthorized) status code, and include the "WWW-Authenticate" + response header field matching the authentication scheme used by the + client. + """ + error = 'invalid_client' + status_code = 401 + + +class InvalidGrantError(OAuth2Error): + """ + The provided authorization grant (e.g. authorization code, resource + owner credentials) or refresh token is invalid, expired, revoked, does + not match the redirection URI used in the authorization request, or was + issued to another client. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_grant' + status_code = 400 + + +class UnauthorizedClientError(OAuth2Error): + """ + The authenticated client is not authorized to use this authorization + grant type. + """ + error = 'unauthorized_client' + + +class UnsupportedGrantTypeError(OAuth2Error): + """ + The authorization grant type is not supported by the authorization + server. + """ + error = 'unsupported_grant_type' + + +class UnsupportedTokenTypeError(OAuth2Error): + """ + The authorization server does not support the hint of the + presented token type. I.e. the client tried to revoke an access token + on a server not supporting this feature. + """ + error = 'unsupported_token_type' + + +class InvalidTokenError(OAuth2Error): + """ + The access token provided is expired, revoked, malformed, or + invalid for other reasons. The resource SHOULD respond with + the HTTP 401 (Unauthorized) status code. The client MAY + request a new access token and retry the protected resource + request. + """ + error = 'invalid_token' + status_code = 401 + description = ("The access token provided is expired, revoked, malformed, " + "or invalid for other reasons.") + + +class InsufficientScopeError(OAuth2Error): + """ + The request requires higher privileges than provided by the + access token. The resource server SHOULD respond with the HTTP + 403 (Forbidden) status code and MAY include the "scope" + attribute with the scope necessary to access the protected + resource. + """ + error = 'insufficient_scope' + status_code = 403 + description = ("The request requires higher privileges than provided by " + "the access token.") + + +class ConsentRequired(OAuth2Error): + """ + The Authorization Server requires End-User consent. + + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface for End-User consent. + """ + error = 'consent_required' + + +class LoginRequired(OAuth2Error): + """ + The Authorization Server requires End-User authentication. + + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface for End-User authentication. + """ + error = 'login_required' + + +class CustomOAuth2Error(OAuth2Error): + """ + This error is a placeholder for all custom errors not described by the RFC. + Some of the popular OAuth2 providers are using custom errors. + """ + def __init__(self, error, *args, **kwargs): + self.error = error + super().__init__(*args, **kwargs) + + +def raise_from_error(error, params=None): + import inspect + import sys + kwargs = { + 'description': params.get('error_description'), + 'uri': params.get('error_uri'), + 'state': params.get('state') + } + for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): + if cls.error == error: + raise cls(**kwargs) + raise CustomOAuth2Error(error=error, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..eb88cfc2e9749d22780532fd75af2fc8b7c2fae2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__init__.py @@ -0,0 +1,11 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +from .authorization_code import AuthorizationCodeGrant +from .client_credentials import ClientCredentialsGrant +from .implicit import ImplicitGrant +from .refresh_token import RefreshTokenGrant +from .resource_owner_password_credentials import ( + ResourceOwnerPasswordCredentialsGrant, +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad392c2fc7b025a6307cc4ea4b7396c18250370a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/authorization_code.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/authorization_code.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5baf53d4b377000b896c485c9774d1920116795 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/authorization_code.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..71814f8b9e68eca07dcd6f9d5c1dc409d11575e6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/client_credentials.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/client_credentials.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a83eb4474a551913d46adfec408be9f114b25b9c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/client_credentials.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/implicit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/implicit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c71afa3a56facc62e03e7b49e96d2cf3bf9514e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/implicit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/refresh_token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/refresh_token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd5d1f28a7d1f0060c6ab3b7a0dbfec071dc7bed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/refresh_token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/resource_owner_password_credentials.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/resource_owner_password_credentials.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b02289491bbc3ecb239630d1c9cfd64a8c5f82d7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/__pycache__/resource_owner_password_credentials.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py new file mode 100644 index 0000000000000000000000000000000000000000..858855a174175bd46ac7c7407bc160218fe8a84a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py @@ -0,0 +1,548 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import base64 +import hashlib +import json +import logging + +from oauthlib import common + +from .. import errors +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +def code_challenge_method_s256(verifier, challenge): + """ + If the "code_challenge_method" from `Section 4.3`_ was "S256", the + received "code_verifier" is hashed by SHA-256, base64url-encoded, and + then compared to the "code_challenge", i.e.: + + BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge + + How to implement a base64url-encoding + function without padding, based upon the standard base64-encoding + function that uses padding. + + To be concrete, example C# code implementing these functions is shown + below. Similar code could be used in other languages. + + static string base64urlencode(byte [] arg) + { + string s = Convert.ToBase64String(arg); // Regular base64 encoder + s = s.Split('=')[0]; // Remove any trailing '='s + s = s.Replace('+', '-'); // 62nd char of encoding + s = s.Replace('/', '_'); // 63rd char of encoding + return s; + } + + In python urlsafe_b64encode is already replacing '+' and '/', but preserve + the trailing '='. So we have to remove it. + + .. _`Section 4.3`: https://tools.ietf.org/html/rfc7636#section-4.3 + """ + return base64.urlsafe_b64encode( + hashlib.sha256(verifier.encode()).digest() + ).decode().rstrip('=') == challenge + + +def code_challenge_method_plain(verifier, challenge): + """ + If the "code_challenge_method" from `Section 4.3`_ was "plain", they are + compared directly, i.e.: + + code_verifier == code_challenge. + + .. _`Section 4.3`: https://tools.ietf.org/html/rfc7636#section-4.3 + """ + return verifier == challenge + + +class AuthorizationCodeGrant(GrantTypeBase): + + """`Authorization Code Grant`_ + + The authorization code grant type is used to obtain both access + tokens and refresh tokens and is optimized for confidential clients. + Since this is a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + ^ + | + (B) + +----|-----+ Client Identifier +---------------+ + | -+----(A)-- & Redirection URI ---->| | + | User- | | Authorization | + | Agent -+----(B)-- User authenticates --->| Server | + | | | | + | -+----(C)-- Authorization Code ---<| | + +-|----|---+ +---------------+ + | | ^ v + (A) (C) | | + | | | | + ^ v | | + +---------+ | | + | |>---(D)-- Authorization Code ---------' | + | Client | & Redirection URI | + | | | + | |<---(E)----- Access Token -------------------' + +---------+ (w/ Optional Refresh Token) + + Note: The lines illustrating steps (A), (B), and (C) are broken into + two parts as they pass through the user-agent. + + Figure 3: Authorization Code Flow + + The flow illustrated in Figure 3 includes the following steps: + + (A) The client initiates the flow by directing the resource owner's + user-agent to the authorization endpoint. The client includes + its client identifier, requested scope, local state, and a + redirection URI to which the authorization server will send the + user-agent back once access is granted (or denied). + + (B) The authorization server authenticates the resource owner (via + the user-agent) and establishes whether the resource owner + grants or denies the client's access request. + + (C) Assuming the resource owner grants access, the authorization + server redirects the user-agent back to the client using the + redirection URI provided earlier (in the request or during + client registration). The redirection URI includes an + authorization code and any local state provided by the client + earlier. + + (D) The client requests an access token from the authorization + server's token endpoint by including the authorization code + received in the previous step. When making the request, the + client authenticates with the authorization server. The client + includes the redirection URI used to obtain the authorization + code for verification. + + (E) The authorization server authenticates the client, validates the + authorization code, and ensures that the redirection URI + received matches the URI used to redirect the client in + step (C). If valid, the authorization server responds back with + an access token and, optionally, a refresh token. + + OAuth 2.0 public clients utilizing the Authorization Code Grant are + susceptible to the authorization code interception attack. + + A technique to mitigate against the threat through the use of Proof Key for Code + Exchange (PKCE, pronounced "pixy") is implemented in the current oauthlib + implementation. + + .. _`Authorization Code Grant`: https://tools.ietf.org/html/rfc6749#section-4.1 + .. _`PKCE`: https://tools.ietf.org/html/rfc7636 + """ + + default_response_mode = 'query' + response_types = ['code'] + + # This dict below is private because as RFC mention it: + # "S256" is Mandatory To Implement (MTI) on the server. + # + _code_challenge_methods = { + 'plain': code_challenge_method_plain, + 'S256': code_challenge_method_s256 + } + + def create_authorization_code(self, request): + """ + Generates an authorization grant represented as a dictionary. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + grant = {'code': common.generate_token()} + if hasattr(request, 'state') and request.state: + grant['state'] = request.state + log.debug('Created authorization code grant %r for request %r.', + grant, request) + return grant + + def create_authorization_response(self, request, token_handler): + """ + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format, per `Appendix B`_: + + response_type + REQUIRED. Value MUST be set to "code" for standard OAuth2 + authorization flow. For OpenID Connect it must be one of + "code token", "code id_token", or "code token id_token" - we + essentially test that "code" appears in the response_type. + client_id + REQUIRED. The client identifier as described in `Section 2.2`_. + redirect_uri + OPTIONAL. As described in `Section 3.1.2`_. + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + The client directs the resource owner to the constructed URI using an + HTTP redirection response, or by other means available to it via the + user-agent. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + :returns: headers, body, status + :raises: FatalClientError on invalid redirect URI or client id. + + A few examples:: + + >>> from your_validator import your_validator + >>> request = Request('https://example.com/authorize?client_id=valid' + ... '&redirect_uri=http%3A%2F%2Fclient.com%2F') + >>> from oauthlib.common import Request + >>> from oauthlib.oauth2 import AuthorizationCodeGrant, BearerToken + >>> token = BearerToken(your_validator) + >>> grant = AuthorizationCodeGrant(your_validator) + >>> request.scopes = ['authorized', 'in', 'some', 'form'] + >>> grant.create_authorization_response(request, token) + (u'http://client.com/?error=invalid_request&error_description=Missing+response_type+parameter.', None, None, 400) + >>> request = Request('https://example.com/authorize?client_id=valid' + ... '&redirect_uri=http%3A%2F%2Fclient.com%2F' + ... '&response_type=code') + >>> request.scopes = ['authorized', 'in', 'some', 'form'] + >>> grant.create_authorization_response(request, token) + (u'http://client.com/?code=u3F05aEObJuP2k7DordviIgW5wl52N', None, None, 200) + >>> # If the client id or redirect uri fails validation + >>> grant.create_authorization_response(request, token) + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "oauthlib/oauth2/rfc6749/grant_types.py", line 515, in create_authorization_response + >>> grant.create_authorization_response(request, token) + File "oauthlib/oauth2/rfc6749/grant_types.py", line 591, in validate_authorization_request + oauthlib.oauth2.rfc6749.errors.InvalidClientIdError + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + """ + try: + self.validate_authorization_request(request) + log.debug('Pre resource owner authorization validation ok for %r.', + request) + + # If the request fails due to a missing, invalid, or mismatching + # redirection URI, or if the client identifier is missing or invalid, + # the authorization server SHOULD inform the resource owner of the + # error and MUST NOT automatically redirect the user-agent to the + # invalid redirection URI. + except errors.FatalClientError as e: + log.debug('Fatal client error during validation of %r. %r.', + request, e) + raise + + # If the resource owner denies the access request or if the request + # fails for reasons other than a missing or invalid redirection URI, + # the authorization server informs the client by adding the following + # parameters to the query component of the redirection URI using the + # "application/x-www-form-urlencoded" format, per Appendix B: + # https://tools.ietf.org/html/rfc6749#appendix-B + except errors.OAuth2Error as e: + log.debug('Client error during validation of %r. %r.', request, e) + request.redirect_uri = request.redirect_uri or self.error_uri + redirect_uri = common.add_params_to_uri( + request.redirect_uri, e.twotuples, + fragment=request.response_mode == "fragment") + return {'Location': redirect_uri}, None, 302 + + grant = self.create_authorization_code(request) + for modifier in self._code_modifiers: + grant = modifier(grant, token_handler, request) + if 'access_token' in grant: + self.request_validator.save_token(grant, request) + log.debug('Saving grant %r for %r.', grant, request) + self.request_validator.save_authorization_code( + request.client_id, grant, request) + return self.prepare_authorization_response( + request, grant, {}, None, 302) + + def create_token_response(self, request, token_handler): + """Validate the authorization code. + + The client MUST NOT use the authorization code more than once. If an + authorization code is used more than once, the authorization server + MUST deny the request and SHOULD revoke (when possible) all tokens + previously issued based on that authorization code. The authorization + code is bound to the client identifier and redirection URI. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + """ + headers = self._get_default_headers() + try: + self.validate_token_request(request) + log.debug('Token request validation ok for %r.', request) + except errors.OAuth2Error as e: + log.debug('Client error during validation of %r. %r.', request, e) + headers.update(e.headers) + return headers, e.json, e.status_code + + token = token_handler.create_token(request, refresh_token=self.refresh_token) + + for modifier in self._token_modifiers: + token = modifier(token, token_handler, request) + + self.request_validator.save_token(token, request) + self.request_validator.invalidate_authorization_code( + request.client_id, request.code, request) + headers.update(self._create_cors_headers(request)) + return headers, json.dumps(token), 200 + + def validate_authorization_request(self, request): + """Check the authorization request for normal and fatal errors. + + A normal error could be a missing response_type parameter or the client + attempting to access scope it is not allowed to ask authorization for. + Normal errors can safely be included in the redirection URI and + sent back to the client. + + Fatal errors occur when the client_id or redirect_uri is invalid or + missing. These must be caught by the provider and handled, how this + is done is outside of the scope of OAuthLib but showing an error + page describing the issue is a good idea. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + + # First check for fatal errors + + # If the request fails due to a missing, invalid, or mismatching + # redirection URI, or if the client identifier is missing or invalid, + # the authorization server SHOULD inform the resource owner of the + # error and MUST NOT automatically redirect the user-agent to the + # invalid redirection URI. + + # First check duplicate parameters + for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'): + try: + duplicate_params = request.duplicate_params + except ValueError: + raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request) + if param in duplicate_params: + raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request) + + # REQUIRED. The client identifier as described in Section 2.2. + # https://tools.ietf.org/html/rfc6749#section-2.2 + if not request.client_id: + raise errors.MissingClientIdError(request=request) + + if not self.request_validator.validate_client_id(request.client_id, request): + raise errors.InvalidClientIdError(request=request) + + # OPTIONAL. As described in Section 3.1.2. + # https://tools.ietf.org/html/rfc6749#section-3.1.2 + log.debug('Validating redirection uri %s for client %s.', + request.redirect_uri, request.client_id) + + # OPTIONAL. As described in Section 3.1.2. + # https://tools.ietf.org/html/rfc6749#section-3.1.2 + self._handle_redirects(request) + + # Then check for normal errors. + + # If the resource owner denies the access request or if the request + # fails for reasons other than a missing or invalid redirection URI, + # the authorization server informs the client by adding the following + # parameters to the query component of the redirection URI using the + # "application/x-www-form-urlencoded" format, per Appendix B. + # https://tools.ietf.org/html/rfc6749#appendix-B + + # Note that the correct parameters to be added are automatically + # populated through the use of specific exceptions. + + request_info = {} + for validator in self.custom_validators.pre_auth: + request_info.update(validator(request)) + + # REQUIRED. + if request.response_type is None: + raise errors.MissingResponseTypeError(request=request) + # Value MUST be set to "code" or one of the OpenID authorization code including + # response_types "code token", "code id_token", "code token id_token" + elif not 'code' in request.response_type and request.response_type != 'none': + raise errors.UnsupportedResponseTypeError(request=request) + + if not self.request_validator.validate_response_type(request.client_id, + request.response_type, + request.client, request): + + log.debug('Client %s is not authorized to use response_type %s.', + request.client_id, request.response_type) + raise errors.UnauthorizedClientError(request=request) + + # OPTIONAL. Validate PKCE request or reply with "error"/"invalid_request" + # https://tools.ietf.org/html/rfc6749#section-4.4.1 + if self.request_validator.is_pkce_required(request.client_id, request) is True: + if request.code_challenge is None: + raise errors.MissingCodeChallengeError(request=request) + + if request.code_challenge is not None: + request_info["code_challenge"] = request.code_challenge + + # OPTIONAL, defaults to "plain" if not present in the request. + if request.code_challenge_method is None: + request.code_challenge_method = "plain" + + if request.code_challenge_method not in self._code_challenge_methods: + raise errors.UnsupportedCodeChallengeMethodError(request=request) + request_info["code_challenge_method"] = request.code_challenge_method + + # OPTIONAL. The scope of the access request as described by Section 3.3 + # https://tools.ietf.org/html/rfc6749#section-3.3 + self.validate_scopes(request) + + request_info.update({ + 'client_id': request.client_id, + 'redirect_uri': request.redirect_uri, + 'response_type': request.response_type, + 'state': request.state, + 'request': request + }) + + for validator in self.custom_validators.post_auth: + request_info.update(validator(request)) + + return request.scopes, request_info + + def validate_token_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + # REQUIRED. Value MUST be set to "authorization_code". + if request.grant_type not in ('authorization_code', 'openid'): + raise errors.UnsupportedGrantTypeError(request=request) + + for validator in self.custom_validators.pre_token: + validator(request) + + if request.code is None: + raise errors.InvalidRequestError( + description='Missing code parameter.', request=request) + + for param in ('client_id', 'grant_type', 'redirect_uri'): + if param in request.duplicate_params: + raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param, + request=request) + + if self.request_validator.client_authentication_required(request): + # If the client type is confidential or the client was issued client + # credentials (or assigned other authentication requirements), the + # client MUST authenticate with the authorization server as described + # in Section 3.2.1. + # https://tools.ietf.org/html/rfc6749#section-3.2.1 + if not self.request_validator.authenticate_client(request): + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + elif not self.request_validator.authenticate_client_id(request.client_id, request): + # REQUIRED, if the client is not authenticating with the + # authorization server as described in Section 3.2.1. + # https://tools.ietf.org/html/rfc6749#section-3.2.1 + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + + if not hasattr(request.client, 'client_id'): + raise NotImplementedError('Authenticate client must set the ' + 'request.client.client_id attribute ' + 'in authenticate_client.') + + request.client_id = request.client_id or request.client.client_id + + # Ensure client is authorized use of this grant type + self.validate_grant_type(request) + + # REQUIRED. The authorization code received from the + # authorization server. + if not self.request_validator.validate_code(request.client_id, + request.code, request.client, request): + log.debug('Client, %r (%r), is not allowed access to scopes %r.', + request.client_id, request.client, request.scopes) + raise errors.InvalidGrantError(request=request) + + # OPTIONAL. Validate PKCE code_verifier + challenge = self.request_validator.get_code_challenge(request.code, request) + + if challenge is not None: + if request.code_verifier is None: + raise errors.MissingCodeVerifierError(request=request) + + challenge_method = self.request_validator.get_code_challenge_method(request.code, request) + if challenge_method is None: + raise errors.InvalidGrantError(request=request, description="Challenge method not found") + + if challenge_method not in self._code_challenge_methods: + raise errors.ServerError( + description="code_challenge_method {} is not supported.".format(challenge_method), + request=request + ) + + if not self.validate_code_challenge(challenge, + challenge_method, + request.code_verifier): + log.debug('request provided a invalid code_verifier.') + raise errors.InvalidGrantError(request=request) + elif self.request_validator.is_pkce_required(request.client_id, request) is True: + if request.code_verifier is None: + raise errors.MissingCodeVerifierError(request=request) + raise errors.InvalidGrantError(request=request, description="Challenge not found") + + for attr in ('user', 'scopes'): + if getattr(request, attr, None) is None: + log.debug('request.%s was not set on code validation.', attr) + + # REQUIRED, if the "redirect_uri" parameter was included in the + # authorization request as described in Section 4.1.1, and their + # values MUST be identical. + if request.redirect_uri is None: + request.using_default_redirect_uri = True + request.redirect_uri = self.request_validator.get_default_redirect_uri( + request.client_id, request) + log.debug('Using default redirect_uri %s.', request.redirect_uri) + if not request.redirect_uri: + raise errors.MissingRedirectURIError(request=request) + else: + request.using_default_redirect_uri = False + log.debug('Using provided redirect_uri %s', request.redirect_uri) + + if not self.request_validator.confirm_redirect_uri(request.client_id, request.code, + request.redirect_uri, request.client, + request): + log.debug('Redirect_uri (%r) invalid for client %r (%r).', + request.redirect_uri, request.client_id, request.client) + raise errors.MismatchingRedirectURIError(request=request) + + for validator in self.custom_validators.post_token: + validator(request) + + def validate_code_challenge(self, challenge, challenge_method, verifier): + if challenge_method in self._code_challenge_methods: + return self._code_challenge_methods[challenge_method](verifier, challenge) + raise NotImplementedError('Unknown challenge_method %s' % challenge_method) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/base.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/base.py new file mode 100644 index 0000000000000000000000000000000000000000..ca343a1193ecb0eda2b8c37cbe00a5b71ee2b859 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/base.py @@ -0,0 +1,268 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging +from itertools import chain + +from oauthlib.common import add_params_to_uri +from oauthlib.oauth2.rfc6749 import errors, utils +from oauthlib.uri_validate import is_absolute_uri + +from ..request_validator import RequestValidator +from ..utils import is_secure_transport + +log = logging.getLogger(__name__) + + +class ValidatorsContainer: + """ + Container object for holding custom validator callables to be invoked + as part of the grant type `validate_authorization_request()` or + `validate_authorization_request()` methods on the various grant types. + + Authorization validators must be callables that take a request object and + return a dict, which may contain items to be added to the `request_info` + returned from the grant_type after validation. + + Token validators must be callables that take a request object and + return None. + + Both authorization validators and token validators may raise OAuth2 + exceptions if validation conditions fail. + + Authorization validators added to `pre_auth` will be run BEFORE + the standard validations (but after the critical ones that raise + fatal errors) as part of `validate_authorization_request()` + + Authorization validators added to `post_auth` will be run AFTER + the standard validations as part of `validate_authorization_request()` + + Token validators added to `pre_token` will be run BEFORE + the standard validations as part of `validate_token_request()` + + Token validators added to `post_token` will be run AFTER + the standard validations as part of `validate_token_request()` + + For example: + + >>> def my_auth_validator(request): + ... return {'myval': True} + >>> auth_code_grant = AuthorizationCodeGrant(request_validator) + >>> auth_code_grant.custom_validators.pre_auth.append(my_auth_validator) + >>> def my_token_validator(request): + ... if not request.everything_okay: + ... raise errors.OAuth2Error("uh-oh") + >>> auth_code_grant.custom_validators.post_token.append(my_token_validator) + """ + + def __init__(self, post_auth, post_token, + pre_auth, pre_token): + self.pre_auth = pre_auth + self.post_auth = post_auth + self.pre_token = pre_token + self.post_token = post_token + + @property + def all_pre(self): + return chain(self.pre_auth, self.pre_token) + + @property + def all_post(self): + return chain(self.post_auth, self.post_token) + + +class GrantTypeBase: + error_uri = None + request_validator = None + default_response_mode = 'fragment' + refresh_token = True + response_types = ['code'] + + def __init__(self, request_validator=None, **kwargs): + self.request_validator = request_validator or RequestValidator() + + # Transforms class variables into instance variables: + self.response_types = self.response_types + self.refresh_token = self.refresh_token + self._setup_custom_validators(kwargs) + self._code_modifiers = [] + self._token_modifiers = [] + + for kw, val in kwargs.items(): + setattr(self, kw, val) + + def _setup_custom_validators(self, kwargs): + post_auth = kwargs.get('post_auth', []) + post_token = kwargs.get('post_token', []) + pre_auth = kwargs.get('pre_auth', []) + pre_token = kwargs.get('pre_token', []) + if not hasattr(self, 'validate_authorization_request'): + if post_auth or pre_auth: + msg = ("{} does not support authorization validators. Use " + "token validators instead.").format(self.__class__.__name__) + raise ValueError(msg) + # Using tuples here because they can't be appended to: + post_auth, pre_auth = (), () + self.custom_validators = ValidatorsContainer(post_auth, post_token, + pre_auth, pre_token) + + def register_response_type(self, response_type): + self.response_types.append(response_type) + + def register_code_modifier(self, modifier): + self._code_modifiers.append(modifier) + + def register_token_modifier(self, modifier): + self._token_modifiers.append(modifier) + + def create_authorization_response(self, request, token_handler): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + """ + raise NotImplementedError('Subclasses must implement this method.') + + def create_token_response(self, request, token_handler): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + """ + raise NotImplementedError('Subclasses must implement this method.') + + def add_token(self, token, token_handler, request): + """ + :param token: + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + # Only add a hybrid access token on auth step if asked for + if not request.response_type in ["token", "code token", "id_token token", "code id_token token"]: + return token + + token.update(token_handler.create_token(request, refresh_token=False)) + return token + + def validate_grant_type(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + client_id = getattr(request, 'client_id', None) + if not self.request_validator.validate_grant_type(client_id, + request.grant_type, request.client, request): + log.debug('Unauthorized from %r (%r) access to grant type %s.', + request.client_id, request.client, request.grant_type) + raise errors.UnauthorizedClientError(request=request) + + def validate_scopes(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + if not request.scopes: + request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list( + self.request_validator.get_default_scopes(request.client_id, request)) + log.debug('Validating access to scopes %r for client %r (%r).', + request.scopes, request.client_id, request.client) + if not self.request_validator.validate_scopes(request.client_id, + request.scopes, request.client, request): + raise errors.InvalidScopeError(request=request) + + def prepare_authorization_response(self, request, token, headers, body, status): + """Place token according to response mode. + + Base classes can define a default response mode for their authorization + response by overriding the static `default_response_mode` member. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token: + :param headers: + :param body: + :param status: + """ + request.response_mode = request.response_mode or self.default_response_mode + + if request.response_mode not in ('query', 'fragment'): + log.debug('Overriding invalid response mode %s with %s', + request.response_mode, self.default_response_mode) + request.response_mode = self.default_response_mode + + token_items = token.items() + + if request.response_type == 'none': + state = token.get('state', None) + if state: + token_items = [('state', state)] + else: + token_items = [] + + if request.response_mode == 'query': + headers['Location'] = add_params_to_uri( + request.redirect_uri, token_items, fragment=False) + return headers, body, status + + if request.response_mode == 'fragment': + headers['Location'] = add_params_to_uri( + request.redirect_uri, token_items, fragment=True) + return headers, body, status + + raise NotImplementedError( + 'Subclasses must set a valid default_response_mode') + + def _get_default_headers(self): + """Create default headers for grant responses.""" + return { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store', + 'Pragma': 'no-cache', + } + + def _handle_redirects(self, request): + if request.redirect_uri is not None: + request.using_default_redirect_uri = False + log.debug('Using provided redirect_uri %s', request.redirect_uri) + if not is_absolute_uri(request.redirect_uri): + raise errors.InvalidRedirectURIError(request=request) + + # The authorization server MUST verify that the redirection URI + # to which it will redirect the access token matches a + # redirection URI registered by the client as described in + # Section 3.1.2. + # https://tools.ietf.org/html/rfc6749#section-3.1.2 + if not self.request_validator.validate_redirect_uri( + request.client_id, request.redirect_uri, request): + raise errors.MismatchingRedirectURIError(request=request) + else: + request.redirect_uri = self.request_validator.get_default_redirect_uri( + request.client_id, request) + request.using_default_redirect_uri = True + log.debug('Using default redirect_uri %s.', request.redirect_uri) + if not request.redirect_uri: + raise errors.MissingRedirectURIError(request=request) + if not is_absolute_uri(request.redirect_uri): + raise errors.InvalidRedirectURIError(request=request) + + def _create_cors_headers(self, request): + """If CORS is allowed, create the appropriate headers.""" + if 'origin' not in request.headers: + return {} + + origin = request.headers['origin'] + if not is_secure_transport(origin): + log.debug('Origin "%s" is not HTTPS, CORS not allowed.', origin) + return {} + elif not self.request_validator.is_origin_allowed( + request.client_id, origin, request): + log.debug('Invalid origin "%s", CORS not allowed.', origin) + return {} + else: + log.debug('Valid origin "%s", injecting CORS headers.', origin) + return {'Access-Control-Allow-Origin': origin} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py new file mode 100644 index 0000000000000000000000000000000000000000..e7b46189777bf4ef32e5f512cb668aec1c8f1ea9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py @@ -0,0 +1,123 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import json +import logging + +from .. import errors +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class ClientCredentialsGrant(GrantTypeBase): + + """`Client Credentials Grant`_ + + The client can request an access token using only its client + credentials (or other supported means of authentication) when the + client is requesting access to the protected resources under its + control, or those of another resource owner that have been previously + arranged with the authorization server (the method of which is beyond + the scope of this specification). + + The client credentials grant type MUST only be used by confidential + clients:: + + +---------+ +---------------+ + : : : : + : :>-- A - Client Authentication --->: Authorization : + : Client : : Server : + : :<-- B ---- Access Token ---------<: : + : : : : + +---------+ +---------------+ + + Figure 6: Client Credentials Flow + + The flow illustrated in Figure 6 includes the following steps: + + (A) The client authenticates with the authorization server and + requests an access token from the token endpoint. + + (B) The authorization server authenticates the client, and if valid, + issues an access token. + + .. _`Client Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.4 + """ + + def create_token_response(self, request, token_handler): + """Return token or error in JSON format. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + If the access token request is valid and authorized, the + authorization server issues an access token as described in + `Section 5.1`_. A refresh token SHOULD NOT be included. If the request + failed client authentication or is invalid, the authorization server + returns an error response as described in `Section 5.2`_. + + .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 + .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 + """ + headers = self._get_default_headers() + try: + log.debug('Validating access token request, %r.', request) + self.validate_token_request(request) + except errors.OAuth2Error as e: + log.debug('Client error in token request. %s.', e) + headers.update(e.headers) + return headers, e.json, e.status_code + + token = token_handler.create_token(request, refresh_token=False) + + for modifier in self._token_modifiers: + token = modifier(token) + + self.request_validator.save_token(token, request) + + log.debug('Issuing token to client id %r (%r), %r.', + request.client_id, request.client, token) + return headers, json.dumps(token), 200 + + def validate_token_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + for validator in self.custom_validators.pre_token: + validator(request) + + if not getattr(request, 'grant_type', None): + raise errors.InvalidRequestError('Request is missing grant type.', + request=request) + + if not request.grant_type == 'client_credentials': + raise errors.UnsupportedGrantTypeError(request=request) + + for param in ('grant_type', 'scope'): + if param in request.duplicate_params: + raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param, + request=request) + + log.debug('Authenticating client, %r.', request) + if not self.request_validator.authenticate_client(request): + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + else: + if not hasattr(request.client, 'client_id'): + raise NotImplementedError('Authenticate client must set the ' + 'request.client.client_id attribute ' + 'in authenticate_client.') + # Ensure client is authorized use of this grant type + self.validate_grant_type(request) + + request.client_id = request.client_id or request.client.client_id + log.debug('Authorizing access to client %r.', request.client_id) + self.validate_scopes(request) + + for validator in self.custom_validators.post_token: + validator(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/implicit.py new file mode 100644 index 0000000000000000000000000000000000000000..6110b6f3379114145d7b830bdaa77e405ea9eb0d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/implicit.py @@ -0,0 +1,376 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib import common + +from .. import errors +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class ImplicitGrant(GrantTypeBase): + + """`Implicit Grant`_ + + The implicit grant type is used to obtain access tokens (it does not + support the issuance of refresh tokens) and is optimized for public + clients known to operate a particular redirection URI. These clients + are typically implemented in a browser using a scripting language + such as JavaScript. + + Unlike the authorization code grant type, in which the client makes + separate requests for authorization and for an access token, the + client receives the access token as the result of the authorization + request. + + The implicit grant type does not include client authentication, and + relies on the presence of the resource owner and the registration of + the redirection URI. Because the access token is encoded into the + redirection URI, it may be exposed to the resource owner and other + applications residing on the same device:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + ^ + | + (B) + +----|-----+ Client Identifier +---------------+ + | -+----(A)-- & Redirection URI --->| | + | User- | | Authorization | + | Agent -|----(B)-- User authenticates -->| Server | + | | | | + | |<---(C)--- Redirection URI ----<| | + | | with Access Token +---------------+ + | | in Fragment + | | +---------------+ + | |----(D)--- Redirection URI ---->| Web-Hosted | + | | without Fragment | Client | + | | | Resource | + | (F) |<---(E)------- Script ---------<| | + | | +---------------+ + +-|--------+ + | | + (A) (G) Access Token + | | + ^ v + +---------+ + | | + | Client | + | | + +---------+ + + Note: The lines illustrating steps (A) and (B) are broken into two + parts as they pass through the user-agent. + + Figure 4: Implicit Grant Flow + + The flow illustrated in Figure 4 includes the following steps: + + (A) The client initiates the flow by directing the resource owner's + user-agent to the authorization endpoint. The client includes + its client identifier, requested scope, local state, and a + redirection URI to which the authorization server will send the + user-agent back once access is granted (or denied). + + (B) The authorization server authenticates the resource owner (via + the user-agent) and establishes whether the resource owner + grants or denies the client's access request. + + (C) Assuming the resource owner grants access, the authorization + server redirects the user-agent back to the client using the + redirection URI provided earlier. The redirection URI includes + the access token in the URI fragment. + + (D) The user-agent follows the redirection instructions by making a + request to the web-hosted client resource (which does not + include the fragment per [RFC2616]). The user-agent retains the + fragment information locally. + + (E) The web-hosted client resource returns a web page (typically an + HTML document with an embedded script) capable of accessing the + full redirection URI including the fragment retained by the + user-agent, and extracting the access token (and other + parameters) contained in the fragment. + + (F) The user-agent executes the script provided by the web-hosted + client resource locally, which extracts the access token. + + (G) The user-agent passes the access token to the client. + + See `Section 10.3`_ and `Section 10.16`_ for important security considerations + when using the implicit grant. + + .. _`Implicit Grant`: https://tools.ietf.org/html/rfc6749#section-4.2 + .. _`Section 10.3`: https://tools.ietf.org/html/rfc6749#section-10.3 + .. _`Section 10.16`: https://tools.ietf.org/html/rfc6749#section-10.16 + """ + + response_types = ['token'] + grant_allows_refresh_token = False + + def create_authorization_response(self, request, token_handler): + """Create an authorization response. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format, per `Appendix B`_: + + response_type + REQUIRED. Value MUST be set to "token" for standard OAuth2 implicit flow + or "id_token token" or just "id_token" for OIDC implicit flow + + client_id + REQUIRED. The client identifier as described in `Section 2.2`_. + + redirect_uri + OPTIONAL. As described in `Section 3.1.2`_. + + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + The authorization server validates the request to ensure that all + required parameters are present and valid. The authorization server + MUST verify that the redirection URI to which it will redirect the + access token matches a redirection URI registered by the client as + described in `Section 3.1.2`_. + + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + """ + return self.create_token_response(request, token_handler) + + def create_token_response(self, request, token_handler): + """Return token or error embedded in the URI fragment. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the "application/x-www-form-urlencoded" format, per + `Appendix B`_: + + access_token + REQUIRED. The access token issued by the authorization server. + + token_type + REQUIRED. The type of the token issued as described in + `Section 7.1`_. Value is case insensitive. + + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + scope + OPTIONAL, if identical to the scope requested by the client; + otherwise, REQUIRED. The scope of the access token as + described by `Section 3.3`_. + + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + The authorization server MUST NOT issue a refresh token. + + .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 + """ + try: + self.validate_token_request(request) + + # If the request fails due to a missing, invalid, or mismatching + # redirection URI, or if the client identifier is missing or invalid, + # the authorization server SHOULD inform the resource owner of the + # error and MUST NOT automatically redirect the user-agent to the + # invalid redirection URI. + except errors.FatalClientError as e: + log.debug('Fatal client error during validation of %r. %r.', + request, e) + raise + + # If the resource owner denies the access request or if the request + # fails for reasons other than a missing or invalid redirection URI, + # the authorization server informs the client by adding the following + # parameters to the fragment component of the redirection URI using the + # "application/x-www-form-urlencoded" format, per Appendix B: + # https://tools.ietf.org/html/rfc6749#appendix-B + except errors.OAuth2Error as e: + log.debug('Client error during validation of %r. %r.', request, e) + return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples, + fragment=True)}, None, 302 + + # In OIDC implicit flow it is possible to have a request_type that does not include the access_token! + # "id_token token" - return the access token and the id token + # "id_token" - don't return the access token + if "token" in request.response_type.split(): + token = token_handler.create_token(request, refresh_token=False) + else: + token = {} + + if request.state is not None: + token['state'] = request.state + + for modifier in self._token_modifiers: + token = modifier(token, token_handler, request) + + # In OIDC implicit flow it is possible to have a request_type that does + # not include the access_token! In this case there is no need to save a token. + if "token" in request.response_type.split(): + self.request_validator.save_token(token, request) + + return self.prepare_authorization_response( + request, token, {}, None, 302) + + def validate_authorization_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + return self.validate_token_request(request) + + def validate_token_request(self, request): + """Check the token request for normal and fatal errors. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + This method is very similar to validate_authorization_request in + the AuthorizationCodeGrant but differ in a few subtle areas. + + A normal error could be a missing response_type parameter or the client + attempting to access scope it is not allowed to ask authorization for. + Normal errors can safely be included in the redirection URI and + sent back to the client. + + Fatal errors occur when the client_id or redirect_uri is invalid or + missing. These must be caught by the provider and handled, how this + is done is outside of the scope of OAuthLib but showing an error + page describing the issue is a good idea. + """ + + # First check for fatal errors + + # If the request fails due to a missing, invalid, or mismatching + # redirection URI, or if the client identifier is missing or invalid, + # the authorization server SHOULD inform the resource owner of the + # error and MUST NOT automatically redirect the user-agent to the + # invalid redirection URI. + + # First check duplicate parameters + for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'): + try: + duplicate_params = request.duplicate_params + except ValueError: + raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request) + if param in duplicate_params: + raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request) + + # REQUIRED. The client identifier as described in Section 2.2. + # https://tools.ietf.org/html/rfc6749#section-2.2 + if not request.client_id: + raise errors.MissingClientIdError(request=request) + + if not self.request_validator.validate_client_id(request.client_id, request): + raise errors.InvalidClientIdError(request=request) + + # OPTIONAL. As described in Section 3.1.2. + # https://tools.ietf.org/html/rfc6749#section-3.1.2 + self._handle_redirects(request) + + # Then check for normal errors. + + request_info = self._run_custom_validators(request, + self.custom_validators.all_pre) + + # If the resource owner denies the access request or if the request + # fails for reasons other than a missing or invalid redirection URI, + # the authorization server informs the client by adding the following + # parameters to the fragment component of the redirection URI using the + # "application/x-www-form-urlencoded" format, per Appendix B. + # https://tools.ietf.org/html/rfc6749#appendix-B + + # Note that the correct parameters to be added are automatically + # populated through the use of specific exceptions + + # REQUIRED. + if request.response_type is None: + raise errors.MissingResponseTypeError(request=request) + # Value MUST be one of our registered types: "token" by default or if using OIDC "id_token" or "id_token token" + elif not set(request.response_type.split()).issubset(self.response_types): + raise errors.UnsupportedResponseTypeError(request=request) + + log.debug('Validating use of response_type token for client %r (%r).', + request.client_id, request.client) + if not self.request_validator.validate_response_type(request.client_id, + request.response_type, + request.client, request): + + log.debug('Client %s is not authorized to use response_type %s.', + request.client_id, request.response_type) + raise errors.UnauthorizedClientError(request=request) + + # OPTIONAL. The scope of the access request as described by Section 3.3 + # https://tools.ietf.org/html/rfc6749#section-3.3 + self.validate_scopes(request) + + request_info.update({ + 'client_id': request.client_id, + 'redirect_uri': request.redirect_uri, + 'response_type': request.response_type, + 'state': request.state, + 'request': request, + }) + + request_info = self._run_custom_validators( + request, + self.custom_validators.all_post, + request_info + ) + + return request.scopes, request_info + + def _run_custom_validators(self, + request, + validations, + request_info=None): + # Make a copy so we don't modify the existing request_info dict + request_info = {} if request_info is None else request_info.copy() + # For implicit grant, auth_validators and token_validators are + # basically equivalent since the token is returned from the + # authorization endpoint. + for validator in validations: + result = validator(request) + if result is not None: + request_info.update(result) + return request_info diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py new file mode 100644 index 0000000000000000000000000000000000000000..ce33df0e7d67de98f9578dbd9c49dcf9046d4c9b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py @@ -0,0 +1,136 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import json +import logging + +from .. import errors, utils +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class RefreshTokenGrant(GrantTypeBase): + + """`Refresh token grant`_ + + .. _`Refresh token grant`: https://tools.ietf.org/html/rfc6749#section-6 + """ + + def __init__(self, request_validator=None, + issue_new_refresh_tokens=True, + **kwargs): + super().__init__( + request_validator, + issue_new_refresh_tokens=issue_new_refresh_tokens, + **kwargs) + + def create_token_response(self, request, token_handler): + """Create a new access token from a refresh_token. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + If valid and authorized, the authorization server issues an access + token as described in `Section 5.1`_. If the request failed + verification or is invalid, the authorization server returns an error + response as described in `Section 5.2`_. + + The authorization server MAY issue a new refresh token, in which case + the client MUST discard the old refresh token and replace it with the + new refresh token. The authorization server MAY revoke the old + refresh token after issuing a new refresh token to the client. If a + new refresh token is issued, the refresh token scope MUST be + identical to that of the refresh token included by the client in the + request. + + .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 + .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 + """ + headers = self._get_default_headers() + try: + log.debug('Validating refresh token request, %r.', request) + self.validate_token_request(request) + except errors.OAuth2Error as e: + log.debug('Client error in token request, %s.', e) + headers.update(e.headers) + return headers, e.json, e.status_code + + token = token_handler.create_token(request, + refresh_token=self.issue_new_refresh_tokens) + + for modifier in self._token_modifiers: + token = modifier(token, token_handler, request) + + self.request_validator.save_token(token, request) + + log.debug('Issuing new token to client id %r (%r), %r.', + request.client_id, request.client, token) + headers.update(self._create_cors_headers(request)) + return headers, json.dumps(token), 200 + + def validate_token_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + # REQUIRED. Value MUST be set to "refresh_token". + if request.grant_type != 'refresh_token': + raise errors.UnsupportedGrantTypeError(request=request) + + for validator in self.custom_validators.pre_token: + validator(request) + + if request.refresh_token is None: + raise errors.InvalidRequestError( + description='Missing refresh token parameter.', + request=request) + + # Because refresh tokens are typically long-lasting credentials used to + # request additional access tokens, the refresh token is bound to the + # client to which it was issued. If the client type is confidential or + # the client was issued client credentials (or assigned other + # authentication requirements), the client MUST authenticate with the + # authorization server as described in Section 3.2.1. + # https://tools.ietf.org/html/rfc6749#section-3.2.1 + if self.request_validator.client_authentication_required(request): + log.debug('Authenticating client, %r.', request) + if not self.request_validator.authenticate_client(request): + log.debug('Invalid client (%r), denying access.', request) + raise errors.InvalidClientError(request=request) + elif not self.request_validator.authenticate_client_id(request.client_id, request): + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + + # Ensure client is authorized use of this grant type + self.validate_grant_type(request) + + # REQUIRED. The refresh token issued to the client. + log.debug('Validating refresh token %s for client %r.', + request.refresh_token, request.client) + if not self.request_validator.validate_refresh_token( + request.refresh_token, request.client, request): + log.debug('Invalid refresh token, %s, for client %r.', + request.refresh_token, request.client) + raise errors.InvalidGrantError(request=request) + + original_scopes = utils.scope_to_list( + self.request_validator.get_original_scopes( + request.refresh_token, request)) + + if request.scope: + request.scopes = utils.scope_to_list(request.scope) + if (not all(s in original_scopes for s in request.scopes) + and not self.request_validator.is_within_original_scope( + request.scopes, request.refresh_token, request)): + log.debug('Refresh token %s lack requested scopes, %r.', + request.refresh_token, request.scopes) + raise errors.InvalidScopeError(request=request) + else: + request.scopes = original_scopes + + for validator in self.custom_validators.post_token: + validator(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py new file mode 100644 index 0000000000000000000000000000000000000000..4b0de5bf6f42d1b923c9dace8ba4624fd797b0b6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py @@ -0,0 +1,199 @@ +""" +oauthlib.oauth2.rfc6749.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import json +import logging + +from .. import errors +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase): + + """`Resource Owner Password Credentials Grant`_ + + The resource owner password credentials grant type is suitable in + cases where the resource owner has a trust relationship with the + client, such as the device operating system or a highly privileged + application. The authorization server should take special care when + enabling this grant type and only allow it when other flows are not + viable. + + This grant type is suitable for clients capable of obtaining the + resource owner's credentials (username and password, typically using + an interactive form). It is also used to migrate existing clients + using direct authentication schemes such as HTTP Basic or Digest + authentication to OAuth by converting the stored credentials to an + access token:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + v + | Resource Owner + (A) Password Credentials + | + v + +---------+ +---------------+ + | |>--(B)---- Resource Owner ------->| | + | | Password Credentials | Authorization | + | Client | | Server | + | |<--(C)---- Access Token ---------<| | + | | (w/ Optional Refresh Token) | | + +---------+ +---------------+ + + Figure 5: Resource Owner Password Credentials Flow + + The flow illustrated in Figure 5 includes the following steps: + + (A) The resource owner provides the client with its username and + password. + + (B) The client requests an access token from the authorization + server's token endpoint by including the credentials received + from the resource owner. When making the request, the client + authenticates with the authorization server. + + (C) The authorization server authenticates the client and validates + the resource owner credentials, and if valid, issues an access + token. + + .. _`Resource Owner Password Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.3 + """ + + def create_token_response(self, request, token_handler): + """Return token or error in json format. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param token_handler: A token handler instance, for example of type + oauthlib.oauth2.BearerToken. + + If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in `Section 5.1`_. If the request failed client + authentication or is invalid, the authorization server returns an + error response as described in `Section 5.2`_. + + .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 + .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 + """ + headers = self._get_default_headers() + try: + if self.request_validator.client_authentication_required(request): + log.debug('Authenticating client, %r.', request) + if not self.request_validator.authenticate_client(request): + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + elif not self.request_validator.authenticate_client_id(request.client_id, request): + log.debug('Client authentication failed, %r.', request) + raise errors.InvalidClientError(request=request) + log.debug('Validating access token request, %r.', request) + self.validate_token_request(request) + except errors.OAuth2Error as e: + log.debug('Client error in token request, %s.', e) + headers.update(e.headers) + return headers, e.json, e.status_code + + token = token_handler.create_token(request, self.refresh_token) + + for modifier in self._token_modifiers: + token = modifier(token) + + self.request_validator.save_token(token, request) + + log.debug('Issuing token %r to client id %r (%r) and username %s.', + token, request.client_id, request.client, request.username) + return headers, json.dumps(token), 200 + + def validate_token_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per Appendix B with a character encoding of UTF-8 in the HTTP + request entity-body: + + grant_type + REQUIRED. Value MUST be set to "password". + + username + REQUIRED. The resource owner username. + + password + REQUIRED. The resource owner password. + + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + If the client type is confidential or the client was issued client + credentials (or assigned other authentication requirements), the + client MUST authenticate with the authorization server as described + in `Section 3.2.1`_. + + The authorization server MUST: + + o require client authentication for confidential clients or for any + client that was issued client credentials (or with other + authentication requirements), + + o authenticate the client if client authentication is included, and + + o validate the resource owner password credentials using its + existing password validation algorithm. + + Since this access token request utilizes the resource owner's + password, the authorization server MUST protect the endpoint against + brute force attacks (e.g., using rate-limitation or generating + alerts). + + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1 + """ + for validator in self.custom_validators.pre_token: + validator(request) + + for param in ('grant_type', 'username', 'password'): + if not getattr(request, param, None): + raise errors.InvalidRequestError( + 'Request is missing %s parameter.' % param, request=request) + + for param in ('grant_type', 'username', 'password', 'scope'): + if param in request.duplicate_params: + raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param, request=request) + + # This error should rarely (if ever) occur if requests are routed to + # grant type handlers based on the grant_type parameter. + if not request.grant_type == 'password': + raise errors.UnsupportedGrantTypeError(request=request) + + log.debug('Validating username %s.', request.username) + if not self.request_validator.validate_user(request.username, + request.password, request.client, request): + raise errors.InvalidGrantError( + 'Invalid credentials given.', request=request) + else: + if not hasattr(request.client, 'client_id'): + raise NotImplementedError( + 'Validate user must set the ' + 'request.client.client_id attribute ' + 'in authenticate_client.') + log.debug('Authorizing access to user %r.', request.user) + + # Ensure client is authorized use of this grant type + self.validate_grant_type(request) + + if request.client: + request.client_id = request.client_id or request.client.client_id + self.validate_scopes(request) + + for validator in self.custom_validators.post_token: + validator(request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/parameters.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/parameters.py new file mode 100644 index 0000000000000000000000000000000000000000..8f6ce2c7fc4f7111928d5387d98b735825f048f3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/parameters.py @@ -0,0 +1,471 @@ +""" +oauthlib.oauth2.rfc6749.parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods related to `Section 4`_ of the OAuth 2 RFC. + +.. _`Section 4`: https://tools.ietf.org/html/rfc6749#section-4 +""" +import json +import os +import time +import urllib.parse as urlparse + +from oauthlib.common import add_params_to_qs, add_params_to_uri +from oauthlib.signals import scope_changed + +from .errors import ( + InsecureTransportError, MismatchingStateError, MissingCodeError, + MissingTokenError, MissingTokenTypeError, raise_from_error, +) +from .tokens import OAuth2Token +from .utils import is_secure_transport, list_to_scope, scope_to_list + + +def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None, + scope=None, state=None, code_challenge=None, code_challenge_method='plain', **kwargs): + """Prepare the authorization grant request URI. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the ``application/x-www-form-urlencoded`` format as defined by + [`W3C.REC-html401-19991224`_]: + + :param uri: + :param client_id: The client identifier as described in `Section 2.2`_. + :param response_type: To indicate which OAuth 2 grant/flow is required, + "code" and "token". + :param redirect_uri: The client provided URI to redirect back to after + authorization as described in `Section 3.1.2`_. + :param scope: The scope of the access request as described by + `Section 3.3`_. + :param state: An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent + back to the client. The parameter SHOULD be used for + preventing cross-site request forgery as described in + `Section 10.12`_. + :param code_challenge: PKCE parameter. A challenge derived from the + code_verifier that is sent in the authorization + request, to be verified against later. + :param code_challenge_method: PKCE parameter. A method that was used to derive the + code_challenge. Defaults to "plain" if not present in the request. + :param kwargs: Extra arguments to embed in the grant/authorization URL. + + An example of an authorization code grant authorization URL: + + .. code-block:: http + + GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz + &code_challenge=kjasBS523KdkAILD2k78NdcJSk2k3KHG6&code_challenge_method=S256 + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 + Host: server.example.com + + .. _`W3C.REC-html401-19991224`: https://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224 + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + """ + if not is_secure_transport(uri): + raise InsecureTransportError() + + params = [(('response_type', response_type)), + (('client_id', client_id))] + + if redirect_uri: + params.append(('redirect_uri', redirect_uri)) + if scope: + params.append(('scope', list_to_scope(scope))) + if state: + params.append(('state', state)) + if code_challenge is not None: + params.append(('code_challenge', code_challenge)) + params.append(('code_challenge_method', code_challenge_method)) + + for k in kwargs: + if kwargs[k]: + params.append((str(k), kwargs[k])) + + return add_params_to_uri(uri, params) + + +def prepare_token_request(grant_type, body='', include_client_id=True, code_verifier=None, **kwargs): + """Prepare the access token request. + + The client makes a request to the token endpoint by adding the + following parameters using the ``application/x-www-form-urlencoded`` + format in the HTTP request entity-body: + + :param grant_type: To indicate grant type being used, i.e. "password", + "authorization_code" or "client_credentials". + + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + + :param include_client_id: `True` (default) to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in + `Section 3.2.1`_. + :type include_client_id: Boolean + + :param client_id: Unicode client identifier. Will only appear if + `include_client_id` is True. * + + :param client_secret: Unicode client secret. Will only appear if set to a + value that is not `None`. Invoking this function with + an empty string will send an empty `client_secret` + value to the server. * + + :param code: If using authorization_code grant, pass the previously + obtained authorization code as the ``code`` argument. * + + :param redirect_uri: If the "redirect_uri" parameter was included in the + authorization request as described in + `Section 4.1.1`_, and their values MUST be identical. * + + :param code_verifier: PKCE parameter. A cryptographically random string that is used to correlate the + authorization request to the token request. + + :param kwargs: Extra arguments to embed in the request body. + + Parameters marked with a `*` above are not explicit arguments in the + function signature, but are specially documented arguments for items + appearing in the generic `**kwargs` keyworded input. + + An example of an authorization code token request body: + + .. code-block:: http + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1 + """ + params = [('grant_type', grant_type)] + + if 'scope' in kwargs: + kwargs['scope'] = list_to_scope(kwargs['scope']) + + # pull the `client_id` out of the kwargs. + client_id = kwargs.pop('client_id', None) + if include_client_id: + if client_id is not None: + params.append(('client_id', client_id)) + + # use code_verifier if code_challenge was passed in the authorization request + if code_verifier is not None: + params.append(('code_verifier', code_verifier)) + + # the kwargs iteration below only supports including boolean truth (truthy) + # values, but some servers may require an empty string for `client_secret` + client_secret = kwargs.pop('client_secret', None) + if client_secret is not None: + params.append(('client_secret', client_secret)) + + # this handles: `code`, `redirect_uri`, and other undocumented params + for k in kwargs: + if kwargs[k]: + params.append((str(k), kwargs[k])) + + return add_params_to_qs(body, params) + + +def prepare_token_revocation_request(url, token, token_type_hint="access_token", + callback=None, body='', **kwargs): + """Prepare a token revocation request. + + The client constructs the request by including the following parameters + using the ``application/x-www-form-urlencoded`` format in the HTTP request + entity-body: + + :param token: REQUIRED. The token that the client wants to get revoked. + + :param token_type_hint: OPTIONAL. A hint about the type of the token + submitted for revocation. Clients MAY pass this + parameter in order to help the authorization server + to optimize the token lookup. If the server is + unable to locate the token using the given hint, it + MUST extend its search across all of its supported + token types. An authorization server MAY ignore + this parameter, particularly if it is able to detect + the token type automatically. + + This specification defines two values for `token_type_hint`: + + * access_token: An access token as defined in [RFC6749], + `Section 1.4`_ + + * refresh_token: A refresh token as defined in [RFC6749], + `Section 1.5`_ + + Specific implementations, profiles, and extensions of this + specification MAY define other values for this parameter using the + registry defined in `Section 4.1.2`_. + + .. _`Section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4 + .. _`Section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5 + .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc7009#section-4.1.2 + + """ + if not is_secure_transport(url): + raise InsecureTransportError() + + params = [('token', token)] + + if token_type_hint: + params.append(('token_type_hint', token_type_hint)) + + for k in kwargs: + if kwargs[k]: + params.append((str(k), kwargs[k])) + + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + + if callback: + params.append(('callback', callback)) + return add_params_to_uri(url, params), headers, body + else: + return url, headers, add_params_to_qs(body, params) + + +def parse_authorization_code_response(uri, state=None): + """Parse authorization grant response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the ``application/x-www-form-urlencoded`` format: + + **code** + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + + **state** + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + :param uri: The full redirect URL back to the client. + :param state: The state parameter from the authorization request. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response: + + .. code-block:: http + + HTTP/1.1 302 Found + Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA + &state=xyz + + """ + if not is_secure_transport(uri): + raise InsecureTransportError() + + query = urlparse.urlparse(uri).query + params = dict(urlparse.parse_qsl(query)) + + if state and params.get('state', None) != state: + raise MismatchingStateError() + + if 'error' in params: + raise_from_error(params.get('error'), params) + + if not 'code' in params: + raise MissingCodeError("Missing code parameter in response.") + + return params + + +def parse_implicit_response(uri, state=None, scope=None): + """Parse the implicit token response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the ``application/x-www-form-urlencoded`` format: + + **access_token** + REQUIRED. The access token issued by the authorization server. + + **token_type** + REQUIRED. The type of the token issued as described in + Section 7.1. Value is case insensitive. + + **expires_in** + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + **scope** + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by Section 3.3. + + **state** + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + :param uri: + :param state: + :param scope: + + Similar to the authorization code response, but with a full token provided + in the URL fragment: + + .. code-block:: http + + HTTP/1.1 302 Found + Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA + &state=xyz&token_type=example&expires_in=3600 + """ + if not is_secure_transport(uri): + raise InsecureTransportError() + + fragment = urlparse.urlparse(uri).fragment + params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True)) + + for key in ('expires_in',): + if key in params: # cast things to int + params[key] = int(params[key]) + + if 'scope' in params: + params['scope'] = scope_to_list(params['scope']) + + if 'expires_in' in params: + params['expires_at'] = time.time() + int(params['expires_in']) + + if state and params.get('state', None) != state: + raise ValueError("Mismatching or missing state in params.") + + params = OAuth2Token(params, old_scope=scope) + validate_token_parameters(params) + return params + + +def parse_token_response(body, scope=None): + """Parse the JSON token response body into a dict. + + The authorization server issues an access token and optional refresh + token, and constructs the response by adding the following parameters + to the entity body of the HTTP response with a 200 (OK) status code: + + access_token + REQUIRED. The access token issued by the authorization server. + token_type + REQUIRED. The type of the token issued as described in + `Section 7.1`_. Value is case insensitive. + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + refresh_token + OPTIONAL. The refresh token which can be used to obtain new + access tokens using the same authorization grant as described + in `Section 6`_. + scope + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by `Section 3.3`_. + + The parameters are included in the entity body of the HTTP response + using the "application/json" media type as defined by [`RFC4627`_]. The + parameters are serialized into a JSON structure by adding each + parameter at the highest structure level. Parameter names and string + values are included as JSON strings. Numerical values are included + as JSON numbers. The order of parameters does not matter and can + vary. + + :param body: The full json encoded response body. + :param scope: The scope requested during authorization. + + For example: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/json + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"2YotnFZFEjr1zCsicMWpAA", + "token_type":"example", + "expires_in":3600, + "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter":"example_value" + } + + .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 + .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`RFC4627`: https://tools.ietf.org/html/rfc4627 + """ + try: + params = json.loads(body) + except ValueError: + + # Fall back to URL-encoded string, to support old implementations, + # including (at time of writing) Facebook. See: + # https://github.com/oauthlib/oauthlib/issues/267 + + params = dict(urlparse.parse_qsl(body)) + for key in ('expires_in',): + if key in params: # cast things to int + params[key] = int(params[key]) + + if 'scope' in params: + params['scope'] = scope_to_list(params['scope']) + + if 'expires_in' in params: + if params['expires_in'] is None: + params.pop('expires_in') + else: + params['expires_at'] = time.time() + int(params['expires_in']) + + params = OAuth2Token(params, old_scope=scope) + validate_token_parameters(params) + return params + + +def validate_token_parameters(params): + """Ensures token presence, token type, expiration and scope in params.""" + if 'error' in params: + raise_from_error(params.get('error'), params) + + if not 'access_token' in params: + raise MissingTokenError(description="Missing access token parameter.") + + if not 'token_type' in params: + if os.environ.get('OAUTHLIB_STRICT_TOKEN_TYPE'): + raise MissingTokenTypeError() + + # If the issued access token scope is different from the one requested by + # the client, the authorization server MUST include the "scope" response + # parameter to inform the client of the actual scope granted. + # https://tools.ietf.org/html/rfc6749#section-3.3 + if params.scope_changed: + message = 'Scope has changed from "{old}" to "{new}".'.format( + old=params.old_scope, new=params.scope, + ) + scope_changed.send(message=message, old=params.old_scopes, new=params.scopes) + if not os.environ.get('OAUTHLIB_RELAX_TOKEN_SCOPE', None): + w = Warning(message) + w.token = params + w.old_scope = params.old_scopes + w.new_scope = params.scopes + raise w diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/request_validator.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/request_validator.py new file mode 100644 index 0000000000000000000000000000000000000000..3910c0b91822190a728471bc19acd5dee0226100 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/request_validator.py @@ -0,0 +1,680 @@ +""" +oauthlib.oauth2.rfc6749.request_validator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +log = logging.getLogger(__name__) + + +class RequestValidator: + + def client_authentication_required(self, request, *args, **kwargs): + """Determine if client authentication is required for current request. + + According to the rfc6749, client authentication is required in the following cases: + - Resource Owner Password Credentials Grant, when Client type is Confidential or when + Client was issued client credentials or whenever Client provided client + authentication, see `Section 4.3.2`_. + - Authorization Code Grant, when Client type is Confidential or when Client was issued + client credentials or whenever Client provided client authentication, + see `Section 4.1.3`_. + - Refresh Token Grant, when Client type is Confidential or when Client was issued + client credentials or whenever Client provided client authentication, see + `Section 6`_ + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Resource Owner Password Credentials Grant + - Refresh Token Grant + + .. _`Section 4.3.2`: https://tools.ietf.org/html/rfc6749#section-4.3.2 + .. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3 + .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6 + """ + return True + + def authenticate_client(self, request, *args, **kwargs): + """Authenticate client through means outside the OAuth 2 spec. + + Means of authentication is negotiated beforehand and may for example + be `HTTP Basic Authentication Scheme`_ which utilizes the Authorization + header. + + Headers may be accesses through request.headers and parameters found in + both body and query can be obtained by direct attribute access, i.e. + request.client_id for client_id in the URL query. + + The authentication process is required to contain the identification of + the client (i.e. search the database based on the client_id). In case the + client doesn't exist based on the received client_id, this method has to + return False and the HTTP response created by the library will contain + 'invalid_client' message. + + After the client identification succeeds, this method needs to set the + client on the request, i.e. request.client = client. A client object's + class must contain the 'client_id' attribute and the 'client_id' must have + a value. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Resource Owner Password Credentials Grant (may be disabled) + - Client Credentials Grant + - Refresh Token Grant + + .. _`HTTP Basic Authentication Scheme`: https://tools.ietf.org/html/rfc1945#section-11.1 + """ + raise NotImplementedError('Subclasses must implement this method.') + + def authenticate_client_id(self, client_id, request, *args, **kwargs): + """Ensure client_id belong to a non-confidential client. + + A non-confidential client is one that is not required to authenticate + through other means, such as using HTTP Basic. + + Note, while not strictly necessary it can often be very convenient + to set request.client to the client object associated with the + given client_id. + + :param client_id: Unicode client identifier. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request, + *args, **kwargs): + """Ensure that the authorization process represented by this authorization + code began with this 'redirect_uri'. + + If the client specifies a redirect_uri when obtaining code then that + redirect URI must be bound to the code and verified equal in this + method, according to RFC 6749 section 4.1.3. Do not compare against + the client's allowed redirect URIs, but against the URI used when the + code was saved. + + :param client_id: Unicode client identifier. + :param code: Unicode authorization_code. + :param redirect_uri: Unicode absolute URI. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant (during token request) + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_default_redirect_uri(self, client_id, request, *args, **kwargs): + """Get the default redirect URI for the client. + + :param client_id: Unicode client identifier. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: The default redirect URI for the client + + Method is used by: + - Authorization Code Grant + - Implicit Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_default_scopes(self, client_id, request, *args, **kwargs): + """Get the default scopes for the client. + + :param client_id: Unicode client identifier. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: List of default scopes + + Method is used by all core grant types: + - Authorization Code Grant + - Implicit Grant + - Resource Owner Password Credentials Grant + - Client Credentials grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_original_scopes(self, refresh_token, request, *args, **kwargs): + """Get the list of scopes associated with the refresh token. + + :param refresh_token: Unicode refresh token. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: List of scopes. + + Method is used by: + - Refresh token grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def is_within_original_scope(self, request_scopes, refresh_token, request, *args, **kwargs): + """Check if requested scopes are within a scope of the refresh token. + + When access tokens are refreshed the scope of the new token + needs to be within the scope of the original token. This is + ensured by checking that all requested scopes strings are on + the list returned by the get_original_scopes. If this check + fails, is_within_original_scope is called. The method can be + used in situations where returning all valid scopes from the + get_original_scopes is not practical. + + :param request_scopes: A list of scopes that were requested by client. + :param refresh_token: Unicode refresh_token. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Refresh token grant + """ + return False + + def introspect_token(self, token, token_type_hint, request, *args, **kwargs): + """Introspect an access or refresh token. + + Called once the introspect request is validated. This method should + verify the *token* and either return a dictionary with the list of + claims associated, or `None` in case the token is unknown. + + Below the list of registered claims you should be interested in: + + - scope : space-separated list of scopes + - client_id : client identifier + - username : human-readable identifier for the resource owner + - token_type : type of the token + - exp : integer timestamp indicating when this token will expire + - iat : integer timestamp indicating when this token was issued + - nbf : integer timestamp indicating when it can be "not-before" used + - sub : subject of the token - identifier of the resource owner + - aud : list of string identifiers representing the intended audience + - iss : string representing issuer of this token + - jti : string identifier for the token + + Note that most of them are coming directly from JWT RFC. More details + can be found in `Introspect Claims`_ or `JWT Claims`_. + + The implementation can use *token_type_hint* to improve lookup + efficiency, but must fallback to other types to be compliant with RFC. + + The dict of claims is added to request.token after this method. + + :param token: The token string. + :param token_type_hint: access_token or refresh_token. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + Method is used by: + - Introspect Endpoint (all grants are compatible) + + .. _`Introspect Claims`: https://tools.ietf.org/html/rfc7662#section-2.2 + .. _`JWT Claims`: https://tools.ietf.org/html/rfc7519#section-4 + """ + raise NotImplementedError('Subclasses must implement this method.') + + def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs): + """Invalidate an authorization code after use. + + :param client_id: Unicode client identifier. + :param code: The authorization code grant (request.code). + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + Method is used by: + - Authorization Code Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def revoke_token(self, token, token_type_hint, request, *args, **kwargs): + """Revoke an access or refresh token. + + :param token: The token string. + :param token_type_hint: access_token or refresh_token. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + Method is used by: + - Revocation Endpoint + """ + raise NotImplementedError('Subclasses must implement this method.') + + def rotate_refresh_token(self, request): + """Determine whether to rotate the refresh token. Default, yes. + + When access tokens are refreshed the old refresh token can be kept + or replaced with a new one (rotated). Return True to rotate and + and False for keeping original. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Refresh Token Grant + """ + return True + + def save_authorization_code(self, client_id, code, request, *args, **kwargs): + """Persist the authorization_code. + + The code should at minimum be stored with: + - the client_id (``client_id``) + - the redirect URI used (``request.redirect_uri``) + - a resource owner / user (``request.user``) + - the authorized scopes (``request.scopes``) + + To support PKCE, you MUST associate the code with: + - Code Challenge (``request.code_challenge``) and + - Code Challenge Method (``request.code_challenge_method``) + + To support OIDC, you MUST associate the code with: + - nonce, if present (``code["nonce"]``) + + The ``code`` argument is actually a dictionary, containing at least a + ``code`` key with the actual authorization code: + + ``{'code': 'sdf345jsdf0934f'}`` + + It may also have a ``claims`` parameter which, when present, will be a dict + deserialized from JSON as described at + http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter + This value should be saved in this method and used again in ``.validate_code``. + + :param client_id: Unicode client identifier. + :param code: A dict of the authorization code grant and, optionally, state. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + Method is used by: + - Authorization Code Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def save_token(self, token, request, *args, **kwargs): + """Persist the token with a token type specific method. + + Currently, only save_bearer_token is supported. + + :param token: A (Bearer) token dict. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + return self.save_bearer_token(token, request, *args, **kwargs) + + def save_bearer_token(self, token, request, *args, **kwargs): + """Persist the Bearer token. + + The Bearer token should at minimum be associated with: + - a client and it's client_id, if available + - a resource owner / user (request.user) + - authorized scopes (request.scopes) + - an expiration time + - a refresh token, if issued + - a claims document, if present in request.claims + + The Bearer token dict may hold a number of items:: + + { + 'token_type': 'Bearer', + 'access_token': 'askfjh234as9sd8', + 'expires_in': 3600, + 'scope': 'string of space separated authorized scopes', + 'refresh_token': '23sdf876234', # if issued + 'state': 'given_by_client', # if supplied by client (implicit ONLY) + } + + Note that while "scope" is a string-separated list of authorized scopes, + the original list is still available in request.scopes. + + The token dict is passed as a reference so any changes made to the dictionary + will go back to the user. If additional information must return to the client + user, and it is only possible to get this information after writing the token + to storage, it should be added to the token dictionary. If the token + dictionary must be modified but the changes should not go back to the user, + a copy of the dictionary must be made before making the changes. + + Also note that if an Authorization Code grant request included a valid claims + parameter (for OpenID Connect) then the request.claims property will contain + the claims dict, which should be saved for later use when generating the + id_token and/or UserInfo response content. + + :param token: A Bearer token dict. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: The default redirect URI for the client + + Method is used by all core grant types issuing Bearer tokens: + - Authorization Code Grant + - Implicit Grant + - Resource Owner Password Credentials Grant (might not associate a client) + - Client Credentials grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_bearer_token(self, token, scopes, request): + """Ensure the Bearer token is valid and authorized access to scopes. + + :param token: A string of random characters. + :param scopes: A list of scopes associated with the protected resource. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + + A key to OAuth 2 security and restricting impact of leaked tokens is + the short expiration time of tokens, *always ensure the token has not + expired!*. + + Two different approaches to scope validation: + + 1) all(scopes). The token must be authorized access to all scopes + associated with the resource. For example, the + token has access to ``read-only`` and ``images``, + thus the client can view images but not upload new. + Allows for fine grained access control through + combining various scopes. + + 2) any(scopes). The token must be authorized access to one of the + scopes associated with the resource. For example, + token has access to ``read-only-images``. + Allows for fine grained, although arguably less + convenient, access control. + + A powerful way to use scopes would mimic UNIX ACLs and see a scope + as a group with certain privileges. For a restful API these might + map to HTTP verbs instead of read, write and execute. + + Note, the request.user attribute can be set to the resource owner + associated with this token. Similarly the request.client and + request.scopes attribute can be set to associated client object + and authorized scopes. If you then use a decorator such as the + one provided for django these attributes will be made available + in all protected views as keyword arguments. + + :param token: Unicode Bearer token + :param scopes: List of scopes (defined by you) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is indirectly used by all core Bearer token issuing grant types: + - Authorization Code Grant + - Implicit Grant + - Resource Owner Password Credentials Grant + - Client Credentials Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_client_id(self, client_id, request, *args, **kwargs): + """Ensure client_id belong to a valid and active client. + + Note, while not strictly necessary it can often be very convenient + to set request.client to the client object associated with the + given client_id. + + :param client_id: Unicode client identifier. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Implicit Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_code(self, client_id, code, client, request, *args, **kwargs): + """Verify that the authorization_code is valid and assigned to the given + client. + + Before returning true, set the following based on the information stored + with the code in 'save_authorization_code': + + - request.user + - request.scopes + - request.claims (if given) + + OBS! The request.user attribute should be set to the resource owner + associated with this authorization code. Similarly request.scopes + must also be set. + + The request.claims property, if it was given, should assigned a dict. + + If PKCE is enabled (see 'is_pkce_required' and 'save_authorization_code') + you MUST set the following based on the information stored: + + - request.code_challenge + - request.code_challenge_method + + :param client_id: Unicode client identifier. + :param code: Unicode authorization code. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs): + """Ensure client is authorized to use the grant_type requested. + + :param client_id: Unicode client identifier. + :param grant_type: Unicode grant type, i.e. authorization_code, password. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Resource Owner Password Credentials Grant + - Client Credentials Grant + - Refresh Token Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs): + """Ensure client is authorized to redirect to the redirect_uri requested. + + All clients should register the absolute URIs of all URIs they intend + to redirect to. The registration is outside of the scope of oauthlib. + + :param client_id: Unicode client identifier. + :param redirect_uri: Unicode absolute URI. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Implicit Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs): + """Ensure the Bearer token is valid and authorized access to scopes. + + OBS! The request.user attribute should be set to the resource owner + associated with this refresh token. + + :param refresh_token: Unicode refresh token. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant (indirectly by issuing refresh tokens) + - Resource Owner Password Credentials Grant (also indirectly) + - Refresh Token Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs): + """Ensure client is authorized to use the response_type requested. + + :param client_id: Unicode client identifier. + :param response_type: Unicode response type, i.e. code, token. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + - Implicit Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): + """Ensure the client is authorized access to requested scopes. + + :param client_id: Unicode client identifier. + :param scopes: List of scopes (defined by you). + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by all core grant types: + - Authorization Code Grant + - Implicit Grant + - Resource Owner Password Credentials Grant + - Client Credentials Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_user(self, username, password, client, request, *args, **kwargs): + """Ensure the username and password is valid. + + OBS! The validation should also set the user attribute of the request + to a valid resource owner, i.e. request.user = username or similar. If + not set you will be unable to associate a token with a user in the + persistence method used (commonly, save_bearer_token). + + :param username: Unicode username. + :param password: Unicode password. + :param client: Client object set by you, see ``.authenticate_client``. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Resource Owner Password Credentials Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def is_pkce_required(self, client_id, request): + """Determine if current request requires PKCE. Default, False. + This is called for both "authorization" and "token" requests. + + Override this method by ``return True`` to enable PKCE for everyone. + You might want to enable it only for public clients. + Note that PKCE can also be used in addition of a client authentication. + + OAuth 2.0 public clients utilizing the Authorization Code Grant are + susceptible to the authorization code interception attack. This + specification describes the attack as well as a technique to mitigate + against the threat through the use of Proof Key for Code Exchange + (PKCE, pronounced "pixy"). See `RFC7636`_. + + :param client_id: Client identifier. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - Authorization Code Grant + + .. _`RFC7636`: https://tools.ietf.org/html/rfc7636 + """ + return False + + def get_code_challenge(self, code, request): + """Is called for every "token" requests. + + When the server issues the authorization code in the authorization + response, it MUST associate the ``code_challenge`` and + ``code_challenge_method`` values with the authorization code so it can + be verified later. + + Typically, the ``code_challenge`` and ``code_challenge_method`` values + are stored in encrypted form in the ``code`` itself but could + alternatively be stored on the server associated with the code. The + server MUST NOT include the ``code_challenge`` value in client requests + in a form that other entities can extract. + + Return the ``code_challenge`` associated to the code. + If ``None`` is returned, code is considered to not be associated to any + challenges. + + :param code: Authorization code. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: code_challenge string + + Method is used by: + - Authorization Code Grant - when PKCE is active + + """ + return None + + def get_code_challenge_method(self, code, request): + """Is called during the "token" request processing, when a + ``code_verifier`` and a ``code_challenge`` has been provided. + + See ``.get_code_challenge``. + + Must return ``plain`` or ``S256``. You can return a custom value if you have + implemented your own ``AuthorizationCodeGrant`` class. + + :param code: Authorization code. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: code_challenge_method string + + Method is used by: + - Authorization Code Grant - when PKCE is active + + """ + raise NotImplementedError('Subclasses must implement this method.') + + def is_origin_allowed(self, client_id, origin, request, *args, **kwargs): + """Indicate if the given origin is allowed to access the token endpoint + via Cross-Origin Resource Sharing (CORS). CORS is used by browser-based + clients, such as Single-Page Applications, to perform the Authorization + Code Grant. + + (Note: If performing Authorization Code Grant via a public client such + as a browser, you should use PKCE as well.) + + If this method returns true, the appropriate CORS headers will be added + to the response. By default this method always returns False, meaning + CORS is disabled. + + :param client_id: Unicode client identifier. + :param redirect_uri: Unicode origin. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: bool + + Method is used by: + - Authorization Code Grant + - Refresh Token Grant + + """ + return False diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/tokens.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/tokens.py new file mode 100644 index 0000000000000000000000000000000000000000..0757d07ea5a7559d09f5e83960953d3ae5c5725a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/tokens.py @@ -0,0 +1,356 @@ +""" +oauthlib.oauth2.rfc6749.tokens +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods for adding two types of access tokens to requests. + +- Bearer https://tools.ietf.org/html/rfc6750 +- MAC https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 +""" +import hashlib +import hmac +import warnings +from binascii import b2a_base64 +from urllib.parse import urlparse + +from oauthlib import common +from oauthlib.common import add_params_to_qs, add_params_to_uri + +from . import utils + + +class OAuth2Token(dict): + + def __init__(self, params, old_scope=None): + super().__init__(params) + self._new_scope = None + if 'scope' in params and params['scope']: + self._new_scope = set(utils.scope_to_list(params['scope'])) + if old_scope is not None: + self._old_scope = set(utils.scope_to_list(old_scope)) + if self._new_scope is None: + # the rfc says that if the scope hasn't changed, it's optional + # in params so set the new scope to the old scope + self._new_scope = self._old_scope + else: + self._old_scope = self._new_scope + + @property + def scope_changed(self): + return self._new_scope != self._old_scope + + @property + def old_scope(self): + return utils.list_to_scope(self._old_scope) + + @property + def old_scopes(self): + return list(self._old_scope) + + @property + def scope(self): + return utils.list_to_scope(self._new_scope) + + @property + def scopes(self): + return list(self._new_scope) + + @property + def missing_scopes(self): + return list(self._old_scope - self._new_scope) + + @property + def additional_scopes(self): + return list(self._new_scope - self._old_scope) + + +def prepare_mac_header(token, uri, key, http_method, + nonce=None, + headers=None, + body=None, + ext='', + hash_algorithm='hmac-sha-1', + issue_time=None, + draft=0): + """Add an `MAC Access Authentication`_ signature to headers. + + Unlike OAuth 1, this HMAC signature does not require inclusion of the + request payload/body, neither does it use a combination of client_secret + and token_secret but rather a mac_key provided together with the access + token. + + Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256", + `extension algorithms`_ are not supported. + + Example MAC Authorization header, linebreaks added for clarity + + Authorization: MAC id="h480djs93hd8", + nonce="1336363200:dj83hs9s", + mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" + + .. _`MAC Access Authentication`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 + .. _`extension algorithms`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1 + + :param token: + :param uri: Request URI. + :param key: MAC given provided by token endpoint. + :param http_method: HTTP Request method. + :param nonce: + :param headers: Request headers as a dictionary. + :param body: + :param ext: + :param hash_algorithm: HMAC algorithm provided by token endpoint. + :param issue_time: Time when the MAC credentials were issued (datetime). + :param draft: MAC authentication specification version. + :return: headers dictionary with the authorization field added. + """ + http_method = http_method.upper() + host, port = utils.host_from_uri(uri) + + if hash_algorithm.lower() == 'hmac-sha-1': + h = hashlib.sha1 + elif hash_algorithm.lower() == 'hmac-sha-256': + h = hashlib.sha256 + else: + raise ValueError('unknown hash algorithm') + + if draft == 0: + nonce = nonce or '{}:{}'.format(utils.generate_age(issue_time), + common.generate_nonce()) + else: + ts = common.generate_timestamp() + nonce = common.generate_nonce() + + sch, net, path, par, query, fra = urlparse(uri) + + if query: + request_uri = path + '?' + query + else: + request_uri = path + + # Hash the body/payload + if body is not None and draft == 0: + body = body.encode('utf-8') + bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8') + else: + bodyhash = '' + + # Create the normalized base string + base = [] + if draft == 0: + base.append(nonce) + else: + base.append(ts) + base.append(nonce) + base.append(http_method.upper()) + base.append(request_uri) + base.append(host) + base.append(port) + if draft == 0: + base.append(bodyhash) + base.append(ext or '') + base_string = '\n'.join(base) + '\n' + + # hmac struggles with unicode strings - http://bugs.python.org/issue5285 + if isinstance(key, str): + key = key.encode('utf-8') + sign = hmac.new(key, base_string.encode('utf-8'), h) + sign = b2a_base64(sign.digest())[:-1].decode('utf-8') + + header = [] + header.append('MAC id="%s"' % token) + if draft != 0: + header.append('ts="%s"' % ts) + header.append('nonce="%s"' % nonce) + if bodyhash: + header.append('bodyhash="%s"' % bodyhash) + if ext: + header.append('ext="%s"' % ext) + header.append('mac="%s"' % sign) + + headers = headers or {} + headers['Authorization'] = ', '.join(header) + return headers + + +def prepare_bearer_uri(token, uri): + """Add a `Bearer Token`_ to the request URI. + Not recommended, use only if client can't use authorization header or body. + + http://www.example.com/path?access_token=h480djs93hd8 + + .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750 + + :param token: + :param uri: + """ + return add_params_to_uri(uri, [(('access_token', token))]) + + +def prepare_bearer_headers(token, headers=None): + """Add a `Bearer Token`_ to the request URI. + Recommended method of passing bearer tokens. + + Authorization: Bearer h480djs93hd8 + + .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750 + + :param token: + :param headers: + """ + headers = headers or {} + headers['Authorization'] = 'Bearer %s' % token + return headers + + +def prepare_bearer_body(token, body=''): + """Add a `Bearer Token`_ to the request body. + + access_token=h480djs93hd8 + + .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750 + + :param token: + :param body: + """ + return add_params_to_qs(body, [(('access_token', token))]) + + +def random_token_generator(request, refresh_token=False): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param refresh_token: + """ + return common.generate_token() + + +def signed_token_generator(private_pem, **kwargs): + """ + :param private_pem: + """ + def signed_token_generator(request): + request.claims = kwargs + return common.generate_signed_token(private_pem, request) + + return signed_token_generator + + +def get_token_from_header(request): + """ + Helper function to extract a token from the request header. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :return: Return the token or None if the Authorization header is malformed. + """ + token = None + + if 'Authorization' in request.headers: + split_header = request.headers.get('Authorization').split() + if len(split_header) == 2 and split_header[0].lower() == 'bearer': + token = split_header[1] + else: + token = request.access_token + + return token + + +class TokenBase: + __slots__ = () + + def __call__(self, request, refresh_token=False): + raise NotImplementedError('Subclasses must implement this method.') + + def validate_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + raise NotImplementedError('Subclasses must implement this method.') + + def estimate_type(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + raise NotImplementedError('Subclasses must implement this method.') + + +class BearerToken(TokenBase): + __slots__ = ( + 'request_validator', 'token_generator', + 'refresh_token_generator', 'expires_in' + ) + + def __init__(self, request_validator=None, token_generator=None, + expires_in=None, refresh_token_generator=None): + self.request_validator = request_validator + self.token_generator = token_generator or random_token_generator + self.refresh_token_generator = ( + refresh_token_generator or self.token_generator + ) + self.expires_in = expires_in or 3600 + + def create_token(self, request, refresh_token=False, **kwargs): + """ + Create a BearerToken, by default without refresh token. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :param refresh_token: + """ + if "save_token" in kwargs: + warnings.warn("`save_token` has been deprecated, it was not called internally." + "If you do, call `request_validator.save_token()` instead.", + DeprecationWarning) + + if callable(self.expires_in): + expires_in = self.expires_in(request) + else: + expires_in = self.expires_in + + request.expires_in = expires_in + + token = { + 'access_token': self.token_generator(request), + 'expires_in': expires_in, + 'token_type': 'Bearer', + } + + # If provided, include - this is optional in some cases https://tools.ietf.org/html/rfc6749#section-3.3 but + # there is currently no mechanism to coordinate issuing a token for only a subset of the requested scopes so + # all tokens issued are for the entire set of requested scopes. + if request.scopes is not None: + token['scope'] = ' '.join(request.scopes) + + if refresh_token: + if (request.refresh_token and + not self.request_validator.rotate_refresh_token(request)): + token['refresh_token'] = request.refresh_token + else: + token['refresh_token'] = self.refresh_token_generator(request) + + token.update(request.extra_credentials or {}) + return OAuth2Token(token) + + def validate_request(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + token = get_token_from_header(request) + return self.request_validator.validate_bearer_token( + token, request.scopes, request) + + def estimate_type(self, request): + """ + :param request: OAuthlib request. + :type request: oauthlib.common.Request + """ + if request.headers.get('Authorization', '').split(' ')[0].lower() == 'bearer': + return 9 + elif request.access_token is not None: + return 5 + else: + return 0 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..7dc27b3dff480bbb89e113f478cec27945af8e2d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc6749/utils.py @@ -0,0 +1,83 @@ +""" +oauthlib.utils +~~~~~~~~~~~~~~ + +This module contains utility methods used by various parts of the OAuth 2 spec. +""" +import datetime +import os +from urllib.parse import quote, urlparse + +from oauthlib.common import urldecode + + +def list_to_scope(scope): + """Convert a list of scopes to a space separated string.""" + if isinstance(scope, str) or scope is None: + return scope + elif isinstance(scope, (set, tuple, list)): + return " ".join([str(s) for s in scope]) + else: + raise ValueError("Invalid scope (%s), must be string, tuple, set, or list." % scope) + + +def scope_to_list(scope): + """Convert a space separated string to a list of scopes.""" + if isinstance(scope, (tuple, list, set)): + return [str(s) for s in scope] + elif scope is None: + return None + else: + return scope.strip().split(" ") + + +def params_from_uri(uri): + params = dict(urldecode(urlparse(uri).query)) + if 'scope' in params: + params['scope'] = scope_to_list(params['scope']) + return params + + +def host_from_uri(uri): + """Extract hostname and port from URI. + + Will use default port for HTTP and HTTPS if none is present in the URI. + """ + default_ports = { + 'HTTP': '80', + 'HTTPS': '443', + } + + sch, netloc, path, par, query, fra = urlparse(uri) + if ':' in netloc: + netloc, port = netloc.split(':', 1) + else: + port = default_ports.get(sch.upper()) + + return netloc, port + + +def escape(u): + """Escape a string in an OAuth-compatible fashion. + + TODO: verify whether this can in fact be used for OAuth 2 + + """ + if not isinstance(u, str): + raise ValueError('Only unicode objects are escapable.') + return quote(u.encode('utf-8'), safe=b'~') + + +def generate_age(issue_time): + """Generate a age parameter for MAC authentication draft 00.""" + td = datetime.datetime.now() - issue_time + age = (td.microseconds + (td.seconds + td.days * 24 * 3600) + * 10 ** 6) / 10 ** 6 + return str(age) + + +def is_secure_transport(uri): + """Check if the uri is over ssl.""" + if os.environ.get('OAUTHLIB_INSECURE_TRANSPORT'): + return True + return uri.lower().startswith('https://') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..531929dcc73f9b52b894b1db733c70fbf6077844 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__init__.py @@ -0,0 +1,10 @@ +""" +oauthlib.oauth2.rfc8628 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 Device Authorization RFC8628. +""" +import logging + +log = logging.getLogger(__name__) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6dd63fddb016afa211d6c47a793c298c38aa0a79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..130b52e3814bc40c0f483b1ab60b034d1374049c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__init__.py @@ -0,0 +1,8 @@ +""" +oauthlib.oauth2.rfc8628 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming OAuth 2.0 Device Authorization RFC8628. +""" +from .device import DeviceClient diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7ca2224016a4318e6a1a5cb29393a05ca3e34f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/device.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/device.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e9784c49533433ae9b1a3b8ef9aa9a1e4821123 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/__pycache__/device.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/device.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/device.py new file mode 100644 index 0000000000000000000000000000000000000000..b9ba2150a2a5f35f485f5e39b48d9f52c90dd75f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/oauth2/rfc8628/clients/device.py @@ -0,0 +1,95 @@ +""" +oauthlib.oauth2.rfc8628 +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OAuth 2.0 Device Authorization RFC8628. +""" +from oauthlib.common import add_params_to_uri +from oauthlib.oauth2 import BackendApplicationClient, Client +from oauthlib.oauth2.rfc6749.errors import InsecureTransportError +from oauthlib.oauth2.rfc6749.parameters import prepare_token_request +from oauthlib.oauth2.rfc6749.utils import is_secure_transport, list_to_scope + + +class DeviceClient(Client): + + """A public client utilizing the device authorization workflow. + + The client can request an access token using a device code and + a public client id associated with the device code as defined + in RFC8628. + + The device authorization grant type can be used to obtain both + access tokens and refresh tokens and is intended to be used in + a scenario where the device being authorized does not have a + user interface that is suitable for performing authentication. + """ + + grant_type = 'urn:ietf:params:oauth:grant-type:device_code' + + def __init__(self, client_id, **kwargs): + super().__init__(client_id, **kwargs) + self.client_secret = kwargs.get('client_secret') + + def prepare_request_uri(self, uri, scope=None, **kwargs): + if not is_secure_transport(uri): + raise InsecureTransportError() + + scope = self.scope if scope is None else scope + params = [(('client_id', self.client_id)), (('grant_type', self.grant_type))] + + if self.client_secret is not None: + params.append(('client_secret', self.client_secret)) + + if scope: + params.append(('scope', list_to_scope(scope))) + + for k in kwargs: + if kwargs[k]: + params.append((str(k), kwargs[k])) + + return add_params_to_uri(uri, params) + + def prepare_request_body(self, device_code, body='', scope=None, + include_client_id=False, **kwargs): + """Add device_code to request body + + The client makes a request to the token endpoint by adding the + device_code as a parameter using the + "application/x-www-form-urlencoded" format to the HTTP request + body. + + :param body: Existing request body (URL encoded string) to embed parameters + into. This may contain extra parameters. Default ''. + :param scope: The scope of the access request as described by + `Section 3.3`_. + + :param include_client_id: `True` to send the `client_id` in the + body of the upstream request. This is required + if the client is not authenticating with the + authorization server as described in + `Section 3.2.1`_. False otherwise (default). + :type include_client_id: Boolean + + :param kwargs: Extra credentials to include in the token request. + + The prepared body will include all provided device_code as well as + the ``grant_type`` parameter set to + ``urn:ietf:params:oauth:grant-type:device_code``:: + + >>> from oauthlib.oauth2 import DeviceClient + >>> client = DeviceClient('your_id', 'your_code') + >>> client.prepare_request_body(scope=['hello', 'world']) + 'grant_type=urn:ietf:params:oauth:grant-type:device_code&scope=hello+world' + + .. _`Section 3.2.1`: https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1 + .. _`Section 3.3`: https://datatracker.ietf.org/doc/html/rfc6749#section-3.3 + .. _`Section 3.4`: https://datatracker.ietf.org/doc/html/rfc8628#section-3.4 + """ + + kwargs['client_id'] = self.client_id + kwargs['include_client_id'] = include_client_id + scope = self.scope if scope is None else scope + return prepare_token_request(self.grant_type, body=body, device_code=device_code, + scope=scope, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e3174374798f21cc8d5f23e67b2077f14234a1a6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__init__.py @@ -0,0 +1,7 @@ +""" +oauthlib.openid +~~~~~~~~~~~~~~ + +""" +from .connect.core.endpoints import Server, UserInfoEndpoint +from .connect.core.request_validator import RequestValidator diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31c793bbfc69121c5a3c0ff875d50414e4226720 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6754e762cf41d229151bc296715ed912c147146 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14ce08d4d1583effb3486bf524499e9d2efff54c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e4ffae0d4b620e50fdfd6d2e5b96f0547902a8e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/request_validator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/request_validator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..178c1d456d2357186a15c968fd32ca76fb96afeb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/request_validator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/tokens.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/tokens.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11beaa55f5f9d8733d586ac0dad3fa80afe963ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/__pycache__/tokens.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7017ff4f3211d2007ee5d297cfff47c0a5b27fd4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__init__.py @@ -0,0 +1,9 @@ +""" +oauthlib.oopenid.core +~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for consuming and providing OpenID Connect +""" +from .pre_configured import Server +from .userinfo import UserInfoEndpoint diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00567bb79d883b73eb2aad4c30ef78dc32e4831c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/pre_configured.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/pre_configured.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..766c81a65d2d3176e6948165aa25df71f799a2b3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/pre_configured.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/userinfo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/userinfo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a02993d7bdf2af1433b8079aea8e0f69b1632614 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/__pycache__/userinfo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/pre_configured.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/pre_configured.py new file mode 100644 index 0000000000000000000000000000000000000000..8ce8bee67b98e5a8289b81974615b7c7e0cccb49 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/pre_configured.py @@ -0,0 +1,97 @@ +""" +oauthlib.openid.connect.core.endpoints.pre_configured +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of various endpoints needed +for providing OpenID Connect servers. +""" +from oauthlib.oauth2.rfc6749.endpoints import ( + AuthorizationEndpoint, IntrospectEndpoint, ResourceEndpoint, + RevocationEndpoint, TokenEndpoint, +) +from oauthlib.oauth2.rfc6749.grant_types import ( + AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant, + ClientCredentialsGrant, ImplicitGrant as OAuth2ImplicitGrant, + RefreshTokenGrant, ResourceOwnerPasswordCredentialsGrant, +) +from oauthlib.oauth2.rfc6749.tokens import BearerToken + +from ..grant_types import AuthorizationCodeGrant, HybridGrant, ImplicitGrant +from ..grant_types.dispatchers import ( + AuthorizationCodeGrantDispatcher, AuthorizationTokenGrantDispatcher, + ImplicitTokenGrantDispatcher, +) +from ..tokens import JWTToken +from .userinfo import UserInfoEndpoint + + +class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint, + ResourceEndpoint, RevocationEndpoint, UserInfoEndpoint): + + """An all-in-one endpoint featuring all four major grant types.""" + + def __init__(self, request_validator, token_expires_in=None, + token_generator=None, refresh_token_generator=None, + *args, **kwargs): + """Construct a new all-grants-in-one server. + + :param request_validator: An implementation of + oauthlib.oauth2.RequestValidator. + :param token_expires_in: An int or a function to generate a token + expiration offset (in seconds) given a + oauthlib.common.Request object. + :param token_generator: A function to generate a token from a request. + :param refresh_token_generator: A function to generate a token from a + request for the refresh token. + :param kwargs: Extra parameters to pass to authorization-, + token-, resource-, and revocation-endpoint constructors. + """ + self.auth_grant = OAuth2AuthorizationCodeGrant(request_validator) + self.implicit_grant = OAuth2ImplicitGrant(request_validator) + self.password_grant = ResourceOwnerPasswordCredentialsGrant( + request_validator) + self.credentials_grant = ClientCredentialsGrant(request_validator) + self.refresh_grant = RefreshTokenGrant(request_validator) + self.openid_connect_auth = AuthorizationCodeGrant(request_validator) + self.openid_connect_implicit = ImplicitGrant(request_validator) + self.openid_connect_hybrid = HybridGrant(request_validator) + + self.bearer = BearerToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + + self.jwt = JWTToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + + self.auth_grant_choice = AuthorizationCodeGrantDispatcher(default_grant=self.auth_grant, oidc_grant=self.openid_connect_auth) + self.implicit_grant_choice = ImplicitTokenGrantDispatcher(default_grant=self.implicit_grant, oidc_grant=self.openid_connect_implicit) + + # See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations for valid combinations + # internally our AuthorizationEndpoint will ensure they can appear in any order for any valid combination + AuthorizationEndpoint.__init__(self, default_response_type='code', + response_types={ + 'code': self.auth_grant_choice, + 'token': self.implicit_grant_choice, + 'id_token': self.openid_connect_implicit, + 'id_token token': self.openid_connect_implicit, + 'code token': self.openid_connect_hybrid, + 'code id_token': self.openid_connect_hybrid, + 'code id_token token': self.openid_connect_hybrid, + 'none': self.auth_grant + }, + default_token_type=self.bearer) + + self.token_grant_choice = AuthorizationTokenGrantDispatcher(request_validator, default_grant=self.auth_grant, oidc_grant=self.openid_connect_auth) + + TokenEndpoint.__init__(self, default_grant_type='authorization_code', + grant_types={ + 'authorization_code': self.token_grant_choice, + 'password': self.password_grant, + 'client_credentials': self.credentials_grant, + 'refresh_token': self.refresh_grant, + }, + default_token_type=self.bearer) + ResourceEndpoint.__init__(self, default_token='Bearer', + token_types={'Bearer': self.bearer, 'JWT': self.jwt}) + RevocationEndpoint.__init__(self, request_validator) + IntrospectEndpoint.__init__(self, request_validator) + UserInfoEndpoint.__init__(self, request_validator) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/userinfo.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/userinfo.py new file mode 100644 index 0000000000000000000000000000000000000000..7aa2bbe97d34fa5afce4168256aafe1c8ce5fcae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/endpoints/userinfo.py @@ -0,0 +1,106 @@ +""" +oauthlib.openid.connect.core.endpoints.userinfo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module is an implementation of userinfo endpoint. +""" +import json +import logging + +from oauthlib.common import Request +from oauthlib.oauth2.rfc6749 import errors +from oauthlib.oauth2.rfc6749.endpoints.base import ( + BaseEndpoint, catch_errors_and_unavailability, +) +from oauthlib.oauth2.rfc6749.tokens import BearerToken + +log = logging.getLogger(__name__) + + +class UserInfoEndpoint(BaseEndpoint): + """Authorizes access to userinfo resource. + """ + def __init__(self, request_validator): + self.bearer = BearerToken(request_validator, None, None, None) + self.request_validator = request_validator + BaseEndpoint.__init__(self) + + @catch_errors_and_unavailability + def create_userinfo_response(self, uri, http_method='GET', body=None, headers=None): + """Validate BearerToken and return userinfo from RequestValidator + + The UserInfo Endpoint MUST return a + content-type header to indicate which format is being returned. The + content-type of the HTTP response MUST be application/json if the + response body is a text JSON object; the response body SHOULD be encoded + using UTF-8. + """ + request = Request(uri, http_method, body, headers) + request.scopes = ["openid"] + self.validate_userinfo_request(request) + + claims = self.request_validator.get_userinfo_claims(request) + if claims is None: + log.error('Userinfo MUST have claims for %r.', request) + raise errors.ServerError(status_code=500) + + if isinstance(claims, dict): + resp_headers = { + 'Content-Type': 'application/json' + } + if "sub" not in claims: + log.error('Userinfo MUST have "sub" for %r.', request) + raise errors.ServerError(status_code=500) + body = json.dumps(claims) + elif isinstance(claims, str): + resp_headers = { + 'Content-Type': 'application/jwt' + } + body = claims + else: + log.error('Userinfo return unknown response for %r.', request) + raise errors.ServerError(status_code=500) + log.debug('Userinfo access valid for %r.', request) + return resp_headers, body, 200 + + def validate_userinfo_request(self, request): + """Ensure the request is valid. + + 5.3.1. UserInfo Request + The Client sends the UserInfo Request using either HTTP GET or HTTP + POST. The Access Token obtained from an OpenID Connect Authentication + Request MUST be sent as a Bearer Token, per `Section 2`_ of OAuth 2.0 + Bearer Token Usage [RFC6750]. + + It is RECOMMENDED that the request use the HTTP GET method and the + Access Token be sent using the Authorization header field. + + The following is a non-normative example of a UserInfo Request: + + .. code-block:: http + + GET /userinfo HTTP/1.1 + Host: server.example.com + Authorization: Bearer SlAV32hkKG + + 5.3.3. UserInfo Error Response + When an error condition occurs, the UserInfo Endpoint returns an Error + Response as defined in `Section 3`_ of OAuth 2.0 Bearer Token Usage + [RFC6750]. (HTTP errors unrelated to RFC 6750 are returned to the User + Agent using the appropriate HTTP status code.) + + The following is a non-normative example of a UserInfo Error Response: + + .. code-block:: http + + HTTP/1.1 401 Unauthorized + WWW-Authenticate: Bearer error="invalid_token", + error_description="The Access Token expired" + + .. _`Section 2`: https://datatracker.ietf.org/doc/html/rfc6750#section-2 + .. _`Section 3`: https://datatracker.ietf.org/doc/html/rfc6750#section-3 + """ + if not self.bearer.validate_request(request): + raise errors.InvalidTokenError() + if "openid" not in request.scopes: + raise errors.InsufficientScopeError() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..099b84e2da9e43ed1d6a7424f42952572d6ee79c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/exceptions.py @@ -0,0 +1,149 @@ +""" +oauthlib.oauth2.rfc6749.errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Error used both by OAuth 2 clients and providers to represent the spec +defined error responses for all four core grant types. +""" +from oauthlib.oauth2.rfc6749.errors import FatalClientError, OAuth2Error + + +class FatalOpenIDClientError(FatalClientError): + pass + + +class OpenIDClientError(OAuth2Error): + pass + + +class InteractionRequired(OpenIDClientError): + """ + The Authorization Server requires End-User interaction to proceed. + + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface for End-User interaction. + """ + error = 'interaction_required' + status_code = 401 + + +class LoginRequired(OpenIDClientError): + """ + The Authorization Server requires End-User authentication. + + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface for End-User authentication. + """ + error = 'login_required' + status_code = 401 + + +class AccountSelectionRequired(OpenIDClientError): + """ + The End-User is REQUIRED to select a session at the Authorization Server. + + The End-User MAY be authenticated at the Authorization Server with + different associated accounts, but the End-User did not select a session. + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface to prompt for a session to + use. + """ + error = 'account_selection_required' + + +class ConsentRequired(OpenIDClientError): + """ + The Authorization Server requires End-User consent. + + This error MAY be returned when the prompt parameter value in the + Authentication Request is none, but the Authentication Request cannot be + completed without displaying a user interface for End-User consent. + """ + error = 'consent_required' + status_code = 401 + + +class InvalidRequestURI(OpenIDClientError): + """ + The request_uri in the Authorization Request returns an error or + contains invalid data. + """ + error = 'invalid_request_uri' + description = 'The request_uri in the Authorization Request returns an ' \ + 'error or contains invalid data.' + + +class InvalidRequestObject(OpenIDClientError): + """ + The request parameter contains an invalid Request Object. + """ + error = 'invalid_request_object' + description = 'The request parameter contains an invalid Request Object.' + + +class RequestNotSupported(OpenIDClientError): + """ + The OP does not support use of the request parameter. + """ + error = 'request_not_supported' + description = 'The request parameter is not supported.' + + +class RequestURINotSupported(OpenIDClientError): + """ + The OP does not support use of the request_uri parameter. + """ + error = 'request_uri_not_supported' + description = 'The request_uri parameter is not supported.' + + +class RegistrationNotSupported(OpenIDClientError): + """ + The OP does not support use of the registration parameter. + """ + error = 'registration_not_supported' + description = 'The registration parameter is not supported.' + + +class InvalidTokenError(OAuth2Error): + """ + The access token provided is expired, revoked, malformed, or + invalid for other reasons. The resource SHOULD respond with + the HTTP 401 (Unauthorized) status code. The client MAY + request a new access token and retry the protected resource + request. + """ + error = 'invalid_token' + status_code = 401 + description = ("The access token provided is expired, revoked, malformed, " + "or invalid for other reasons.") + + +class InsufficientScopeError(OAuth2Error): + """ + The request requires higher privileges than provided by the + access token. The resource server SHOULD respond with the HTTP + 403 (Forbidden) status code and MAY include the "scope" + attribute with the scope necessary to access the protected + resource. + """ + error = 'insufficient_scope' + status_code = 403 + description = ("The request requires higher privileges than provided by " + "the access token.") + + +def raise_from_error(error, params=None): + import inspect + import sys + kwargs = { + 'description': params.get('error_description'), + 'uri': params.get('error_uri'), + 'state': params.get('state') + } + for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): + if cls.error == error: + raise cls(**kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8dad5f607b9856704b3f074d31f3b701ddfafd94 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__init__.py @@ -0,0 +1,13 @@ +""" +oauthlib.openid.connect.core.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +from .authorization_code import AuthorizationCodeGrant +from .base import GrantTypeBase +from .dispatchers import ( + AuthorizationCodeGrantDispatcher, AuthorizationTokenGrantDispatcher, + ImplicitTokenGrantDispatcher, +) +from .hybrid import HybridGrant +from .implicit import ImplicitGrant +from .refresh_token import RefreshTokenGrant diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1ad401ffa99a87d7063ae3c1528c39e0c33db81 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/authorization_code.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/authorization_code.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f043883e9fbc81e19c55c1f3968f6584a2b5455c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/authorization_code.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..faecbcfc35ca6714ed6c943a3d6a52cf5dfdcabb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/dispatchers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/dispatchers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9ffb8968b8e74b88a2fae9f82164ca52eeb2244 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/dispatchers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/hybrid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/hybrid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a772b0adc8f3b6df0f497176c58feaa867fe4165 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/hybrid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/implicit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/implicit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a65f4d6e9cc7b0deefa2cb8863fd6bb1810c7a16 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/implicit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/refresh_token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/refresh_token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea40fa0882ae9c25ec9cc8b8164d3bf35d30d5d8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/__pycache__/refresh_token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/authorization_code.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/authorization_code.py new file mode 100644 index 0000000000000000000000000000000000000000..6b2dcc3bdd12d27d280890494286efc5f0c9befb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/authorization_code.py @@ -0,0 +1,43 @@ +""" +oauthlib.openid.connect.core.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib.oauth2.rfc6749.grant_types.authorization_code import ( + AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant, +) + +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class AuthorizationCodeGrant(GrantTypeBase): + + def __init__(self, request_validator=None, **kwargs): + self.proxy_target = OAuth2AuthorizationCodeGrant( + request_validator=request_validator, **kwargs) + self.custom_validators.post_auth.append( + self.openid_authorization_validator) + self.register_token_modifier(self.add_id_token) + + def add_id_token(self, token, token_handler, request): + """ + Construct an initial version of id_token, and let the + request_validator sign or encrypt it. + + The authorization_code version of this method is used to + retrieve the nonce accordingly to the code storage. + """ + # Treat it as normal OAuth 2 auth code request if openid is not present + if not request.scopes or 'openid' not in request.scopes: + return token + + nonce = self.request_validator.get_authorization_code_nonce( + request.client_id, + request.code, + request.redirect_uri, + request + ) + return super().add_id_token(token, token_handler, request, nonce=nonce) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/base.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/base.py new file mode 100644 index 0000000000000000000000000000000000000000..33411dad751da5e5cde6d77c286e9988fd548d01 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/base.py @@ -0,0 +1,326 @@ +import base64 +import hashlib +import logging +import time +from json import loads + +from oauthlib.oauth2.rfc6749.errors import ( + ConsentRequired, InvalidRequestError, LoginRequired, +) + +log = logging.getLogger(__name__) + + +class GrantTypeBase: + + # Just proxy the majority of method calls through to the + # proxy_target grant type handler, which will usually be either + # the standard OAuth2 AuthCode or Implicit grant types. + def __getattr__(self, attr): + return getattr(self.proxy_target, attr) + + def __setattr__(self, attr, value): + proxied_attrs = {'refresh_token', 'response_types'} + if attr in proxied_attrs: + setattr(self.proxy_target, attr, value) + else: + super(OpenIDConnectBase, self).__setattr__(attr, value) + + def validate_authorization_request(self, request): + """Validates the OpenID Connect authorization request parameters. + + :returns: (list of scopes, dict of request info) + """ + return self.proxy_target.validate_authorization_request(request) + + def _inflate_claims(self, request): + # this may be called multiple times in a single request so make sure we only de-serialize the claims once + if request.claims and not isinstance(request.claims, dict): + # specific claims are requested during the Authorization Request and may be requested for inclusion + # in either the id_token or the UserInfo endpoint response + # see http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter + try: + request.claims = loads(request.claims) + except Exception as ex: + raise InvalidRequestError(description="Malformed claims parameter", + uri="http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter") + + def id_token_hash(self, value, hashfunc=hashlib.sha256): + """ + Its value is the base64url encoding of the left-most half of the + hash of the octets of the ASCII representation of the access_token + value, where the hash algorithm used is the hash algorithm used in + the alg Header Parameter of the ID Token's JOSE Header. + + For instance, if the alg is RS256, hash the access_token value + with SHA-256, then take the left-most 128 bits and + base64url-encode them. + For instance, if the alg is HS512, hash the code value with + SHA-512, then take the left-most 256 bits and base64url-encode + them. The c_hash value is a case-sensitive string. + + Example of hash from OIDC specification (bound to a JWS using RS256): + + code: + Qcb0Orv1zh30vL1MPRsbm-diHiMwcLyZvn1arpZv-Jxf_11jnpEX3Tgfvk + + c_hash: + LDktKdoQak3Pk0cnXxCltA + """ + digest = hashfunc(value.encode()).digest() + left_most = len(digest) // 2 + return base64.urlsafe_b64encode(digest[:left_most]).decode().rstrip("=") + + def add_id_token(self, token, token_handler, request, nonce=None): + """ + Construct an initial version of id_token, and let the + request_validator sign or encrypt it. + + The initial version can contain the fields below, accordingly + to the spec: + - aud + - iat + - nonce + - at_hash + - c_hash + """ + # Treat it as normal OAuth 2 auth code request if openid is not present + if not request.scopes or 'openid' not in request.scopes: + return token + + # Only add an id token on auth/token step if asked for. + if request.response_type and 'id_token' not in request.response_type: + return token + + # Implementation mint its own id_token without help. + id_token = self.request_validator.get_id_token(token, token_handler, request) + if id_token: + token['id_token'] = id_token + return token + + # Fallback for asking some help from oauthlib framework. + # Start with technicals fields bound to the specification. + id_token = {} + id_token['aud'] = request.client_id + id_token['iat'] = int(time.time()) + + # nonce is REQUIRED when response_type value is: + # - id_token token (Implicit) + # - id_token (Implicit) + # - code id_token (Hybrid) + # - code id_token token (Hybrid) + # + # nonce is OPTIONAL when response_type value is: + # - code (Authorization Code) + # - code token (Hybrid) + if nonce is not None: + id_token["nonce"] = nonce + + # at_hash is REQUIRED when response_type value is: + # - id_token token (Implicit) + # - code id_token token (Hybrid) + # + # at_hash is OPTIONAL when: + # - code (Authorization code) + # - code id_token (Hybrid) + # - code token (Hybrid) + # + # at_hash MAY NOT be used when: + # - id_token (Implicit) + if "access_token" in token: + id_token["at_hash"] = self.id_token_hash(token["access_token"]) + + # c_hash is REQUIRED when response_type value is: + # - code id_token (Hybrid) + # - code id_token token (Hybrid) + # + # c_hash is OPTIONAL for others. + if "code" in token: + id_token["c_hash"] = self.id_token_hash(token["code"]) + + # Call request_validator to complete/sign/encrypt id_token + token['id_token'] = self.request_validator.finalize_id_token(id_token, token, token_handler, request) + + return token + + def openid_authorization_validator(self, request): + """Perform OpenID Connect specific authorization request validation. + + nonce + OPTIONAL. String value used to associate a Client session with + an ID Token, and to mitigate replay attacks. The value is + passed through unmodified from the Authentication Request to + the ID Token. Sufficient entropy MUST be present in the nonce + values used to prevent attackers from guessing values + + display + OPTIONAL. ASCII string value that specifies how the + Authorization Server displays the authentication and consent + user interface pages to the End-User. The defined values are: + + page - The Authorization Server SHOULD display the + authentication and consent UI consistent with a full User + Agent page view. If the display parameter is not specified, + this is the default display mode. + + popup - The Authorization Server SHOULD display the + authentication and consent UI consistent with a popup User + Agent window. The popup User Agent window should be of an + appropriate size for a login-focused dialog and should not + obscure the entire window that it is popping up over. + + touch - The Authorization Server SHOULD display the + authentication and consent UI consistent with a device that + leverages a touch interface. + + wap - The Authorization Server SHOULD display the + authentication and consent UI consistent with a "feature + phone" type display. + + The Authorization Server MAY also attempt to detect the + capabilities of the User Agent and present an appropriate + display. + + prompt + OPTIONAL. Space delimited, case sensitive list of ASCII string + values that specifies whether the Authorization Server prompts + the End-User for reauthentication and consent. The defined + values are: + + none - The Authorization Server MUST NOT display any + authentication or consent user interface pages. An error is + returned if an End-User is not already authenticated or the + Client does not have pre-configured consent for the + requested Claims or does not fulfill other conditions for + processing the request. The error code will typically be + login_required, interaction_required, or another code + defined in Section 3.1.2.6. This can be used as a method to + check for existing authentication and/or consent. + + login - The Authorization Server SHOULD prompt the End-User + for reauthentication. If it cannot reauthenticate the + End-User, it MUST return an error, typically + login_required. + + consent - The Authorization Server SHOULD prompt the + End-User for consent before returning information to the + Client. If it cannot obtain consent, it MUST return an + error, typically consent_required. + + select_account - The Authorization Server SHOULD prompt the + End-User to select a user account. This enables an End-User + who has multiple accounts at the Authorization Server to + select amongst the multiple accounts that they might have + current sessions for. If it cannot obtain an account + selection choice made by the End-User, it MUST return an + error, typically account_selection_required. + + The prompt parameter can be used by the Client to make sure + that the End-User is still present for the current session or + to bring attention to the request. If this parameter contains + none with any other value, an error is returned. + + max_age + OPTIONAL. Maximum Authentication Age. Specifies the allowable + elapsed time in seconds since the last time the End-User was + actively authenticated by the OP. If the elapsed time is + greater than this value, the OP MUST attempt to actively + re-authenticate the End-User. (The max_age request parameter + corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] max_auth_age + request parameter.) When max_age is used, the ID Token returned + MUST include an auth_time Claim Value. + + ui_locales + OPTIONAL. End-User's preferred languages and scripts for the + user interface, represented as a space-separated list of BCP47 + [RFC5646] language tag values, ordered by preference. For + instance, the value "fr-CA fr en" represents a preference for + French as spoken in Canada, then French (without a region + designation), followed by English (without a region + designation). An error SHOULD NOT result if some or all of the + requested locales are not supported by the OpenID Provider. + + id_token_hint + OPTIONAL. ID Token previously issued by the Authorization + Server being passed as a hint about the End-User's current or + past authenticated session with the Client. If the End-User + identified by the ID Token is logged in or is logged in by the + request, then the Authorization Server returns a positive + response; otherwise, it SHOULD return an error, such as + login_required. When possible, an id_token_hint SHOULD be + present when prompt=none is used and an invalid_request error + MAY be returned if it is not; however, the server SHOULD + respond successfully when possible, even if it is not present. + The Authorization Server need not be listed as an audience of + the ID Token when it is used as an id_token_hint value. If the + ID Token received by the RP from the OP is encrypted, to use it + as an id_token_hint, the Client MUST decrypt the signed ID + Token contained within the encrypted ID Token. The Client MAY + re-encrypt the signed ID token to the Authentication Server + using a key that enables the server to decrypt the ID Token, + and use the re-encrypted ID token as the id_token_hint value. + + login_hint + OPTIONAL. Hint to the Authorization Server about the login + identifier the End-User might use to log in (if necessary). + This hint can be used by an RP if it first asks the End-User + for their e-mail address (or other identifier) and then wants + to pass that value as a hint to the discovered authorization + service. It is RECOMMENDED that the hint value match the value + used for discovery. This value MAY also be a phone number in + the format specified for the phone_number Claim. The use of + this parameter is left to the OP's discretion. + + acr_values + OPTIONAL. Requested Authentication Context Class Reference + values. Space-separated string that specifies the acr values + that the Authorization Server is being requested to use for + processing this Authentication Request, with the values + appearing in order of preference. The Authentication Context + Class satisfied by the authentication performed is returned as + the acr Claim Value, as specified in Section 2. The acr Claim + is requested as a Voluntary Claim by this parameter. + """ + + # Treat it as normal OAuth 2 auth code request if openid is not present + if not request.scopes or 'openid' not in request.scopes: + return {} + + prompt = request.prompt if request.prompt else [] + if hasattr(prompt, 'split'): + prompt = prompt.strip().split() + prompt = set(prompt) + + if 'none' in prompt: + + if len(prompt) > 1: + msg = "Prompt none is mutually exclusive with other values." + raise InvalidRequestError(request=request, description=msg) + + if not self.request_validator.validate_silent_login(request): + raise LoginRequired(request=request) + + if not self.request_validator.validate_silent_authorization(request): + raise ConsentRequired(request=request) + + self._inflate_claims(request) + + if not self.request_validator.validate_user_match( + request.id_token_hint, request.scopes, request.claims, request): + msg = "Session user does not match client supplied user." + raise LoginRequired(request=request, description=msg) + + request_info = { + 'display': request.display, + 'nonce': request.nonce, + 'prompt': prompt, + 'ui_locales': request.ui_locales.split() if request.ui_locales else [], + 'id_token_hint': request.id_token_hint, + 'login_hint': request.login_hint, + 'claims': request.claims + } + + return request_info + + +OpenIDConnectBase = GrantTypeBase diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/dispatchers.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/dispatchers.py new file mode 100644 index 0000000000000000000000000000000000000000..5aa7d4698bb963b39873aee6b115e8bcbd2d3842 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/dispatchers.py @@ -0,0 +1,101 @@ +import logging + +log = logging.getLogger(__name__) + + +class Dispatcher: + default_grant = None + oidc_grant = None + + +class AuthorizationCodeGrantDispatcher(Dispatcher): + """ + This is an adapter class that will route simple Authorization Code + requests, those that have `response_type=code` and a scope including + `openid` to either the `default_grant` or the `oidc_grant` based on + the scopes requested. + """ + def __init__(self, default_grant=None, oidc_grant=None): + self.default_grant = default_grant + self.oidc_grant = oidc_grant + + def _handler_for_request(self, request): + handler = self.default_grant + + if request.scopes and "openid" in request.scopes: + handler = self.oidc_grant + + log.debug('Selecting handler for request %r.', handler) + return handler + + def create_authorization_response(self, request, token_handler): + """Read scope and route to the designated handler.""" + return self._handler_for_request(request).create_authorization_response(request, token_handler) + + def validate_authorization_request(self, request): + """Read scope and route to the designated handler.""" + return self._handler_for_request(request).validate_authorization_request(request) + + +class ImplicitTokenGrantDispatcher(Dispatcher): + """ + This is an adapter class that will route simple Authorization + requests, those that have `id_token` in `response_type` and a scope + including `openid` to either the `default_grant` or the `oidc_grant` + based on the scopes requested. + """ + def __init__(self, default_grant=None, oidc_grant=None): + self.default_grant = default_grant + self.oidc_grant = oidc_grant + + def _handler_for_request(self, request): + handler = self.default_grant + + if request.scopes and "openid" in request.scopes and 'id_token' in request.response_type: + handler = self.oidc_grant + + log.debug('Selecting handler for request %r.', handler) + return handler + + def create_authorization_response(self, request, token_handler): + """Read scope and route to the designated handler.""" + return self._handler_for_request(request).create_authorization_response(request, token_handler) + + def validate_authorization_request(self, request): + """Read scope and route to the designated handler.""" + return self._handler_for_request(request).validate_authorization_request(request) + + +class AuthorizationTokenGrantDispatcher(Dispatcher): + """ + This is an adapter class that will route simple Token requests, those that authorization_code have a scope + including 'openid' to either the default_grant or the oidc_grant based on the scopes requested. + """ + def __init__(self, request_validator, default_grant=None, oidc_grant=None): + self.default_grant = default_grant + self.oidc_grant = oidc_grant + self.request_validator = request_validator + + def _handler_for_request(self, request): + handler = self.default_grant + scopes = () + parameters = dict(request.decoded_body) + client_id = parameters.get('client_id', None) + code = parameters.get('code', None) + redirect_uri = parameters.get('redirect_uri', None) + + # If code is not present fallback to `default_grant` which will + # raise an error for the missing `code` in `create_token_response` step. + if code: + scopes = self.request_validator.get_authorization_code_scopes(client_id, code, redirect_uri, request) + + if 'openid' in scopes: + handler = self.oidc_grant + + log.debug('Selecting handler for request %r.', handler) + return handler + + def create_token_response(self, request, token_handler): + """Read scope and route to the designated handler.""" + handler = self._handler_for_request(request) + return handler.create_token_response(request, token_handler) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/hybrid.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/hybrid.py new file mode 100644 index 0000000000000000000000000000000000000000..7cb0758b81ee5891b0ef8500c028b4b16a586997 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/hybrid.py @@ -0,0 +1,63 @@ +""" +oauthlib.openid.connect.core.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib.oauth2.rfc6749.errors import InvalidRequestError +from oauthlib.oauth2.rfc6749.grant_types.authorization_code import ( + AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant, +) + +from ..request_validator import RequestValidator +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class HybridGrant(GrantTypeBase): + + def __init__(self, request_validator=None, **kwargs): + self.request_validator = request_validator or RequestValidator() + + self.proxy_target = OAuth2AuthorizationCodeGrant( + request_validator=request_validator, **kwargs) + # All hybrid response types should be fragment-encoded. + self.proxy_target.default_response_mode = "fragment" + self.register_response_type('code id_token') + self.register_response_type('code token') + self.register_response_type('code id_token token') + self.custom_validators.post_auth.append( + self.openid_authorization_validator) + # Hybrid flows can return the id_token from the authorization + # endpoint as part of the 'code' response + self.register_code_modifier(self.add_token) + self.register_code_modifier(self.add_id_token) + self.register_token_modifier(self.add_id_token) + + def add_id_token(self, token, token_handler, request): + return super().add_id_token(token, token_handler, request, nonce=request.nonce) + + def openid_authorization_validator(self, request): + """Additional validation when following the Authorization Code flow. + """ + request_info = super().openid_authorization_validator(request) + if not request_info: # returns immediately if OAuth2.0 + return request_info + + # REQUIRED if the Response Type of the request is `code + # id_token` or `code id_token token` and OPTIONAL when the + # Response Type of the request is `code token`. It is a string + # value used to associate a Client session with an ID Token, + # and to mitigate replay attacks. The value is passed through + # unmodified from the Authentication Request to the ID + # Token. Sufficient entropy MUST be present in the `nonce` + # values used to prevent attackers from guessing values. For + # implementation notes, see Section 15.5.2. + if request.response_type in ["code id_token", "code id_token token"]: + if not request.nonce: + raise InvalidRequestError( + request=request, + description='Request is missing mandatory nonce parameter.' + ) + return request_info diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/implicit.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/implicit.py new file mode 100644 index 0000000000000000000000000000000000000000..a4fe6049bc29a8d9b202b9e0244a1b6c559d99d6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/implicit.py @@ -0,0 +1,51 @@ +""" +oauthlib.openid.connect.core.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib.oauth2.rfc6749.errors import InvalidRequestError +from oauthlib.oauth2.rfc6749.grant_types.implicit import ( + ImplicitGrant as OAuth2ImplicitGrant, +) + +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class ImplicitGrant(GrantTypeBase): + + def __init__(self, request_validator=None, **kwargs): + self.proxy_target = OAuth2ImplicitGrant( + request_validator=request_validator, **kwargs) + self.register_response_type('id_token') + self.register_response_type('id_token token') + self.custom_validators.post_auth.append( + self.openid_authorization_validator) + self.register_token_modifier(self.add_id_token) + + def add_id_token(self, token, token_handler, request): + if 'state' not in token and request.state: + token['state'] = request.state + return super().add_id_token(token, token_handler, request, nonce=request.nonce) + + def openid_authorization_validator(self, request): + """Additional validation when following the implicit flow. + """ + request_info = super().openid_authorization_validator(request) + if not request_info: # returns immediately if OAuth2.0 + return request_info + + # REQUIRED. String value used to associate a Client session with an ID + # Token, and to mitigate replay attacks. The value is passed through + # unmodified from the Authentication Request to the ID Token. + # Sufficient entropy MUST be present in the nonce values used to + # prevent attackers from guessing values. For implementation notes, see + # Section 15.5.2. + if not request.nonce: + raise InvalidRequestError( + request=request, + description='Request is missing mandatory nonce parameter.' + ) + return request_info diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/refresh_token.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/refresh_token.py new file mode 100644 index 0000000000000000000000000000000000000000..43e4499c53c77a7f1486981f84e7fe49cf71f545 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/grant_types/refresh_token.py @@ -0,0 +1,34 @@ +""" +oauthlib.openid.connect.core.grant_types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib.oauth2.rfc6749.grant_types.refresh_token import ( + RefreshTokenGrant as OAuth2RefreshTokenGrant, +) + +from .base import GrantTypeBase + +log = logging.getLogger(__name__) + + +class RefreshTokenGrant(GrantTypeBase): + + def __init__(self, request_validator=None, **kwargs): + self.proxy_target = OAuth2RefreshTokenGrant( + request_validator=request_validator, **kwargs) + self.register_token_modifier(self.add_id_token) + + def add_id_token(self, token, token_handler, request): + """ + Construct an initial version of id_token, and let the + request_validator sign or encrypt it. + + The authorization_code version of this method is used to + retrieve the nonce accordingly to the code storage. + """ + if not self.request_validator.refresh_id_token(request): + return token + + return super().add_id_token(token, token_handler, request) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/request_validator.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/request_validator.py new file mode 100644 index 0000000000000000000000000000000000000000..47c4cd9406fb02a32d50bcdfb15c37df8312a464 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/request_validator.py @@ -0,0 +1,320 @@ +""" +oauthlib.openid.connect.core.request_validator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" +import logging + +from oauthlib.oauth2.rfc6749.request_validator import ( + RequestValidator as OAuth2RequestValidator, +) + +log = logging.getLogger(__name__) + + +class RequestValidator(OAuth2RequestValidator): + + def get_authorization_code_scopes(self, client_id, code, redirect_uri, request): + """ Extracts scopes from saved authorization code. + + The scopes returned by this method is used to route token requests + based on scopes passed to Authorization Code requests. + + With that the token endpoint knows when to include OpenIDConnect + id_token in token response only based on authorization code scopes. + + Only code param should be sufficient to retrieve grant code from + any storage you are using, `client_id` and `redirect_uri` can have a + blank value `""` don't forget to check it before using those values + in a select query if a database is used. + + :param client_id: Unicode client identifier + :param code: Unicode authorization code grant + :param redirect_uri: Unicode absolute URI + :return: A list of scope + + Method is used by: + - Authorization Token Grant Dispatcher + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_authorization_code_nonce(self, client_id, code, redirect_uri, request): + """ Extracts nonce from saved authorization code. + + If present in the Authentication Request, Authorization + Servers MUST include a nonce Claim in the ID Token with the + Claim Value being the nonce value sent in the Authentication + Request. Authorization Servers SHOULD perform no other + processing on nonce values used. The nonce value is a + case-sensitive string. + + Only code param should be sufficient to retrieve grant code from + any storage you are using. However, `client_id` and `redirect_uri` + have been validated and can be used also. + + :param client_id: Unicode client identifier + :param code: Unicode authorization code grant + :param redirect_uri: Unicode absolute URI + :return: Unicode nonce + + Method is used by: + - Authorization Token Grant Dispatcher + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_jwt_bearer_token(self, token, token_handler, request): + """Get JWT Bearer token or OpenID Connect ID token + + If using OpenID Connect this SHOULD call `oauthlib.oauth2.RequestValidator.get_id_token` + + :param token: A Bearer token dict + :param token_handler: the token handler (BearerToken class) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :return: The JWT Bearer token or OpenID Connect ID token (a JWS signed JWT) + + Method is used by JWT Bearer and OpenID Connect tokens: + - JWTToken.create_token + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_id_token(self, token, token_handler, request): + """Get OpenID Connect ID token + + This method is OPTIONAL and is NOT RECOMMENDED. + `finalize_id_token` SHOULD be implemented instead. However, if you + want a full control over the minting of the `id_token`, you + MAY want to override `get_id_token` instead of using + `finalize_id_token`. + + In the OpenID Connect workflows when an ID Token is requested this method is called. + Subclasses should implement the construction, signing and optional encryption of the + ID Token as described in the OpenID Connect spec. + + In addition to the standard OAuth2 request properties, the request may also contain + these OIDC specific properties which are useful to this method: + + - nonce, if workflow is implicit or hybrid and it was provided + - claims, if provided to the original Authorization Code request + + The token parameter is a dict which may contain an ``access_token`` entry, in which + case the resulting ID Token *should* include a calculated ``at_hash`` claim. + + Similarly, when the request parameter has a ``code`` property defined, the ID Token + *should* include a calculated ``c_hash`` claim. + + http://openid.net/specs/openid-connect-core-1_0.html (sections `3.1.3.6`_, `3.2.2.10`_, `3.3.2.11`_) + + .. _`3.1.3.6`: http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken + .. _`3.2.2.10`: http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDToken + .. _`3.3.2.11`: http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken + + :param token: A Bearer token dict + :param token_handler: the token handler (BearerToken class) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :return: The ID Token (a JWS signed JWT) + """ + return None + + def finalize_id_token(self, id_token, token, token_handler, request): + """Finalize OpenID Connect ID token & Sign or Encrypt. + + In the OpenID Connect workflows when an ID Token is requested + this method is called. Subclasses should implement the + construction, signing and optional encryption of the ID Token + as described in the OpenID Connect spec. + + The `id_token` parameter is a dict containing a couple of OIDC + technical fields related to the specification. Prepopulated + attributes are: + + - `aud`, equals to `request.client_id`. + - `iat`, equals to current time. + - `nonce`, if present, is equals to the `nonce` from the + authorization request. + - `at_hash`, hash of `access_token`, if relevant. + - `c_hash`, hash of `code`, if relevant. + + This method MUST provide required fields as below: + + - `iss`, REQUIRED. Issuer Identifier for the Issuer of the response. + - `sub`, REQUIRED. Subject Identifier + - `exp`, REQUIRED. Expiration time on or after which the ID + Token MUST NOT be accepted by the RP when performing + authentication with the OP. + + Additionals claims must be added, note that `request.scope` + should be used to determine the list of claims. + + More information can be found at `OpenID Connect Core#Claims`_ + + .. _`OpenID Connect Core#Claims`: https://openid.net/specs/openid-connect-core-1_0.html#Claims + + :param id_token: A dict containing technical fields of id_token + :param token: A Bearer token dict + :param token_handler: the token handler (BearerToken class) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :return: The ID Token (a JWS signed JWT or JWE encrypted JWT) + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_jwt_bearer_token(self, token, scopes, request): + """Ensure the JWT Bearer token or OpenID Connect ID token are valids and authorized access to scopes. + + If using OpenID Connect this SHOULD call `oauthlib.oauth2.RequestValidator.get_id_token` + + If not using OpenID Connect this can `return None` to avoid 5xx rather 401/3 response. + + OpenID connect core 1.0 describe how to validate an id_token: + - http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation + - http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2 + + :param token: Unicode Bearer token + :param scopes: List of scopes (defined by you) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is indirectly used by all core OpenID connect JWT token issuing grant types: + - Authorization Code Grant + - Implicit Grant + - Hybrid Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_id_token(self, token, scopes, request): + """Ensure the id token is valid and authorized access to scopes. + + OpenID connect core 1.0 describe how to validate an id_token: + - http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation + - http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2 + + :param token: Unicode Bearer token + :param scopes: List of scopes (defined by you) + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is indirectly used by all core OpenID connect JWT token issuing grant types: + - Authorization Code Grant + - Implicit Grant + - Hybrid Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_silent_authorization(self, request): + """Ensure the logged in user has authorized silent OpenID authorization. + + Silent OpenID authorization allows access tokens and id tokens to be + granted to clients without any user prompt or interaction. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - OpenIDConnectAuthCode + - OpenIDConnectImplicit + - OpenIDConnectHybrid + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_silent_login(self, request): + """Ensure session user has authorized silent OpenID login. + + If no user is logged in or has not authorized silent login, this + method should return False. + + If the user is logged in but associated with multiple accounts and + not selected which one to link to the token then this method should + raise an oauthlib.oauth2.AccountSelectionRequired error. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - OpenIDConnectAuthCode + - OpenIDConnectImplicit + - OpenIDConnectHybrid + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_user_match(self, id_token_hint, scopes, claims, request): + """Ensure client supplied user id hint matches session user. + + If the sub claim or id_token_hint is supplied then the session + user must match the given ID. + + :param id_token_hint: User identifier string. + :param scopes: List of OAuth 2 scopes and OpenID claims (strings). + :param claims: OpenID Connect claims dict. + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + - OpenIDConnectAuthCode + - OpenIDConnectImplicit + - OpenIDConnectHybrid + """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_userinfo_claims(self, request): + """Return the UserInfo claims in JSON or Signed or Encrypted. + + The UserInfo Claims MUST be returned as the members of a JSON object + unless a signed or encrypted response was requested during Client + Registration. The Claims defined in Section 5.1 can be returned, as can + additional Claims not specified there. + + For privacy reasons, OpenID Providers MAY elect to not return values for + some requested Claims. + + If a Claim is not returned, that Claim Name SHOULD be omitted from the + JSON object representing the Claims; it SHOULD NOT be present with a + null or empty string value. + + The sub (subject) Claim MUST always be returned in the UserInfo + Response. + + Upon receipt of the UserInfo Request, the UserInfo Endpoint MUST return + the JSON Serialization of the UserInfo Response as in Section 13.3 in + the HTTP response body unless a different format was specified during + Registration [OpenID.Registration]. + + If the UserInfo Response is signed and/or encrypted, then the Claims are + returned in a JWT and the content-type MUST be application/jwt. The + response MAY be encrypted without also being signed. If both signing and + encryption are requested, the response MUST be signed then encrypted, + with the result being a Nested JWT, as defined in [JWT]. + + If signed, the UserInfo Response SHOULD contain the Claims iss (issuer) + and aud (audience) as members. The iss value SHOULD be the OP's Issuer + Identifier URL. The aud value SHOULD be or include the RP's Client ID + value. + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: Claims as a dict OR JWT/JWS/JWE as a string + + Method is used by: + UserInfoEndpoint + """ + + def refresh_id_token(self, request): + """Whether the id token should be refreshed. Default, True + + :param request: OAuthlib request. + :type request: oauthlib.common.Request + :rtype: True or False + + Method is used by: + RefreshTokenGrant + """ + return True diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/tokens.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/tokens.py new file mode 100644 index 0000000000000000000000000000000000000000..936ab52e3865f8ab0d1c96ef4cf9f9fd41279e14 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/openid/connect/core/tokens.py @@ -0,0 +1,48 @@ +""" +authlib.openid.connect.core.tokens +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods for adding JWT tokens to requests. +""" +from oauthlib.oauth2.rfc6749.tokens import ( + TokenBase, get_token_from_header, random_token_generator, +) + + +class JWTToken(TokenBase): + __slots__ = ( + 'request_validator', 'token_generator', + 'refresh_token_generator', 'expires_in' + ) + + def __init__(self, request_validator=None, token_generator=None, + expires_in=None, refresh_token_generator=None): + self.request_validator = request_validator + self.token_generator = token_generator or random_token_generator + self.refresh_token_generator = ( + refresh_token_generator or self.token_generator + ) + self.expires_in = expires_in or 3600 + + def create_token(self, request, refresh_token=False): + """Create a JWT Token, using requestvalidator method.""" + + if callable(self.expires_in): + expires_in = self.expires_in(request) + else: + expires_in = self.expires_in + + request.expires_in = expires_in + + return self.request_validator.get_jwt_bearer_token(None, None, request) + + def validate_request(self, request): + token = get_token_from_header(request) + return self.request_validator.validate_jwt_bearer_token( + token, request.scopes, request) + + def estimate_type(self, request): + token = get_token_from_header(request) + if token and token.startswith('ey') and token.count('.') in (2, 4): + return 10 + return 0 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/signals.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/signals.py new file mode 100644 index 0000000000000000000000000000000000000000..8fd347a5c8b88a9beb8c390acb800d128be18ae4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/signals.py @@ -0,0 +1,40 @@ +""" + Implements signals based on blinker if available, otherwise + falls silently back to a noop. Shamelessly stolen from flask.signals: + https://github.com/mitsuhiko/flask/blob/master/flask/signals.py +""" +signals_available = False +try: + from blinker import Namespace + signals_available = True +except ImportError: # noqa + class Namespace: + def signal(self, name, doc=None): + return _FakeSignal(name, doc) + + class _FakeSignal: + """If blinker is unavailable, create a fake class with the same + interface that allows sending of signals but will fail with an + error on anything else. Instead of doing anything on send, it + will just ignore the arguments and do nothing instead. + """ + + def __init__(self, name, doc=None): + self.name = name + self.__doc__ = doc + def _fail(self, *args, **kwargs): + raise RuntimeError('signalling support is unavailable ' + 'because the blinker library is ' + 'not installed.') + send = lambda *a, **kw: None + connect = disconnect = has_receivers_for = receivers_for = \ + temporarily_connected_to = connected_to = _fail + del _fail + +# The namespace for code signals. If you are not oauthlib code, do +# not put signals in here. Create your own namespace instead. +_signals = Namespace() + + +# Core signals. +scope_changed = _signals.signal('scope-changed') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/uri_validate.py b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/uri_validate.py new file mode 100644 index 0000000000000000000000000000000000000000..a6fe0fb23e05f1ecd34a4fcd6a5cbb17aa091af9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/oauthlib/uri_validate.py @@ -0,0 +1,190 @@ +""" +Regex for URIs + +These regex are directly derived from the collected ABNF in RFC3986 +(except for DIGIT, ALPHA and HEXDIG, defined by RFC2234). + +They should be processed with re.VERBOSE. + +Thanks Mark Nottingham for this code - https://gist.github.com/138549 +""" +import re + +# basics + +DIGIT = r"[\x30-\x39]" + +ALPHA = r"[\x41-\x5A\x61-\x7A]" + +HEXDIG = r"[\x30-\x39A-Fa-f]" + +# pct-encoded = "%" HEXDIG HEXDIG +pct_encoded = r" %% %(HEXDIG)s %(HEXDIG)s" % locals() + +# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +unreserved = r"(?: %(ALPHA)s | %(DIGIT)s | \- | \. | _ | ~ )" % locals() + +# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" +gen_delims = r"(?: : | / | \? | \# | \[ | \] | @ )" + +# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +# / "*" / "+" / "," / ";" / "=" +sub_delims = r"""(?: ! | \$ | & | ' | \( | \) | + \* | \+ | , | ; | = )""" + +# pchar = unreserved / pct-encoded / sub-delims / ":" / "@" +pchar = r"(?: %(unreserved)s | %(pct_encoded)s | %(sub_delims)s | : | @ )" % locals( +) + +# reserved = gen-delims / sub-delims +reserved = r"(?: %(gen_delims)s | %(sub_delims)s )" % locals() + + +# scheme + +# scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +scheme = r"%(ALPHA)s (?: %(ALPHA)s | %(DIGIT)s | \+ | \- | \. )*" % locals() + + +# authority + +# dec-octet = DIGIT ; 0-9 +# / %x31-39 DIGIT ; 10-99 +# / "1" 2DIGIT ; 100-199 +# / "2" %x30-34 DIGIT ; 200-249 +# / "25" %x30-35 ; 250-255 +dec_octet = r"""(?: %(DIGIT)s | + [\x31-\x39] %(DIGIT)s | + 1 %(DIGIT)s{2} | + 2 [\x30-\x34] %(DIGIT)s | + 25 [\x30-\x35] + ) +""" % locals() + +# IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet +IPv4address = r"%(dec_octet)s \. %(dec_octet)s \. %(dec_octet)s \. %(dec_octet)s" % locals( +) + +# IPv6address +IPv6address = r"([A-Fa-f0-9:]+[:$])[A-Fa-f0-9]{1,4}" + +# IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) +IPvFuture = r"v %(HEXDIG)s+ \. (?: %(unreserved)s | %(sub_delims)s | : )+" % locals() + +# IP-literal = "[" ( IPv6address / IPvFuture ) "]" +IP_literal = r"\[ (?: %(IPv6address)s | %(IPvFuture)s ) \]" % locals() + +# reg-name = *( unreserved / pct-encoded / sub-delims ) +reg_name = r"(?: %(unreserved)s | %(pct_encoded)s | %(sub_delims)s )*" % locals() + +# userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) +userinfo = r"(?: %(unreserved)s | %(pct_encoded)s | %(sub_delims)s | : )" % locals( +) + +# host = IP-literal / IPv4address / reg-name +host = r"(?: %(IP_literal)s | %(IPv4address)s | %(reg_name)s )" % locals() + +# port = *DIGIT +port = r"(?: %(DIGIT)s )*" % locals() + +# authority = [ userinfo "@" ] host [ ":" port ] +authority = r"(?: %(userinfo)s @)? %(host)s (?: : %(port)s)?" % locals() + +# Path + +# segment = *pchar +segment = r"%(pchar)s*" % locals() + +# segment-nz = 1*pchar +segment_nz = r"%(pchar)s+" % locals() + +# segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) +# ; non-zero-length segment without any colon ":" +segment_nz_nc = r"(?: %(unreserved)s | %(pct_encoded)s | %(sub_delims)s | @ )+" % locals() + +# path-abempty = *( "/" segment ) +path_abempty = r"(?: / %(segment)s )*" % locals() + +# path-absolute = "/" [ segment-nz *( "/" segment ) ] +path_absolute = r"/ (?: %(segment_nz)s (?: / %(segment)s )* )?" % locals() + +# path-noscheme = segment-nz-nc *( "/" segment ) +path_noscheme = r"%(segment_nz_nc)s (?: / %(segment)s )*" % locals() + +# path-rootless = segment-nz *( "/" segment ) +path_rootless = r"%(segment_nz)s (?: / %(segment)s )*" % locals() + +# path-empty = 0<pchar> +path_empty = r"" # FIXME + +# path = path-abempty ; begins with "/" or is empty +# / path-absolute ; begins with "/" but not "//" +# / path-noscheme ; begins with a non-colon segment +# / path-rootless ; begins with a segment +# / path-empty ; zero characters +path = r"""(?: %(path_abempty)s | + %(path_absolute)s | + %(path_noscheme)s | + %(path_rootless)s | + %(path_empty)s + ) +""" % locals() + +### Query and Fragment + +# query = *( pchar / "/" / "?" ) +query = r"(?: %(pchar)s | / | \? )*" % locals() + +# fragment = *( pchar / "/" / "?" ) +fragment = r"(?: %(pchar)s | / | \? )*" % locals() + +# URIs + +# hier-part = "//" authority path-abempty +# / path-absolute +# / path-rootless +# / path-empty +hier_part = r"""(?: (?: // %(authority)s %(path_abempty)s ) | + %(path_absolute)s | + %(path_rootless)s | + %(path_empty)s + ) +""" % locals() + +# relative-part = "//" authority path-abempty +# / path-absolute +# / path-noscheme +# / path-empty +relative_part = r"""(?: (?: // %(authority)s %(path_abempty)s ) | + %(path_absolute)s | + %(path_noscheme)s | + %(path_empty)s + ) +""" % locals() + +# relative-ref = relative-part [ "?" query ] [ "#" fragment ] +relative_ref = r"%(relative_part)s (?: \? %(query)s)? (?: \# %(fragment)s)?" % locals( +) + +# URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +URI = r"^(?: %(scheme)s : %(hier_part)s (?: \? %(query)s )? (?: \# %(fragment)s )? )$" % locals( +) + +# URI-reference = URI / relative-ref +URI_reference = r"^(?: %(URI)s | %(relative_ref)s )$" % locals() + +# absolute-URI = scheme ":" hier-part [ "?" query ] +absolute_URI = r"^(?: %(scheme)s : %(hier_part)s (?: \? %(query)s )? )$" % locals( +) + + +def is_uri(uri): + return re.match(URI, uri, re.VERBOSE) + + +def is_uri_reference(uri): + return re.match(URI_reference, uri, re.VERBOSE) + + +def is_absolute_uri(uri): + return re.match(absolute_URI, uri, re.VERBOSE) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8fb62d5a8e2137a0dce4cdcbb196f141f3da8afb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/__init__.py @@ -0,0 +1,49 @@ +#-*- coding: utf-8 -*- +""" +This package is an implementation of the OpenID specification in +Python. It contains code for both server and consumer +implementations. For information on implementing an OpenID consumer, +see the C{L{openid.consumer.consumer}} module. For information on +implementing an OpenID server, see the C{L{openid.server.server}} +module. + +@contact: U{http://github.com/necaris/python3-openid/} + +@copyright: (C) 2005-2008 JanRain, Inc., 2012-2017 Rami Chowdhury + +@license: Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + U{http://www.apache.org/licenses/LICENSE-2.0} + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions + and limitations under the License. +""" + +version_info = (3, 2, 0) + + + + +__version__ = ".".join(str(x) for x in version_info) + +__all__ = [ + 'association', + 'consumer', + 'cryptutil', + 'dh', + 'extension', + 'extensions', + 'fetchers', + 'kvform', + 'message', + 'oidutil', + 'server', + 'sreg', + 'store', + 'urinorm', + 'yadis', +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43e76fc5af9801e598b44d686c99fe5314d504ca Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/association.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/association.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c22916bf72c90f2be14e7afcd1dca784ba6ec07 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/association.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/codecutil.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/codecutil.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f06532e7a8425d5cb67e9d5cc1f4960333423a64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/codecutil.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/cryptutil.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/cryptutil.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..096f7870226a82bbced26c9c878a98ad46dc9c3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/cryptutil.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/dh.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/dh.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3939d5131490ece576283390dd7e329b70ced5c6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/dh.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/extension.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/extension.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7b76536dcccf79da7e000949eb123c4fa5a60ad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/extension.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/fetchers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/fetchers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51f17fffad00bdbe8da1afa4cf6ea2afc832068f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/fetchers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/kvform.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/kvform.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d5c86e8be0ff285d6a6f51ccd24c63de7c224aa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/kvform.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/message.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/message.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d814b5799764c79b6a3ad7a5610eadb738c0a59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/message.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/oidutil.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/oidutil.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12257a7e714b06003e16fda738c638e74b0a326a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/oidutil.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/sreg.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/sreg.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be59dd6b606bbed81ab91e6ad832882c26c1df4b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/sreg.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/urinorm.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/urinorm.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c154294ff82e2de5ee0d1a15dd4e255cc17d07f0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/__pycache__/urinorm.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/association.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/association.py new file mode 100644 index 0000000000000000000000000000000000000000..94d68d71ac0a18dcbe8fb12f9f99ff1127163eb0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/association.py @@ -0,0 +1,562 @@ +#-*-test-case-name: openid.test.test_association-*- +#-*- coding: utf-8 -*- +""" +This module contains code for dealing with associations between +consumers and servers. Associations contain a shared secret that is +used to sign C{openid.mode=id_res} messages. + +Users of the library should not usually need to interact directly with +associations. The L{store<openid.store>}, L{server<openid.server.server>} +and L{consumer<openid.consumer.consumer>} objects will create and manage +the associations. The consumer and server code will make use of a +C{L{SessionNegotiator}} when managing associations, which enables +users to express a preference for what kind of associations should be +allowed, and what kind of exchange should be done to establish the +association. + +@var default_negotiator: A C{L{SessionNegotiator}} that allows all + association types that are specified by the OpenID + specification. It prefers to use HMAC-SHA1/DH-SHA1, if it's + available. If HMAC-SHA256 is not supported by your Python runtime, + HMAC-SHA256 and DH-SHA256 will not be available. + +@var encrypted_negotiator: A C{L{SessionNegotiator}} that + does not support C{'no-encryption'} associations. It prefers + HMAC-SHA1/DH-SHA1 association types if available. +""" +import time +import functools + +from openid import cryptutil +from openid import kvform +from openid import oidutil +from openid.message import OPENID_NS + +__all__ = [ + 'default_negotiator', + 'encrypted_negotiator', + 'SessionNegotiator', + 'Association', +] + +all_association_types = [ + 'HMAC-SHA1', + 'HMAC-SHA256', +] + +if hasattr(cryptutil, 'hmacSha256'): + supported_association_types = list(all_association_types) + + default_association_order = [ + ('HMAC-SHA1', 'DH-SHA1'), + ('HMAC-SHA1', 'no-encryption'), + ('HMAC-SHA256', 'DH-SHA256'), + ('HMAC-SHA256', 'no-encryption'), + ] + + only_encrypted_association_order = [ + ('HMAC-SHA1', 'DH-SHA1'), + ('HMAC-SHA256', 'DH-SHA256'), + ] +else: + supported_association_types = ['HMAC-SHA1'] + + default_association_order = [ + ('HMAC-SHA1', 'DH-SHA1'), + ('HMAC-SHA1', 'no-encryption'), + ] + + only_encrypted_association_order = [ + ('HMAC-SHA1', 'DH-SHA1'), + ] + + +def getSessionTypes(assoc_type): + """Return the allowed session types for a given association type""" + assoc_to_session = { + 'HMAC-SHA1': ['DH-SHA1', 'no-encryption'], + 'HMAC-SHA256': ['DH-SHA256', 'no-encryption'], + } + return assoc_to_session.get(assoc_type, []) + + +def checkSessionType(assoc_type, session_type): + """Check to make sure that this pair of assoc type and session + type are allowed""" + if session_type not in getSessionTypes(assoc_type): + raise ValueError('Session type %r not valid for assocation type %r' % + (session_type, assoc_type)) + + +class SessionNegotiator(object): + """A session negotiator controls the allowed and preferred + association types and association session types. Both the + C{L{Consumer<openid.consumer.consumer.Consumer>}} and + C{L{Server<openid.server.server.Server>}} use negotiators when + creating associations. + + You can create and use negotiators if you: + + - Do not want to do Diffie-Hellman key exchange because you use + transport-layer encryption (e.g. SSL) + + - Want to use only SHA-256 associations + + - Do not want to support plain-text associations over a non-secure + channel + + It is up to you to set a policy for what kinds of associations to + accept. By default, the library will make any kind of association + that is allowed in the OpenID 2.0 specification. + + Use of negotiators in the library + ================================= + + When a consumer makes an association request, it calls + C{L{getAllowedType}} to get the preferred association type and + association session type. + + The server gets a request for a particular association/session + type and calls C{L{isAllowed}} to determine if it should + create an association. If it is supported, negotiation is + complete. If it is not, the server calls C{L{getAllowedType}} to + get an allowed association type to return to the consumer. + + If the consumer gets an error response indicating that the + requested association/session type is not supported by the server + that contains an assocation/session type to try, it calls + C{L{isAllowed}} to determine if it should try again with the + given combination of association/session type. + + @ivar allowed_types: A list of association/session types that are + allowed by the server. The order of the pairs in this list + determines preference. If an association/session type comes + earlier in the list, the library is more likely to use that + type. + @type allowed_types: [(str, str)] + """ + + def __init__(self, allowed_types): + self.setAllowedTypes(allowed_types) + + def copy(self): + return self.__class__(list(self.allowed_types)) + + def setAllowedTypes(self, allowed_types): + """Set the allowed association types, checking to make sure + each combination is valid.""" + for (assoc_type, session_type) in allowed_types: + checkSessionType(assoc_type, session_type) + + self.allowed_types = allowed_types + + def addAllowedType(self, assoc_type, session_type=None): + """Add an association type and session type to the allowed + types list. The assocation/session pairs are tried in the + order that they are added.""" + if self.allowed_types is None: + self.allowed_types = [] + + if session_type is None: + available = getSessionTypes(assoc_type) + + if not available: + raise ValueError('No session available for association type %r' + % (assoc_type, )) + + for session_type in getSessionTypes(assoc_type): + self.addAllowedType(assoc_type, session_type) + else: + checkSessionType(assoc_type, session_type) + self.allowed_types.append((assoc_type, session_type)) + + def isAllowed(self, assoc_type, session_type): + """Is this combination of association type and session type allowed?""" + assoc_good = (assoc_type, session_type) in self.allowed_types + matches = session_type in getSessionTypes(assoc_type) + return assoc_good and matches + + def getAllowedType(self): + """Get a pair of assocation type and session type that are + supported""" + try: + return self.allowed_types[0] + except IndexError: + return (None, None) + + +default_negotiator = SessionNegotiator(default_association_order) +encrypted_negotiator = SessionNegotiator(only_encrypted_association_order) + + +def getSecretSize(assoc_type): + if assoc_type == 'HMAC-SHA1': + return 20 + elif assoc_type == 'HMAC-SHA256': + return 32 + else: + raise ValueError('Unsupported association type: %r' % (assoc_type, )) + + +@functools.total_ordering +class Association(object): + """ + This class represents an association between a server and a + consumer. In general, users of this library will never see + instances of this object. The only exception is if you implement + a custom C{L{OpenIDStore<openid.store.interface.OpenIDStore>}}. + + If you do implement such a store, it will need to store the values + of the C{L{handle}}, C{L{secret}}, C{L{issued}}, C{L{lifetime}}, and + C{L{assoc_type}} instance variables. + + @ivar handle: This is the handle the server gave this association. + + @type handle: C{str} + + + @ivar secret: This is the shared secret the server generated for + this association. + + @type secret: C{str} + + + @ivar issued: This is the time this association was issued, in + seconds since 00:00 GMT, January 1, 1970. (ie, a unix + timestamp) + + @type issued: C{int} + + + @ivar lifetime: This is the amount of time this association is + good for, measured in seconds since the association was + issued. + + @type lifetime: C{int} + + + @ivar assoc_type: This is the type of association this instance + represents. The only valid value of this field at this time + is C{'HMAC-SHA1'}, but new types may be defined in the future. + + @type assoc_type: C{str} + + + @sort: __init__, fromExpiresIn, expiresIn, __eq__, __ne__, + handle, secret, issued, lifetime, assoc_type + """ + + # The ordering and name of keys as stored by serialize + assoc_keys = [ + 'version', + 'handle', + 'secret', + 'issued', + 'lifetime', + 'assoc_type', + ] + + _macs = { + 'HMAC-SHA1': cryptutil.hmacSha1, + 'HMAC-SHA256': cryptutil.hmacSha256, + } + + @classmethod + def fromExpiresIn(cls, expires_in, handle, secret, assoc_type): + """ + This is an alternate constructor used by the OpenID consumer + library to create associations. C{L{OpenIDStore + <openid.store.interface.OpenIDStore>}} implementations + shouldn't use this constructor. + + + @param expires_in: This is the amount of time this association + is good for, measured in seconds since the association was + issued. + + @type expires_in: C{int} + + + @param handle: This is the handle the server gave this + association. + + @type handle: C{str} + + + @param secret: This is the shared secret the server generated + for this association. + + @type secret: C{str} + + + @param assoc_type: This is the type of association this + instance represents. The only valid value of this field + at this time is C{'HMAC-SHA1'}, but new types may be + defined in the future. + + @type assoc_type: C{str} + """ + issued = int(time.time()) + lifetime = expires_in + return cls(handle, secret, issued, lifetime, assoc_type) + + def __init__(self, handle, secret, issued, lifetime, assoc_type): + """ + This is the standard constructor for creating an association. + + + @param handle: This is the handle the server gave this + association. + + @type handle: C{str} + + + @param secret: This is the shared secret the server generated + for this association. + + @type secret: C{str} + + + @param issued: This is the time this association was issued, + in seconds since 00:00 GMT, January 1, 1970. (ie, a unix + timestamp) + + @type issued: C{int} + + + @param lifetime: This is the amount of time this association + is good for, measured in seconds since the association was + issued. + + @type lifetime: C{int} + + + @param assoc_type: This is the type of association this + instance represents. The only valid value of this field + at this time is C{'HMAC-SHA1'}, but new types may be + defined in the future. + + @type assoc_type: C{str} + """ + if assoc_type not in all_association_types: + fmt = '%r is not a supported association type' + raise ValueError(fmt % (assoc_type, )) + + # secret_size = getSecretSize(assoc_type) + # if len(secret) != secret_size: + # fmt = 'Wrong size secret (%s bytes) for association type %s' + # raise ValueError(fmt % (len(secret), assoc_type)) + + self.handle = handle + + if isinstance(secret, str): + secret = secret.encode("utf-8") # should be bytes + self.secret = secret + + self.issued = issued + self.lifetime = lifetime + self.assoc_type = assoc_type + + @property + def expiresIn(self, now=None): + """ + This returns the number of seconds this association is still + valid for, or C{0} if the association is no longer valid. + + + @return: The number of seconds this association is still valid + for, or C{0} if the association is no longer valid. + + @rtype: C{int} + """ + if now is None: + now = int(time.time()) + + return max(0, self.issued + self.lifetime - now) + + def __lt__(self, other): + """ + Compare two C{L{Association}} instances to determine relative + ordering. + + Currently compares object lifetimes -- C{L{Association}} A < B + if A.lifetime < B.lifetime. + """ + return self.lifetime < other.lifetime + + def __eq__(self, other): + """ + This checks to see if two C{L{Association}} instances + represent the same association. + + + @return: C{True} if the two instances represent the same + association, C{False} otherwise. + + @rtype: C{bool} + """ + return type(self) is type(other) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + """ + This checks to see if two C{L{Association}} instances + represent different associations. + + + @return: C{True} if the two instances represent different + associations, C{False} otherwise. + + @rtype: C{bool} + """ + return not (self == other) + + def serialize(self): + """ + Convert an association to KV form. + + @return: String in KV form suitable for deserialization by + deserialize. + + @rtype: str + """ + data = { + 'version': '2', + 'handle': self.handle, + 'secret': oidutil.toBase64(self.secret), + 'issued': str(int(self.issued)), + 'lifetime': str(int(self.lifetime)), + 'assoc_type': self.assoc_type + } + + assert len(data) == len(self.assoc_keys) + + pairs = [] + for field_name in self.assoc_keys: + pairs.append((field_name, data[field_name])) + + return kvform.seqToKV(pairs, strict=True) + + @classmethod + def deserialize(cls, assoc_s): + """ + Parse an association as stored by serialize(). + + inverse of serialize + + @param assoc_s: Association as serialized by serialize() + @type assoc_s: bytes + + @return: instance of this class + """ + pairs = kvform.kvToSeq(assoc_s, strict=True) + keys = [] + values = [] + for k, v in pairs: + keys.append(k) + values.append(v) + + if keys != cls.assoc_keys: + raise ValueError('Unexpected key values: %r', keys) + + version, handle, secret, issued, lifetime, assoc_type = values + if version != '2': + raise ValueError('Unknown version: %r' % version) + issued = int(issued) + lifetime = int(lifetime) + secret = oidutil.fromBase64(secret) + return cls(handle, secret, issued, lifetime, assoc_type) + + def sign(self, pairs): + """ + Generate a signature for a sequence of (key, value) pairs + + + @param pairs: The pairs to sign, in order + @type pairs: sequence of (str, str) + + + @return: The binary signature of this sequence of pairs + @rtype: bytes + """ + kv = kvform.seqToKV(pairs) + + try: + mac = self._macs[self.assoc_type] + except KeyError: + raise ValueError('Unknown association type: %r' % + (self.assoc_type, )) + + return mac(self.secret, kv) + + def getMessageSignature(self, message): + """Return the signature of a message. + + If I am not a sign-all association, the message must have a + signed list. + + @return: the signature, base64 encoded + + @rtype: bytes + + @raises ValueError: If there is no signed list and I am not a sign-all + type of association. + """ + pairs = self._makePairs(message) + return oidutil.toBase64(self.sign(pairs)) + + def signMessage(self, message): + """Add a signature (and a signed list) to a message. + + @return: a new Message object with a signature + @rtype: L{openid.message.Message} + """ + if (message.hasKey(OPENID_NS, 'sig') or + message.hasKey(OPENID_NS, 'signed')): + raise ValueError('Message already has signed list or signature') + + extant_handle = message.getArg(OPENID_NS, 'assoc_handle') + if extant_handle and extant_handle != self.handle: + raise ValueError("Message has a different association handle") + + signed_message = message.copy() + signed_message.setArg(OPENID_NS, 'assoc_handle', self.handle) + message_keys = list(signed_message.toPostArgs().keys()) + signed_list = [k[7:] for k in message_keys if k.startswith('openid.')] + signed_list.append('signed') + signed_list.sort() + signed_message.setArg(OPENID_NS, 'signed', ','.join(signed_list)) + sig = self.getMessageSignature(signed_message) + signed_message.setArg(OPENID_NS, 'sig', sig) + return signed_message + + def checkMessageSignature(self, message): + """Given a message with a signature, calculate a new signature + and return whether it matches the signature in the message. + + @raises ValueError: if the message has no signature or no signature + can be calculated for it. + """ + message_sig = message.getArg(OPENID_NS, 'sig') + if not message_sig: + raise ValueError("%s has no sig." % (message, )) + calculated_sig = self.getMessageSignature(message) + # remember, getMessageSignature returns bytes + calculated_sig = calculated_sig.decode('utf-8') + return cryptutil.const_eq(calculated_sig, message_sig) + + def _makePairs(self, message): + signed = message.getArg(OPENID_NS, 'signed') + if not signed: + raise ValueError('Message has no signed list: %s' % (message, )) + + signed_list = signed.split(',') + pairs = [] + data = message.toPostArgs() + for field in signed_list: + pairs.append((field, data.get('openid.' + field, ''))) + return pairs + + def __repr__(self): + return "<%s.%s %s %s>" % (self.__class__.__module__, + self.__class__.__name__, self.assoc_type, + self.handle) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/codecutil.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/codecutil.py new file mode 100644 index 0000000000000000000000000000000000000000..d8b9fe962a893a67c5643946f755e73b062b9cd9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/codecutil.py @@ -0,0 +1,91 @@ +import codecs + +try: + chr(0x10000) +except ValueError: + # narrow python build + UCSCHAR = [ + (0xA0, 0xD7FF), + (0xF900, 0xFDCF), + (0xFDF0, 0xFFEF), + ] + + IPRIVATE = [ + (0xE000, 0xF8FF), + ] +else: + UCSCHAR = [ + (0xA0, 0xD7FF), + (0xF900, 0xFDCF), + (0xFDF0, 0xFFEF), + (0x10000, 0x1FFFD), + (0x20000, 0x2FFFD), + (0x30000, 0x3FFFD), + (0x40000, 0x4FFFD), + (0x50000, 0x5FFFD), + (0x60000, 0x6FFFD), + (0x70000, 0x7FFFD), + (0x80000, 0x8FFFD), + (0x90000, 0x9FFFD), + (0xA0000, 0xAFFFD), + (0xB0000, 0xBFFFD), + (0xC0000, 0xCFFFD), + (0xD0000, 0xDFFFD), + (0xE1000, 0xEFFFD), + ] + + IPRIVATE = [ + (0xE000, 0xF8FF), + (0xF0000, 0xFFFFD), + (0x100000, 0x10FFFD), + ] + +_ESCAPE_RANGES = UCSCHAR + IPRIVATE + + +def _in_escape_range(octet): + for start, end in _ESCAPE_RANGES: + if start <= octet <= end: + return True + return False + + +def _starts_surrogate_pair(character): + char_value = ord(character) + return 0xD800 <= char_value <= 0xDBFF + + +def _ends_surrogate_pair(character): + char_value = ord(character) + return 0xDC00 <= char_value <= 0xDFFF + + +def _pct_encoded_replacements(chunk): + replacements = [] + chunk_iter = iter(chunk) + for character in chunk_iter: + codepoint = ord(character) + if _in_escape_range(codepoint): + for char in chr(codepoint).encode("utf-8"): + replacements.append("%%%X" % char) + elif _starts_surrogate_pair(character): + next_character = next(chunk_iter) + for char in (character + next_character).encode("utf-8"): + replacements.append("%%%X" % char) + else: + replacements.append(chr(codepoint)) + return replacements + + +def _pct_escape_handler(err): + ''' + Encoding error handler that does percent-escaping of Unicode, to be used + with codecs.register_error + TODO: replace use of this with urllib.parse.quote as appropriate + ''' + chunk = err.object[err.start:err.end] + replacements = _pct_encoded_replacements(chunk) + return ("".join(replacements), err.end) + + +codecs.register_error("oid_percent_escape", _pct_escape_handler) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..aab51a293c3106c0d637c737226f6820c54269fc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__init__.py @@ -0,0 +1,6 @@ +""" +This package contains the portions of the library used only when +implementing an OpenID consumer. +""" + +__all__ = ['consumer', 'discover'] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..537656d9ebd6016e0fd02630ecc78aabdb765d63 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/consumer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/consumer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df0830d9cc06f709b7d7fa66c17289a43f529057 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/consumer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/discover.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/discover.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c599a57241524a4296d333125bfe4afed780d16 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/discover.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/html_parse.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/html_parse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6949115ed3bd8b345eb0bf04b1d7490623637b2d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/__pycache__/html_parse.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/consumer.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/consumer.py new file mode 100644 index 0000000000000000000000000000000000000000..ea390ecfb6157b62d5c751564ff5ecf9075115e1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/consumer.py @@ -0,0 +1,1925 @@ +# -*- test-case-name: openid.test.test_consumer -*- +"""OpenID support for Relying Parties (aka Consumers). + +This module documents the main interface with the OpenID consumer +library. The only part of the library which has to be used and isn't +documented in full here is the store required to create an +C{L{Consumer}} instance. More on the abstract store type and +concrete implementations of it that are provided in the documentation +for the C{L{__init__<Consumer.__init__>}} method of the +C{L{Consumer}} class. + + +OVERVIEW +======== + + The OpenID identity verification process most commonly uses the + following steps, as visible to the user of this library: + + 1. The user enters their OpenID into a field on the consumer's + site, and hits a login button. + + 2. The consumer site discovers the user's OpenID provider using + the Yadis protocol. + + 3. The consumer site sends the browser a redirect to the + OpenID provider. This is the authentication request as + described in the OpenID specification. + + 4. The OpenID provider's site sends the browser a redirect + back to the consumer site. This redirect contains the + provider's response to the authentication request. + + The most important part of the flow to note is the consumer's site + must handle two separate HTTP requests in order to perform the + full identity check. + + +LIBRARY DESIGN +============== + + This consumer library is designed with that flow in mind. The + goal is to make it as easy as possible to perform the above steps + securely. + + At a high level, there are two important parts in the consumer + library. The first important part is this module, which contains + the interface to actually use this library. The second is the + C{L{openid.store.interface}} module, which describes the + interface to use if you need to create a custom method for storing + the state this library needs to maintain between requests. + + In general, the second part is less important for users of the + library to know about, as several implementations are provided + which cover a wide variety of situations in which consumers may + use the library. + + This module contains a class, C{L{Consumer}}, with methods + corresponding to the actions necessary in each of steps 2, 3, and + 4 described in the overview. Use of this library should be as easy + as creating an C{L{Consumer}} instance and calling the methods + appropriate for the action the site wants to take. + + +SESSIONS, STORES, AND STATELESS MODE +==================================== + + The C{L{Consumer}} object keeps track of two types of state: + + 1. State of the user's current authentication attempt. Things like + the identity URL, the list of endpoints discovered for that + URL, and in case where some endpoints are unreachable, the list + of endpoints already tried. This state needs to be held from + Consumer.begin() to Consumer.complete(), but it is only applicable + to a single session with a single user agent, and at the end of + the authentication process (i.e. when an OP replies with either + C{id_res} or C{cancel}) it may be discarded. + + 2. State of relationships with servers, i.e. shared secrets + (associations) with servers and nonces seen on signed messages. + This information should persist from one session to the next and + should not be bound to a particular user-agent. + + + These two types of storage are reflected in the first two arguments of + Consumer's constructor, C{session} and C{store}. C{session} is a + dict-like object and we hope your web framework provides you with one + of these bound to the user agent. C{store} is an instance of + L{openid.store.interface.OpenIDStore}. + + Since the store does hold secrets shared between your application and the + OpenID provider, you should be careful about how you use it in a shared + hosting environment. If the filesystem or database permissions of your + web host allow strangers to read from them, do not store your data there! + If you have no safe place to store your data, construct your consumer + with C{None} for the store, and it will operate only in stateless mode. + Stateless mode may be slower, put more load on the OpenID provider, and + trusts the provider to keep you safe from replay attacks. + + + Several store implementation are provided, and the interface is + fully documented so that custom stores can be used as well. See + the documentation for the C{L{Consumer}} class for more + information on the interface for stores. The implementations that + are provided allow the consumer site to store the necessary data + in several different ways, including several SQL databases and + normal files on disk. + + +IMMEDIATE MODE +============== + + In the flow described above, the user may need to confirm to the + OpenID provider that it's ok to disclose his or her identity. + The provider may draw pages asking for information from the user + before it redirects the browser back to the consumer's site. This + is generally transparent to the consumer site, so it is typically + ignored as an implementation detail. + + There can be times, however, where the consumer site wants to get + a response immediately. When this is the case, the consumer can + put the library in immediate mode. In immediate mode, there is an + extra response possible from the server, which is essentially the + server reporting that it doesn't have enough information to answer + the question yet. + + +USING THIS LIBRARY +================== + + Integrating this library into an application is usually a + relatively straightforward process. The process should basically + follow this plan: + + Add an OpenID login field somewhere on your site. When an OpenID + is entered in that field and the form is submitted, it should make + a request to your site which includes that OpenID URL. + + First, the application should L{instantiate a Consumer<Consumer.__init__>} + with a session for per-user state and store for shared state. + using the store of choice. + + Next, the application should call the 'C{L{begin<Consumer.begin>}}' method on the + C{L{Consumer}} instance. This method takes the OpenID URL. The + C{L{begin<Consumer.begin>}} method returns an C{L{AuthRequest}} + object. + + Next, the application should call the + C{L{redirectURL<AuthRequest.redirectURL>}} method on the + C{L{AuthRequest}} object. The parameter C{return_to} is the URL + that the OpenID server will send the user back to after attempting + to verify his or her identity. The C{realm} parameter is the + URL (or URL pattern) that identifies your web site to the user + when he or she is authorizing it. Send a redirect to the + resulting URL to the user's browser. + + That's the first half of the authentication process. The second + half of the process is done after the user's OpenID Provider sends the + user's browser a redirect back to your site to complete their + login. + + When that happens, the user will contact your site at the URL + given as the C{return_to} URL to the + C{L{redirectURL<AuthRequest.redirectURL>}} call made + above. The request will have several query parameters added to + the URL by the OpenID provider as the information necessary to + finish the request. + + Get a C{L{Consumer}} instance with the same session and store as + before and call its C{L{complete<Consumer.complete>}} method, + passing in all the received query arguments. + + There are multiple possible return types possible from that + method. These indicate whether or not the login was successful, + and include any additional information appropriate for their type. + +@var SUCCESS: constant used as the status for + L{SuccessResponse<openid.consumer.consumer.SuccessResponse>} objects. + +@var FAILURE: constant used as the status for + L{FailureResponse<openid.consumer.consumer.FailureResponse>} objects. + +@var CANCEL: constant used as the status for + L{CancelResponse<openid.consumer.consumer.CancelResponse>} objects. + +@var SETUP_NEEDED: constant used as the status for + L{SetupNeededResponse<openid.consumer.consumer.SetupNeededResponse>} + objects. +""" + +import copy +import logging +from urllib.parse import urlparse, urldefrag, parse_qsl + +from openid import fetchers + +from openid.consumer.discover import discover, OpenIDServiceEndpoint, \ + DiscoveryFailure, OPENID_1_0_TYPE, OPENID_1_1_TYPE, OPENID_2_0_TYPE +from openid.message import Message, OPENID_NS, OPENID2_NS, OPENID1_NS, \ + IDENTIFIER_SELECT, no_default, BARE_NS +from openid import cryptutil +from openid import oidutil +from openid.association import Association, default_negotiator, \ + SessionNegotiator +from openid.dh import DiffieHellman +from openid.store.nonce import mkNonce, split as splitNonce +from openid.yadis.manager import Discovery +from openid import urinorm + +__all__ = [ + 'AuthRequest', + 'Consumer', + 'SuccessResponse', + 'SetupNeededResponse', + 'CancelResponse', + 'FailureResponse', + 'SUCCESS', + 'FAILURE', + 'CANCEL', + 'SETUP_NEEDED', +] + +logger = logging.getLogger(__name__) + +def makeKVPost(request_message, server_url): + """Make a Direct Request to an OpenID Provider and return the + result as a Message object. + + @raises openid.fetchers.HTTPFetchingError: if an error is + encountered in making the HTTP post. + + @rtype: L{openid.message.Message} + """ + # XXX: TESTME + resp = fetchers.fetch(server_url, body=request_message.toURLEncoded()) + + # Process response in separate function that can be shared by async code. + return _httpResponseToMessage(resp, server_url) + + +def _httpResponseToMessage(response, server_url): + """Adapt a POST response to a Message. + + @type response: L{openid.fetchers.HTTPResponse} + @param response: Result of a POST to an OpenID endpoint. + + @rtype: L{openid.message.Message} + + @raises openid.fetchers.HTTPFetchingError: if the server returned a + status of other than 200 or 400. + + @raises ServerError: if the server returned an OpenID error. + """ + # Should this function be named Message.fromHTTPResponse instead? + response_message = Message.fromKVForm(response.body) + if response.status == 400: + raise ServerError.fromMessage(response_message) + + elif response.status not in (200, 206): + fmt = 'bad status code from server %s: %s' + error_message = fmt % (server_url, response.status) + raise fetchers.HTTPFetchingError(error_message) + + return response_message + + +class Consumer(object): + """An OpenID consumer implementation that performs discovery and + does session management. + + @ivar consumer: an instance of an object implementing the OpenID + protocol, but doing no discovery or session management. + + @type consumer: GenericConsumer + + @ivar session: A dictionary-like object representing the user's + session data. This is used for keeping state of the OpenID + transaction when the user is redirected to the server. + + @cvar session_key_prefix: A string that is prepended to session + keys to ensure that they are unique. This variable may be + changed to suit your application. + """ + session_key_prefix = "_openid_consumer_" + + _token = 'last_token' + + _discover = staticmethod(discover) + + def __init__(self, session, store, consumer_class=None): + """Initialize a Consumer instance. + + You should create a new instance of the Consumer object with + every HTTP request that handles OpenID transactions. + + @param session: See L{the session instance variable<openid.consumer.consumer.Consumer.session>} + + @param store: an object that implements the interface in + C{L{openid.store.interface.OpenIDStore}}. Several + implementations are provided, to cover common database + environments. + + @type store: C{L{openid.store.interface.OpenIDStore}} + + @see: L{openid.store.interface} + @see: L{openid.store} + """ + self.session = session + if consumer_class is None: + consumer_class = GenericConsumer + self.consumer = consumer_class(store) + self._token_key = self.session_key_prefix + self._token + + def begin(self, user_url, anonymous=False): + """Start the OpenID authentication process. See steps 1-2 in + the overview at the top of this file. + + @param user_url: Identity URL given by the user. This method + performs a textual transformation of the URL to try and + make sure it is normalized. For example, a user_url of + example.com will be normalized to http://example.com/ + normalizing and resolving any redirects the server might + issue. + + @type user_url: unicode + + @param anonymous: Whether to make an anonymous request of the OpenID + provider. Such a request does not ask for an authorization + assertion for an OpenID identifier, but may be used with + extensions to pass other data. e.g. "I don't care who you are, + but I'd like to know your time zone." + + @type anonymous: bool + + @returns: An object containing the discovered information will + be returned, with a method for building a redirect URL to + the server, as described in step 3 of the overview. This + object may also be used to add extension arguments to the + request, using its + L{addExtensionArg<openid.consumer.consumer.AuthRequest.addExtensionArg>} + method. + + @returntype: L{AuthRequest<openid.consumer.consumer.AuthRequest>} + + @raises openid.consumer.discover.DiscoveryFailure: when I fail to + find an OpenID server for this URL. If the C{yadis} package + is available, L{openid.consumer.discover.DiscoveryFailure} is + an alias for C{yadis.discover.DiscoveryFailure}. + """ + disco = Discovery(self.session, user_url, self.session_key_prefix) + try: + service = disco.getNextService(self._discover) + except fetchers.HTTPFetchingError as why: + raise DiscoveryFailure('Error fetching XRDS document: %s' % + (why.why, ), None) + + if service is None: + raise DiscoveryFailure('No usable OpenID services found for %s' % + (user_url, ), None) + else: + return self.beginWithoutDiscovery(service, anonymous) + + def beginWithoutDiscovery(self, service, anonymous=False): + """Start OpenID verification without doing OpenID server + discovery. This method is used internally by Consumer.begin + after discovery is performed, and exists to provide an + interface for library users needing to perform their own + discovery. + + @param service: an OpenID service endpoint descriptor. This + object and factories for it are found in the + L{openid.consumer.discover} module. + + @type service: + L{OpenIDServiceEndpoint<openid.consumer.discover.OpenIDServiceEndpoint>} + + @returns: an OpenID authentication request object. + + @rtype: L{AuthRequest<openid.consumer.consumer.AuthRequest>} + + @See: Openid.consumer.consumer.Consumer.begin + @see: openid.consumer.discover + """ + auth_req = self.consumer.begin(service) + self.session[self._token_key] = auth_req.endpoint + + try: + auth_req.setAnonymous(anonymous) + except ValueError as why: + raise ProtocolError(str(why)) + + return auth_req + + def complete(self, query, current_url): + """Called to interpret the server's response to an OpenID + request. It is called in step 4 of the flow described in the + consumer overview. + + @param query: A dictionary of the query parameters for this + HTTP request. + + @param current_url: The URL used to invoke the application. + Extract the URL from your application's web + request framework and specify it here to have it checked + against the openid.return_to value in the response. If + the return_to URL check fails, the status of the + completion will be FAILURE. + + @returns: a subclass of Response. The type of response is + indicated by the status attribute, which will be one of + SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED. + + @see: L{SuccessResponse<openid.consumer.consumer.SuccessResponse>} + @see: L{CancelResponse<openid.consumer.consumer.CancelResponse>} + @see: L{SetupNeededResponse<openid.consumer.consumer.SetupNeededResponse>} + @see: L{FailureResponse<openid.consumer.consumer.FailureResponse>} + """ + + endpoint = self.session.get(self._token_key) + + message = Message.fromPostArgs(query) + response = self.consumer.complete(message, endpoint, current_url) + + try: + del self.session[self._token_key] + except KeyError: + pass + + if (response.status in ['success', 'cancel'] and + response.identity_url is not None): + + disco = Discovery(self.session, response.identity_url, + self.session_key_prefix) + # This is OK to do even if we did not do discovery in + # the first place. + disco.cleanup(force=True) + + return response + + def setAssociationPreference(self, association_preferences): + """Set the order in which association types/sessions should be + attempted. For instance, to only allow HMAC-SHA256 + associations created with a DH-SHA256 association session: + + >>> consumer.setAssociationPreference([('HMAC-SHA256', 'DH-SHA256')]) + + Any association type/association type pair that is not in this + list will not be attempted at all. + + @param association_preferences: The list of allowed + (association type, association session type) pairs that + should be allowed for this consumer to use, in order from + most preferred to least preferred. + @type association_preferences: [(str, str)] + + @returns: None + + @see: C{L{openid.association.SessionNegotiator}} + """ + self.consumer.negotiator = SessionNegotiator(association_preferences) + + +class DiffieHellmanSHA1ConsumerSession(object): + session_type = 'DH-SHA1' + hash_func = staticmethod(cryptutil.sha1) + secret_size = 20 + allowed_assoc_types = ['HMAC-SHA1'] + + def __init__(self, dh=None): + if dh is None: + dh = DiffieHellman.fromDefaults() + + self.dh = dh + + def getRequest(self): + cpub = cryptutil.longToBase64(self.dh.public) + + args = {'dh_consumer_public': cpub} + + if not self.dh.usingDefaultValues(): + args.update({ + 'dh_modulus': cryptutil.longToBase64(self.dh.modulus), + 'dh_gen': cryptutil.longToBase64(self.dh.generator), + }) + + return args + + def extractSecret(self, response): + dh_server_public64 = response.getArg(OPENID_NS, 'dh_server_public', + no_default) + enc_mac_key64 = response.getArg(OPENID_NS, 'enc_mac_key', no_default) + dh_server_public = cryptutil.base64ToLong(dh_server_public64) + enc_mac_key = oidutil.fromBase64(enc_mac_key64) + return self.dh.xorSecret(dh_server_public, enc_mac_key, self.hash_func) + + +class DiffieHellmanSHA256ConsumerSession(DiffieHellmanSHA1ConsumerSession): + session_type = 'DH-SHA256' + hash_func = staticmethod(cryptutil.sha256) + secret_size = 32 + allowed_assoc_types = ['HMAC-SHA256'] + + +class PlainTextConsumerSession(object): + session_type = 'no-encryption' + allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256'] + + def getRequest(self): + return {} + + def extractSecret(self, response): + mac_key64 = response.getArg(OPENID_NS, 'mac_key', no_default) + return oidutil.fromBase64(mac_key64) + + +class SetupNeededError(Exception): + """Internally-used exception that indicates that an immediate-mode + request cancelled.""" + + def __init__(self, user_setup_url=None): + Exception.__init__(self, user_setup_url) + self.user_setup_url = user_setup_url + + +class ProtocolError(ValueError): + """Exception that indicates that a message violated the + protocol. It is raised and caught internally to this file.""" + + +class TypeURIMismatch(ProtocolError): + """A protocol error arising from type URIs mismatching + """ + + def __init__(self, expected, endpoint): + ProtocolError.__init__(self, expected, endpoint) + self.expected = expected + self.endpoint = endpoint + + def __str__(self): + s = '<%s.%s: Required type %s not found in %s for endpoint %s>' % ( + self.__class__.__module__, self.__class__.__name__, self.expected, + self.endpoint.type_uris, self.endpoint) + return s + + +class ServerError(Exception): + """Exception that is raised when the server returns a 400 response + code to a direct request.""" + + def __init__(self, error_text, error_code, message): + Exception.__init__(self, error_text) + self.error_text = error_text + self.error_code = error_code + self.message = message + + def fromMessage(cls, message): + """Generate a ServerError instance, extracting the error text + and the error code from the message.""" + error_text = message.getArg(OPENID_NS, 'error', + '<no error message supplied>') + error_code = message.getArg(OPENID_NS, 'error_code') + return cls(error_text, error_code, message) + + fromMessage = classmethod(fromMessage) + + +class GenericConsumer(object): + """This is the implementation of the common logic for OpenID + consumers. It is unaware of the application in which it is + running. + + @ivar negotiator: An object that controls the kind of associations + that the consumer makes. It defaults to + C{L{openid.association.default_negotiator}}. Assign a + different negotiator to it if you have specific requirements + for how associations are made. + @type negotiator: C{L{openid.association.SessionNegotiator}} + """ + + # The name of the query parameter that gets added to the return_to + # URL when using OpenID1. You can change this value if you want or + # need a different name, but don't make it start with openid, + # because it's not a standard protocol thing for OpenID1. For + # OpenID2, the library will take care of the nonce using standard + # OpenID query parameter names. + openid1_nonce_query_arg_name = 'janrain_nonce' + + # Another query parameter that gets added to the return_to for + # OpenID 1; if the user's session state is lost, use this claimed + # identifier to do discovery when verifying the response. + openid1_return_to_identifier_name = 'openid1_claimed_id' + + session_types = { + 'DH-SHA1': DiffieHellmanSHA1ConsumerSession, + 'DH-SHA256': DiffieHellmanSHA256ConsumerSession, + 'no-encryption': PlainTextConsumerSession, + } + + _discover = staticmethod(discover) + + def __init__(self, store): + self.store = store + self.negotiator = default_negotiator.copy() + + def begin(self, service_endpoint): + """Create an AuthRequest object for the specified + service_endpoint. This method will create an association if + necessary.""" + if self.store is None: + assoc = None + else: + assoc = self._getAssociation(service_endpoint) + + request = AuthRequest(service_endpoint, assoc) + request.return_to_args[self.openid1_nonce_query_arg_name] = mkNonce() + + if request.message.isOpenID1(): + request.return_to_args[self.openid1_return_to_identifier_name] = \ + request.endpoint.claimed_id + + return request + + def complete(self, message, endpoint, return_to): + """Process the OpenID message, using the specified endpoint + and return_to URL as context. This method will handle any + OpenID message that is sent to the return_to URL. + """ + mode = message.getArg(OPENID_NS, 'mode', '<No mode set>') + + modeMethod = getattr(self, '_complete_' + mode, self._completeInvalid) + + return modeMethod(message, endpoint, return_to) + + def _complete_cancel(self, message, endpoint, _): + return CancelResponse(endpoint) + + def _complete_error(self, message, endpoint, _): + error = message.getArg(OPENID_NS, 'error') + contact = message.getArg(OPENID_NS, 'contact') + reference = message.getArg(OPENID_NS, 'reference') + + return FailureResponse( + endpoint, error, contact=contact, reference=reference) + + def _complete_setup_needed(self, message, endpoint, _): + if not message.isOpenID2(): + return self._completeInvalid(message, endpoint, _) + + user_setup_url = message.getArg(OPENID2_NS, 'user_setup_url') + return SetupNeededResponse(endpoint, user_setup_url) + + def _complete_id_res(self, message, endpoint, return_to): + try: + self._checkSetupNeeded(message) + except SetupNeededError as why: + return SetupNeededResponse(endpoint, why.user_setup_url) + else: + try: + return self._doIdRes(message, endpoint, return_to) + except (ProtocolError, DiscoveryFailure) as why: + return FailureResponse(endpoint, why) + + def _completeInvalid(self, message, endpoint, _): + mode = message.getArg(OPENID_NS, 'mode', '<No mode set>') + return FailureResponse(endpoint, 'Invalid openid.mode: %r' % (mode, )) + + def _checkReturnTo(self, message, return_to): + """Check an OpenID message and its openid.return_to value + against a return_to URL from an application. Return True on + success, False on failure. + """ + # Check the openid.return_to args against args in the original + # message. + try: + self._verifyReturnToArgs(message.toPostArgs()) + except ProtocolError as why: + logger.exception("Verifying return_to arguments: %s" % (why, )) + return False + + # Check the return_to base URL against the one in the message. + msg_return_to = message.getArg(OPENID_NS, 'return_to') + + # The URL scheme, authority, and path MUST be the same between + # the two URLs. + app_parts = urlparse(urinorm.urinorm(return_to)) + msg_parts = urlparse(urinorm.urinorm(msg_return_to)) + + # (addressing scheme, network location, path) must be equal in + # both URLs. + for part in range(0, 3): + if app_parts[part] != msg_parts[part]: + return False + + return True + + _makeKVPost = staticmethod(makeKVPost) + + def _checkSetupNeeded(self, message): + """Check an id_res message to see if it is a + checkid_immediate cancel response. + + @raises SetupNeededError: if it is a checkid_immediate cancellation + """ + # In OpenID 1, we check to see if this is a cancel from + # immediate mode by the presence of the user_setup_url + # parameter. + if message.isOpenID1(): + user_setup_url = message.getArg(OPENID1_NS, 'user_setup_url') + if user_setup_url is not None: + raise SetupNeededError(user_setup_url) + + def _doIdRes(self, message, endpoint, return_to): + """Handle id_res responses that are not cancellations of + immediate mode requests. + + @param message: the response paramaters. + @param endpoint: the discovered endpoint object. May be None. + + @raises ProtocolError: If the message contents are not + well-formed according to the OpenID specification. This + includes missing fields or not signing fields that should + be signed. + + @raises DiscoveryFailure: If the subject of the id_res message + does not match the supplied endpoint, and discovery on the + identifier in the message fails (this should only happen + when using OpenID 2) + + @returntype: L{Response} + """ + # Checks for presence of appropriate fields (and checks + # signed list fields) + self._idResCheckForFields(message) + + if not self._checkReturnTo(message, return_to): + raise ProtocolError( + "return_to does not match return URL. Expected %r, got %r" % + (return_to, message.getArg(OPENID_NS, 'return_to'))) + + # Verify discovery information: + endpoint = self._verifyDiscoveryResults(message, endpoint) + logger.info("Received id_res response from %s using association %s" % + (endpoint.server_url, + message.getArg(OPENID_NS, 'assoc_handle'))) + + self._idResCheckSignature(message, endpoint.server_url) + + # Will raise a ProtocolError if the nonce is bad + self._idResCheckNonce(message, endpoint) + + signed_list_str = message.getArg(OPENID_NS, 'signed', no_default) + signed_list = signed_list_str.split(',') + signed_fields = ["openid." + s for s in signed_list] + return SuccessResponse(endpoint, message, signed_fields) + + def _idResGetNonceOpenID1(self, message, endpoint): + """Extract the nonce from an OpenID 1 response. Return the + nonce from the BARE_NS since we independently check the + return_to arguments are the same as those in the response + message. + + See the openid1_nonce_query_arg_name class variable + + @returns: The nonce as a string or None + """ + return message.getArg(BARE_NS, self.openid1_nonce_query_arg_name) + + def _idResCheckNonce(self, message, endpoint): + if message.isOpenID1(): + # This indicates that the nonce was generated by the consumer + nonce = self._idResGetNonceOpenID1(message, endpoint) + server_url = '' + else: + nonce = message.getArg(OPENID2_NS, 'response_nonce') + server_url = endpoint.server_url + + if nonce is None: + raise ProtocolError('Nonce missing from response') + + try: + timestamp, salt = splitNonce(nonce) + except ValueError as why: + raise ProtocolError('Malformed nonce: %s' % (why, )) + + if (self.store is not None and + not self.store.useNonce(server_url, timestamp, salt)): + raise ProtocolError('Nonce already used or out of range') + + def _idResCheckSignature(self, message, server_url): + assoc_handle = message.getArg(OPENID_NS, 'assoc_handle') + if self.store is None: + assoc = None + else: + assoc = self.store.getAssociation(server_url, assoc_handle) + + if assoc: + if assoc.expiresIn <= 0: + # XXX: It might be a good idea sometimes to re-start the + # authentication with a new association. Doing it + # automatically opens the possibility for + # denial-of-service by a server that just returns expired + # associations (or really short-lived associations) + raise ProtocolError('Association with %s expired' % + (server_url, )) + + if not assoc.checkMessageSignature(message): + raise ProtocolError('Bad signature') + + else: + # It's not an association we know about. Stateless mode is our + # only possible path for recovery. + # XXX - async framework will not want to block on this call to + # _checkAuth. + if not self._checkAuth(message, server_url): + raise ProtocolError('Server denied check_authentication') + + def _idResCheckForFields(self, message): + # XXX: this should be handled by the code that processes the + # response (that is, if a field is missing, we should not have + # to explicitly check that it's present, just make sure that + # the fields are actually being used by the rest of the code + # in tests). Although, which fields are signed does need to be + # checked somewhere. + basic_fields = ['return_to', 'assoc_handle', 'sig', 'signed'] + basic_sig_fields = ['return_to', 'identity'] + + require_fields = { + OPENID2_NS: basic_fields + ['op_endpoint'], + OPENID1_NS: basic_fields + ['identity'], + } + + require_sigs = { + OPENID2_NS: + basic_sig_fields + + ['response_nonce', 'claimed_id', 'assoc_handle', 'op_endpoint'], + OPENID1_NS: + basic_sig_fields, + } + + for field in require_fields[message.getOpenIDNamespace()]: + if not message.hasKey(OPENID_NS, field): + raise ProtocolError('Missing required field %r' % (field, )) + + signed_list_str = message.getArg(OPENID_NS, 'signed', no_default) + signed_list = signed_list_str.split(',') + + for field in require_sigs[message.getOpenIDNamespace()]: + # Field is present and not in signed list + if message.hasKey(OPENID_NS, field) and field not in signed_list: + raise ProtocolError('"%s" not signed' % (field, )) + + def _verifyReturnToArgs(query): + """Verify that the arguments in the return_to URL are present in this + response. + """ + # NOTE -- query came from Message.toPostArgs, which returns a dict of + # {str: str} + message = Message.fromPostArgs(query) + return_to = message.getArg(OPENID_NS, 'return_to') + + if return_to is None: + raise ProtocolError('Response has no return_to') + + parsed_url = urlparse(return_to) + rt_query = parsed_url[4] + parsed_args = parse_qsl(rt_query) + + # NOTE -- parsed_args will be a dict of {bytes: bytes}, however it + # will be checked against return values from Message methods which are + # {str: str}. We need to compare apples to apples. + for rt_key, rt_value in parsed_args: + try: + value = query[rt_key] + if rt_value != value: + format = ("parameter %s value %r does not match " + "return_to's value %r") + raise ProtocolError(format % (rt_key, value, rt_value)) + except KeyError: + format = "return_to parameter %s absent from query %r" + raise ProtocolError(format % (rt_key, query)) + + # Make sure all non-OpenID arguments in the response are also + # in the signed return_to. + bare_args = message.getArgs(BARE_NS) + for pair in bare_args.items(): + if pair not in parsed_args: + raise ProtocolError("Parameter %s not in return_to URL" % + (pair[0], )) + + _verifyReturnToArgs = staticmethod(_verifyReturnToArgs) + + def _verifyDiscoveryResults(self, resp_msg, endpoint=None): + """ + Extract the information from an OpenID assertion message and + verify it against the original + + @param endpoint: The endpoint that resulted from doing discovery + @param resp_msg: The id_res message object + + @returns: the verified endpoint + """ + if resp_msg.getOpenIDNamespace() == OPENID2_NS: + return self._verifyDiscoveryResultsOpenID2(resp_msg, endpoint) + else: + return self._verifyDiscoveryResultsOpenID1(resp_msg, endpoint) + + def _verifyDiscoveryResultsOpenID2(self, resp_msg, endpoint): + to_match = OpenIDServiceEndpoint() + to_match.type_uris = [OPENID_2_0_TYPE] + to_match.claimed_id = resp_msg.getArg(OPENID2_NS, 'claimed_id') + to_match.local_id = resp_msg.getArg(OPENID2_NS, 'identity') + + # Raises a KeyError when the op_endpoint is not present + to_match.server_url = resp_msg.getArg(OPENID2_NS, 'op_endpoint', + no_default) + + # claimed_id and identifier must both be present or both + # be absent + if (to_match.claimed_id is None and to_match.local_id is not None): + raise ProtocolError( + 'openid.identity is present without openid.claimed_id') + + elif (to_match.claimed_id is not None and to_match.local_id is None): + raise ProtocolError( + 'openid.claimed_id is present without openid.identity') + + # This is a response without identifiers, so there's really no + # checking that we can do, so return an endpoint that's for + # the specified `openid.op_endpoint' + elif to_match.claimed_id is None: + return OpenIDServiceEndpoint.fromOPEndpointURL(to_match.server_url) + + # The claimed ID doesn't match, so we have to do discovery + # again. This covers not using sessions, OP identifier + # endpoints and responses that didn't match the original + # request. + if not endpoint: + logger.info('No pre-discovered information supplied.') + endpoint = self._discoverAndVerify(to_match.claimed_id, [to_match]) + elif endpoint.isOPIdentifier(): + logger.info( + 'Pre-discovered information based on OP-ID; need to rediscover.' + ) + endpoint = self._discoverAndVerify(to_match.claimed_id, [to_match]) + else: + # The claimed ID matches, so we use the endpoint that we + # discovered in initiation. This should be the most common + # case. + try: + self._verifyDiscoverySingle(endpoint, to_match) + except ProtocolError as e: + logger.exception( + "Error attempting to use stored discovery information: " + + str(e)) + logger.info("Attempting discovery to verify endpoint") + endpoint = self._discoverAndVerify(to_match.claimed_id, + [to_match]) + + # The endpoint we return should have the claimed ID from the + # message we just verified, fragment and all. + if endpoint.claimed_id != to_match.claimed_id: + endpoint = copy.copy(endpoint) + endpoint.claimed_id = to_match.claimed_id + return endpoint + + def _verifyDiscoveryResultsOpenID1(self, resp_msg, endpoint): + claimed_id = resp_msg.getArg(BARE_NS, + self.openid1_return_to_identifier_name) + + if endpoint is None and claimed_id is None: + raise RuntimeError( + 'When using OpenID 1, the claimed ID must be supplied, ' + 'either by passing it through as a return_to parameter ' + 'or by using a session, and supplied to the GenericConsumer ' + 'as the argument to complete()') + elif endpoint is not None and claimed_id is None: + claimed_id = endpoint.claimed_id + + to_match = OpenIDServiceEndpoint() + to_match.type_uris = [OPENID_1_1_TYPE] + to_match.local_id = resp_msg.getArg(OPENID1_NS, 'identity') + # Restore delegate information from the initiation phase + to_match.claimed_id = claimed_id + + if to_match.local_id is None: + raise ProtocolError('Missing required field openid.identity') + + to_match_1_0 = copy.copy(to_match) + to_match_1_0.type_uris = [OPENID_1_0_TYPE] + + if endpoint is not None: + try: + try: + self._verifyDiscoverySingle(endpoint, to_match) + except TypeURIMismatch: + self._verifyDiscoverySingle(endpoint, to_match_1_0) + except ProtocolError as e: + logger.exception( + "Error attempting to use stored discovery information: " + + str(e)) + logger.info("Attempting discovery to verify endpoint") + else: + return endpoint + + # Endpoint is either bad (failed verification) or None + return self._discoverAndVerify(claimed_id, [to_match, to_match_1_0]) + + def _verifyDiscoverySingle(self, endpoint, to_match): + """Verify that the given endpoint matches the information + extracted from the OpenID assertion, and raise an exception if + there is a mismatch. + + @type endpoint: openid.consumer.discover.OpenIDServiceEndpoint + @type to_match: openid.consumer.discover.OpenIDServiceEndpoint + + @rtype: NoneType + + @raises ProtocolError: when the endpoint does not match the + discovered information. + """ + # Every type URI that's in the to_match endpoint has to be + # present in the discovered endpoint. + for type_uri in to_match.type_uris: + if not endpoint.usesExtension(type_uri): + raise TypeURIMismatch(type_uri, endpoint) + + # Fragments do not influence discovery, so we can't compare a + # claimed identifier with a fragment to discovered information. + defragged_claimed_id, _ = urldefrag(to_match.claimed_id) + if defragged_claimed_id != endpoint.claimed_id: + raise ProtocolError( + 'Claimed ID does not match (different subjects!), ' + 'Expected %s, got %s' % + (defragged_claimed_id, endpoint.claimed_id)) + + if to_match.getLocalID() != endpoint.getLocalID(): + raise ProtocolError('local_id mismatch. Expected %s, got %s' % + (to_match.getLocalID(), endpoint.getLocalID())) + + # If the server URL is None, this must be an OpenID 1 + # response, because op_endpoint is a required parameter in + # OpenID 2. In that case, we don't actually care what the + # discovered server_url is, because signature checking or + # check_auth should take care of that check for us. + if to_match.server_url is None: + assert to_match.preferredNamespace() == OPENID1_NS, ( + """The code calling this must ensure that OpenID 2 + responses have a non-none `openid.op_endpoint' and + that it is set as the `server_url' attribute of the + `to_match' endpoint.""") + + elif to_match.server_url != endpoint.server_url: + raise ProtocolError('OP Endpoint mismatch. Expected %s, got %s' % + (to_match.server_url, endpoint.server_url)) + + def _discoverAndVerify(self, claimed_id, to_match_endpoints): + """Given an endpoint object created from the information in an + OpenID response, perform discovery and verify the discovery + results, returning the matching endpoint that is the result of + doing that discovery. + + @type to_match: openid.consumer.discover.OpenIDServiceEndpoint + @param to_match: The endpoint whose information we're confirming + + @rtype: openid.consumer.discover.OpenIDServiceEndpoint + @returns: The result of performing discovery on the claimed + identifier in `to_match' + + @raises DiscoveryFailure: when discovery fails. + """ + logger.info('Performing discovery on %s' % (claimed_id, )) + _, services = self._discover(claimed_id) + if not services: + raise DiscoveryFailure('No OpenID information found at %s' % + (claimed_id, ), None) + return self._verifyDiscoveredServices(claimed_id, services, + to_match_endpoints) + + def _verifyDiscoveredServices(self, claimed_id, services, + to_match_endpoints): + """See @L{_discoverAndVerify}""" + + # Search the services resulting from discovery to find one + # that matches the information from the assertion + failure_messages = [] + for endpoint in services: + for to_match_endpoint in to_match_endpoints: + try: + self._verifyDiscoverySingle(endpoint, to_match_endpoint) + except ProtocolError as why: + failure_messages.append(str(why)) + else: + # It matches, so discover verification has + # succeeded. Return this endpoint. + return endpoint + else: + logger.error('Discovery verification failure for %s' % + (claimed_id, )) + for failure_message in failure_messages: + logger.error(' * Endpoint mismatch: ' + failure_message) + + raise DiscoveryFailure( + 'No matching endpoint found after discovering %s' % + (claimed_id, ), None) + + def _checkAuth(self, message, server_url): + """Make a check_authentication request to verify this message. + + @returns: True if the request is valid. + @rtype: bool + """ + logger.info('Using OpenID check_authentication') + request = self._createCheckAuthRequest(message) + if request is None: + return False + try: + response = self._makeKVPost(request, server_url) + except (fetchers.HTTPFetchingError, ServerError) as e: + e0 = e.args[0] + logger.exception('check_authentication failed: %s' % e0) + return False + else: + return self._processCheckAuthResponse(response, server_url) + + def _createCheckAuthRequest(self, message): + """Generate a check_authentication request message given an + id_res message. + """ + signed = message.getArg(OPENID_NS, 'signed') + if signed: + if isinstance(signed, bytes): + signed = str(signed, encoding="utf-8") + for k in signed.split(','): + logger.info(k) + val = message.getAliasedArg(k) + + # Signed value is missing + if val is None: + logger.info('Missing signed field %r' % (k, )) + return None + + check_auth_message = message.copy() + check_auth_message.setArg(OPENID_NS, 'mode', 'check_authentication') + return check_auth_message + + def _processCheckAuthResponse(self, response, server_url): + """Process the response message from a check_authentication + request, invalidating associations if requested. + """ + is_valid = response.getArg(OPENID_NS, 'is_valid', 'false') + + invalidate_handle = response.getArg(OPENID_NS, 'invalidate_handle') + if invalidate_handle is not None: + logger.info('Received "invalidate_handle" from server %s' % + (server_url, )) + if self.store is None: + logger.error('Unexpectedly got invalidate_handle without ' + 'a store!') + else: + self.store.removeAssociation(server_url, invalidate_handle) + + if is_valid == 'true': + return True + else: + logger.error('Server responds that checkAuth call is not valid') + return False + + def _getAssociation(self, endpoint): + """Get an association for the endpoint's server_url. + + First try seeing if we have a good association in the + store. If we do not, then attempt to negotiate an association + with the server. + + If we negotiate a good association, it will get stored. + + @returns: A valid association for the endpoint's server_url or None + @rtype: openid.association.Association or NoneType + """ + assoc = self.store.getAssociation(endpoint.server_url) + + if assoc is None or assoc.expiresIn <= 0: + assoc = self._negotiateAssociation(endpoint) + if assoc is not None: + self.store.storeAssociation(endpoint.server_url, assoc) + + return assoc + + def _negotiateAssociation(self, endpoint): + """Make association requests to the server, attempting to + create a new association. + + @returns: a new association object + + @rtype: L{openid.association.Association} + """ + # Get our preferred session/association type from the negotiatior. + assoc_type, session_type = self.negotiator.getAllowedType() + + try: + assoc = self._requestAssociation(endpoint, assoc_type, + session_type) + except ServerError as why: + supportedTypes = self._extractSupportedAssociationType( + why, endpoint, assoc_type) + if supportedTypes is not None: + assoc_type, session_type = supportedTypes + # Attempt to create an association from the assoc_type + # and session_type that the server told us it + # supported. + try: + assoc = self._requestAssociation(endpoint, assoc_type, + session_type) + except ServerError as why: + # Do not keep trying, since it rejected the + # association type that it told us to use. + logger.error( + 'Server %s refused its suggested association ' + 'type: session_type=%s, assoc_type=%s' % ( + endpoint.server_url, session_type, assoc_type)) + return None + else: + return assoc + else: + return assoc + + def _extractSupportedAssociationType(self, server_error, endpoint, + assoc_type): + """Handle ServerErrors resulting from association requests. + + @returns: If server replied with an C{unsupported-type} error, + return a tuple of supported C{association_type}, C{session_type}. + Otherwise logs the error and returns None. + @rtype: tuple or None + """ + # Any error message whose code is not 'unsupported-type' + # should be considered a total failure. + if server_error.error_code != 'unsupported-type' or \ + server_error.message.isOpenID1(): + logger.error( + 'Server error when requesting an association from %r: %s' % + (endpoint.server_url, server_error.error_text)) + return None + + # The server didn't like the association/session type + # that we sent, and it sent us back a message that + # might tell us how to handle it. + logger.error('Unsupported association type %s: %s' % + (assoc_type, server_error.error_text, )) + + # Extract the session_type and assoc_type from the + # error message + assoc_type = server_error.message.getArg(OPENID_NS, 'assoc_type') + session_type = server_error.message.getArg(OPENID_NS, 'session_type') + + if assoc_type is None or session_type is None: + logger.error('Server responded with unsupported association ' + 'session but did not supply a fallback.') + return None + elif not self.negotiator.isAllowed(assoc_type, session_type): + fmt = ('Server sent unsupported session/association type: ' + 'session_type=%s, assoc_type=%s') + logger.error(fmt % (session_type, assoc_type)) + return None + else: + return assoc_type, session_type + + def _requestAssociation(self, endpoint, assoc_type, session_type): + """Make and process one association request to this endpoint's + OP endpoint URL. + + @returns: An association object or None if the association + processing failed. + + @raises ServerError: when the remote OpenID server returns an error. + """ + assoc_session, args = self._createAssociateRequest( + endpoint, assoc_type, session_type) + + try: + response = self._makeKVPost(args, endpoint.server_url) + except fetchers.HTTPFetchingError as why: + logger.exception('openid.associate request failed: %s' % (why, )) + return None + + try: + assoc = self._extractAssociation(response, assoc_session) + except KeyError as why: + logger.exception( + 'Missing required parameter in response from %s: %s' % + (endpoint.server_url, why)) + return None + except ProtocolError as why: + logger.exception('Protocol error parsing response from %s: %s' % + (endpoint.server_url, why)) + return None + else: + return assoc + + def _createAssociateRequest(self, endpoint, assoc_type, session_type): + """Create an association request for the given assoc_type and + session_type. + + @param endpoint: The endpoint whose server_url will be + queried. The important bit about the endpoint is whether + it's in compatiblity mode (OpenID 1.1) + + @param assoc_type: The association type that the request + should ask for. + @type assoc_type: str + + @param session_type: The session type that should be used in + the association request. The session_type is used to + create an association session object, and that session + object is asked for any additional fields that it needs to + add to the request. + @type session_type: str + + @returns: a pair of the association session object and the + request message that will be sent to the server. + @rtype: (association session type (depends on session_type), + openid.message.Message) + """ + session_type_class = self.session_types[session_type] + assoc_session = session_type_class() + + args = { + 'mode': 'associate', + 'assoc_type': assoc_type, + } + + if not endpoint.compatibilityMode(): + args['ns'] = OPENID2_NS + + # Leave out the session type if we're in compatibility mode + # *and* it's no-encryption. + if (not endpoint.compatibilityMode() or + assoc_session.session_type != 'no-encryption'): + args['session_type'] = assoc_session.session_type + + args.update(assoc_session.getRequest()) + message = Message.fromOpenIDArgs(args) + return assoc_session, message + + def _getOpenID1SessionType(self, assoc_response): + """Given an association response message, extract the OpenID + 1.X session type. + + This function mostly takes care of the 'no-encryption' default + behavior in OpenID 1. + + If the association type is plain-text, this function will + return 'no-encryption' + + @returns: The association type for this message + @rtype: str + + @raises KeyError: when the session_type field is absent. + """ + # If it's an OpenID 1 message, allow session_type to default + # to None (which signifies "no-encryption") + session_type = assoc_response.getArg(OPENID1_NS, 'session_type') + + # Handle the differences between no-encryption association + # respones in OpenID 1 and 2: + + # no-encryption is not really a valid session type for + # OpenID 1, but we'll accept it anyway, while issuing a + # warning. + if session_type == 'no-encryption': + logger.warning('OpenID server sent "no-encryption"' + 'for OpenID 1.X') + + # Missing or empty session type is the way to flag a + # 'no-encryption' response. Change the session type to + # 'no-encryption' so that it can be handled in the same + # way as OpenID 2 'no-encryption' respones. + elif session_type == '' or session_type is None: + session_type = 'no-encryption' + + return session_type + + def _extractAssociation(self, assoc_response, assoc_session): + """Attempt to extract an association from the response, given + the association response message and the established + association session. + + @param assoc_response: The association response message from + the server + @type assoc_response: openid.message.Message + + @param assoc_session: The association session object that was + used when making the request + @type assoc_session: depends on the session type of the request + + @raises ProtocolError: when data is malformed + @raises KeyError: when a field is missing + + @rtype: openid.association.Association + """ + # Extract the common fields from the response, raising an + # exception if they are not found + assoc_type = assoc_response.getArg(OPENID_NS, 'assoc_type', no_default) + assoc_handle = assoc_response.getArg(OPENID_NS, 'assoc_handle', + no_default) + + # expires_in is a base-10 string. The Python parsing will + # accept literals that have whitespace around them and will + # accept negative values. Neither of these are really in-spec, + # but we think it's OK to accept them. + expires_in_str = assoc_response.getArg(OPENID_NS, 'expires_in', + no_default) + try: + expires_in = int(expires_in_str) + except ValueError as why: + raise ProtocolError('Invalid expires_in field: %s' % (why, )) + + # OpenID 1 has funny association session behaviour. + if assoc_response.isOpenID1(): + session_type = self._getOpenID1SessionType(assoc_response) + else: + session_type = assoc_response.getArg(OPENID2_NS, 'session_type', + no_default) + + # Session type mismatch + if assoc_session.session_type != session_type: + if (assoc_response.isOpenID1() and + session_type == 'no-encryption'): + # In OpenID 1, any association request can result in a + # 'no-encryption' association response. Setting + # assoc_session to a new no-encryption session should + # make the rest of this function work properly for + # that case. + assoc_session = PlainTextConsumerSession() + else: + # Any other mismatch, regardless of protocol version + # results in the failure of the association session + # altogether. + fmt = 'Session type mismatch. Expected %r, got %r' + message = fmt % (assoc_session.session_type, session_type) + raise ProtocolError(message) + + # Make sure assoc_type is valid for session_type + if assoc_type not in assoc_session.allowed_assoc_types: + fmt = 'Unsupported assoc_type for session %s returned: %s' + raise ProtocolError(fmt % (assoc_session.session_type, assoc_type)) + + # Delegate to the association session to extract the secret + # from the response, however is appropriate for that session + # type. + try: + secret = assoc_session.extractSecret(assoc_response) + except ValueError as why: + fmt = 'Malformed response for %s session: %s' + raise ProtocolError(fmt % (assoc_session.session_type, why)) + + return Association.fromExpiresIn(expires_in, assoc_handle, secret, + assoc_type) + + +class AuthRequest(object): + """An object that holds the state necessary for generating an + OpenID authentication request. This object holds the association + with the server and the discovered information with which the + request will be made. + + It is separate from the consumer because you may wish to add + things to the request before sending it on its way to the + server. It also has serialization options that let you encode the + authentication request as a URL or as a form POST. + """ + + def __init__(self, endpoint, assoc): + """ + Creates a new AuthRequest object. This just stores each + argument in an appropriately named field. + + Users of this library should not create instances of this + class. Instances of this class are created by the library + when needed. + """ + self.assoc = assoc + self.endpoint = endpoint + self.return_to_args = {} + self.message = Message(endpoint.preferredNamespace()) + self._anonymous = False + + def setAnonymous(self, is_anonymous): + """Set whether this request should be made anonymously. If a + request is anonymous, the identifier will not be sent in the + request. This is only useful if you are making another kind of + request with an extension in this request. + + Anonymous requests are not allowed when the request is made + with OpenID 1. + + @raises ValueError: when attempting to set an OpenID1 request + as anonymous + """ + if is_anonymous and self.message.isOpenID1(): + raise ValueError('OpenID 1 requests MUST include the ' + 'identifier in the request') + else: + self._anonymous = is_anonymous + + def addExtension(self, extension_request): + """Add an extension to this checkid request. + + @param extension_request: An object that implements the + extension interface for adding arguments to an OpenID + message. + """ + extension_request.toMessage(self.message) + + def addExtensionArg(self, namespace, key, value): + """Add an extension argument to this OpenID authentication + request. + + Use caution when adding arguments, because they will be + URL-escaped and appended to the redirect URL, which can easily + get quite long. + + @param namespace: The namespace for the extension. For + example, the simple registration extension uses the + namespace C{sreg}. + + @type namespace: str + + @param key: The key within the extension namespace. For + example, the nickname field in the simple registration + extension's key is C{nickname}. + + @type key: str + + @param value: The value to provide to the server for this + argument. + + @type value: str + """ + self.message.setArg(namespace, key, value) + + def getMessage(self, realm, return_to=None, immediate=False): + """Produce a L{openid.message.Message} representing this request. + + @param realm: The URL (or URL pattern) that identifies your + web site to the user when she is authorizing it. + + @type realm: str + + @param return_to: The URL that the OpenID provider will send the + user back to after attempting to verify her identity. + + Not specifying a return_to URL means that the user will not + be returned to the site issuing the request upon its + completion. + + @type return_to: str + + @param immediate: If True, the OpenID provider is to send back + a response immediately, useful for behind-the-scenes + authentication attempts. Otherwise the OpenID provider + may engage the user before providing a response. This is + the default case, as the user may need to provide + credentials or approve the request before a positive + response can be sent. + + @type immediate: bool + + @returntype: L{openid.message.Message} + """ + if return_to: + return_to = oidutil.appendArgs(return_to, self.return_to_args) + elif immediate: + raise ValueError( + '"return_to" is mandatory when using "checkid_immediate"') + elif self.message.isOpenID1(): + raise ValueError('"return_to" is mandatory for OpenID 1 requests') + elif self.return_to_args: + raise ValueError('extra "return_to" arguments were specified, ' + 'but no return_to was specified') + + if immediate: + mode = 'checkid_immediate' + else: + mode = 'checkid_setup' + + message = self.message.copy() + if message.isOpenID1(): + realm_key = 'trust_root' + else: + realm_key = 'realm' + + message.updateArgs(OPENID_NS, { + realm_key: realm, + 'mode': mode, + 'return_to': return_to, + }) + + if not self._anonymous: + if self.endpoint.isOPIdentifier(): + # This will never happen when we're in compatibility + # mode, as long as isOPIdentifier() returns False + # whenever preferredNamespace() returns OPENID1_NS. + claimed_id = request_identity = IDENTIFIER_SELECT + else: + request_identity = self.endpoint.getLocalID() + claimed_id = self.endpoint.claimed_id + + # This is true for both OpenID 1 and 2 + message.setArg(OPENID_NS, 'identity', request_identity) + + if message.isOpenID2(): + message.setArg(OPENID2_NS, 'claimed_id', claimed_id) + + if self.assoc: + message.setArg(OPENID_NS, 'assoc_handle', self.assoc.handle) + assoc_log_msg = 'with association %s' % (self.assoc.handle, ) + else: + assoc_log_msg = 'using stateless mode.' + + logger.info("Generated %s request to %s %s" % + (mode, self.endpoint.server_url, assoc_log_msg)) + + return message + + def redirectURL(self, realm, return_to=None, immediate=False): + """Returns a URL with an encoded OpenID request. + + The resulting URL is the OpenID provider's endpoint URL with + parameters appended as query arguments. You should redirect + the user agent to this URL. + + OpenID 2.0 endpoints also accept POST requests, see + C{L{shouldSendRedirect}} and C{L{formMarkup}}. + + @param realm: The URL (or URL pattern) that identifies your + web site to the user when she is authorizing it. + + @type realm: str + + @param return_to: The URL that the OpenID provider will send the + user back to after attempting to verify her identity. + + Not specifying a return_to URL means that the user will not + be returned to the site issuing the request upon its + completion. + + @type return_to: str + + @param immediate: If True, the OpenID provider is to send back + a response immediately, useful for behind-the-scenes + authentication attempts. Otherwise the OpenID provider + may engage the user before providing a response. This is + the default case, as the user may need to provide + credentials or approve the request before a positive + response can be sent. + + @type immediate: bool + + @returns: The URL to redirect the user agent to. + + @returntype: str + """ + message = self.getMessage(realm, return_to, immediate) + return message.toURL(self.endpoint.server_url) + + def formMarkup(self, + realm, + return_to=None, + immediate=False, + form_tag_attrs=None): + """Get html for a form to submit this request to the IDP. + + @param form_tag_attrs: Dictionary of attributes to be added to + the form tag. 'accept-charset' and 'enctype' have defaults + that can be overridden. If a value is supplied for + 'action' or 'method', it will be replaced. + @type form_tag_attrs: {unicode: unicode} + """ + message = self.getMessage(realm, return_to, immediate) + return message.toFormMarkup(self.endpoint.server_url, form_tag_attrs) + + def htmlMarkup(self, + realm, + return_to=None, + immediate=False, + form_tag_attrs=None): + """Get an autosubmitting HTML page that submits this request to the + IDP. This is just a wrapper for formMarkup. + + @see: formMarkup + + @returns: str + """ + return oidutil.autoSubmitHTML( + self.formMarkup(realm, return_to, immediate, form_tag_attrs)) + + def shouldSendRedirect(self): + """Should this OpenID authentication request be sent as a HTTP + redirect or as a POST (form submission)? + + @rtype: bool + """ + return self.endpoint.compatibilityMode() + + +FAILURE = 'failure' +SUCCESS = 'success' +CANCEL = 'cancel' +SETUP_NEEDED = 'setup_needed' + + +class Response(object): + status = None + + def setEndpoint(self, endpoint): + self.endpoint = endpoint + if endpoint is None: + self.identity_url = None + else: + self.identity_url = endpoint.claimed_id + + def getDisplayIdentifier(self): + """Return the display identifier for this response. + + The display identifier is related to the Claimed Identifier, but the + two are not always identical. The display identifier is something the + user should recognize as what they entered, whereas the response's + claimed identifier (in the L{identity_url} attribute) may have extra + information for better persistence. + + URLs will be stripped of their fragments for display. XRIs will + display the human-readable identifier (i-name) instead of the + persistent identifier (i-number). + + Use the display identifier in your user interface. Use + L{identity_url} for querying your database or authorization server. + """ + if self.endpoint is not None: + return self.endpoint.getDisplayIdentifier() + return None + + +class SuccessResponse(Response): + """A response with a status of SUCCESS. Indicates that this request is a + successful acknowledgement from the OpenID server that the + supplied URL is, indeed controlled by the requesting agent. + + @ivar identity_url: The identity URL that has been authenticated; + the Claimed Identifier. + See also L{getDisplayIdentifier}. + + @ivar endpoint: The endpoint that authenticated the identifier. You + may access other discovered information related to this endpoint, + such as the CanonicalID of an XRI, through this object. + @type endpoint: + L{OpenIDServiceEndpoint<openid.consumer.discover.OpenIDServiceEndpoint>} + + @ivar signed_fields: The arguments in the server's response that + were signed and verified. + + @cvar status: SUCCESS + """ + + status = SUCCESS + + def __init__(self, endpoint, message, signed_fields=None): + # Don't use setEndpoint, because endpoint should never be None + # for a successfull transaction. + self.endpoint = endpoint + self.identity_url = endpoint.claimed_id + + self.message = message + + if signed_fields is None: + signed_fields = [] + self.signed_fields = signed_fields + + def isOpenID1(self): + """Was this authentication response an OpenID 1 authentication + response? + """ + return self.message.isOpenID1() + + def isSigned(self, ns_uri, ns_key): + """Return whether a particular key is signed, regardless of + its namespace alias + """ + return self.message.getKey(ns_uri, ns_key) in self.signed_fields + + def getSigned(self, ns_uri, ns_key, default=None): + """Return the specified signed field if available, + otherwise return default + """ + if self.isSigned(ns_uri, ns_key): + return self.message.getArg(ns_uri, ns_key, default) + else: + return default + + def getSignedNS(self, ns_uri): + """Get signed arguments from the response message. Return a + dict of all arguments in the specified namespace. If any of + the arguments are not signed, return None. + """ + msg_args = self.message.getArgs(ns_uri) + + for key in msg_args.keys(): + if not self.isSigned(ns_uri, key): + logger.info( + "SuccessResponse.getSignedNS: (%s, %s) not signed." % + (ns_uri, key)) + return None + + return msg_args + + def extensionResponse(self, namespace_uri, require_signed): + """Return response arguments in the specified namespace. + + @param namespace_uri: The namespace URI of the arguments to be + returned. + + @param require_signed: True if the arguments should be among + those signed in the response, False if you don't care. + + If require_signed is True and the arguments are not signed, + return None. + """ + if require_signed: + return self.getSignedNS(namespace_uri) + else: + return self.message.getArgs(namespace_uri) + + def getReturnTo(self): + """Get the openid.return_to argument from this response. + + This is useful for verifying that this request was initiated + by this consumer. + + @returns: The return_to URL supplied to the server on the + initial request, or C{None} if the response did not contain + an C{openid.return_to} argument. + + @returntype: str + """ + return self.getSigned(OPENID_NS, 'return_to') + + def __eq__(self, other): + return ((self.endpoint == other.endpoint) and + (self.identity_url == other.identity_url) and + (self.message == other.message) and + (self.signed_fields == other.signed_fields) and + (self.status == other.status)) + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return '<%s.%s id=%r signed=%r>' % ( + self.__class__.__module__, self.__class__.__name__, + self.identity_url, self.signed_fields) + + +class FailureResponse(Response): + """A response with a status of FAILURE. Indicates that the OpenID + protocol has failed. This could be locally or remotely triggered. + + @ivar identity_url: The identity URL for which authenitcation was + attempted, if it can be determined. Otherwise, None. + + @ivar message: A message indicating why the request failed, if one + is supplied. otherwise, None. + + @cvar status: FAILURE + """ + + status = FAILURE + + def __init__(self, endpoint, message=None, contact=None, reference=None): + self.setEndpoint(endpoint) + self.message = message + self.contact = contact + self.reference = reference + + def __repr__(self): + return "<%s.%s id=%r message=%r>" % (self.__class__.__module__, + self.__class__.__name__, + self.identity_url, self.message) + + +class CancelResponse(Response): + """A response with a status of CANCEL. Indicates that the user + cancelled the OpenID authentication request. + + @ivar identity_url: The identity URL for which authenitcation was + attempted, if it can be determined. Otherwise, None. + + @cvar status: CANCEL + """ + + status = CANCEL + + def __init__(self, endpoint): + self.setEndpoint(endpoint) + + +class SetupNeededResponse(Response): + """A response with a status of SETUP_NEEDED. Indicates that the + request was in immediate mode, and the server is unable to + authenticate the user without further interaction. + + @ivar identity_url: The identity URL for which authenitcation was + attempted. + + @ivar setup_url: A URL that can be used to send the user to the + server to set up for authentication. The user should be + redirected in to the setup_url, either in the current window + or in a new browser window. C{None} in OpenID 2.0. + + @cvar status: SETUP_NEEDED + """ + + status = SETUP_NEEDED + + def __init__(self, endpoint, setup_url=None): + self.setEndpoint(endpoint) + self.setup_url = setup_url diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/discover.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/discover.py new file mode 100644 index 0000000000000000000000000000000000000000..bfe987dd7f4ade478b8a7b44bb3767b9e74e102c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/discover.py @@ -0,0 +1,467 @@ +# -*- test-case-name: openid.test.test_discover -*- +"""Functions to discover OpenID endpoints from identifiers. +""" + +__all__ = [ + 'DiscoveryFailure', + 'OPENID_1_0_NS', + 'OPENID_1_0_TYPE', + 'OPENID_1_1_TYPE', + 'OPENID_2_0_TYPE', + 'OPENID_IDP_2_0_TYPE', + 'OpenIDServiceEndpoint', + 'discover', +] + +import urllib.parse +import logging + +from openid import fetchers, urinorm + +from openid import yadis +from openid.yadis.etxrd import nsTag, XRDSError, XRD_NS_2_0 +from openid.yadis.services import applyFilter as extractServices +from openid.yadis.discover import discover as yadisDiscover +from openid.yadis.discover import DiscoveryFailure +from openid.yadis import xrires, filters +from openid.yadis import xri + +from openid.consumer import html_parse + +OPENID_1_0_NS = 'http://openid.net/xmlns/1.0' +OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server' +OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon' +OPENID_1_1_TYPE = 'http://openid.net/signon/1.1' +OPENID_1_0_TYPE = 'http://openid.net/signon/1.0' + +from openid.message import OPENID1_NS as OPENID_1_0_MESSAGE_NS +from openid.message import OPENID2_NS as OPENID_2_0_MESSAGE_NS + +logger = logging.getLogger(__name__) + + +class OpenIDServiceEndpoint(object): + """Object representing an OpenID service endpoint. + + @ivar identity_url: the verified identifier. + @ivar canonicalID: For XRI, the persistent identifier. + """ + + # OpenID service type URIs, listed in order of preference. The + # ordering of this list affects yadis and XRI service discovery. + openid_type_uris = [ + OPENID_IDP_2_0_TYPE, + OPENID_2_0_TYPE, + OPENID_1_1_TYPE, + OPENID_1_0_TYPE, + ] + + def __init__(self): + self.claimed_id = None + self.server_url = None + self.type_uris = [] + self.local_id = None + self.canonicalID = None + self.used_yadis = False # whether this came from an XRDS + self.display_identifier = None + + def usesExtension(self, extension_uri): + return extension_uri in self.type_uris + + def preferredNamespace(self): + if (OPENID_IDP_2_0_TYPE in self.type_uris or + OPENID_2_0_TYPE in self.type_uris): + return OPENID_2_0_MESSAGE_NS + else: + return OPENID_1_0_MESSAGE_NS + + def supportsType(self, type_uri): + """Does this endpoint support this type? + + I consider C{/server} endpoints to implicitly support C{/signon}. + """ + return ((type_uri in self.type_uris) or + (type_uri == OPENID_2_0_TYPE and self.isOPIdentifier())) + + def getDisplayIdentifier(self): + """Return the display_identifier if set, else return the claimed_id. + """ + if self.display_identifier is not None: + return self.display_identifier + if self.claimed_id is None: + return None + else: + return urllib.parse.urldefrag(self.claimed_id)[0] + + def compatibilityMode(self): + return self.preferredNamespace() != OPENID_2_0_MESSAGE_NS + + def isOPIdentifier(self): + return OPENID_IDP_2_0_TYPE in self.type_uris + + def parseService(self, yadis_url, uri, type_uris, service_element): + """Set the state of this object based on the contents of the + service element.""" + self.type_uris = type_uris + self.server_url = uri + self.used_yadis = True + + if not self.isOPIdentifier(): + # XXX: This has crappy implications for Service elements + # that contain both 'server' and 'signon' Types. But + # that's a pathological configuration anyway, so I don't + # think I care. + self.local_id = findOPLocalIdentifier(service_element, + self.type_uris) + self.claimed_id = yadis_url + + def getLocalID(self): + """Return the identifier that should be sent as the + openid.identity parameter to the server.""" + # I looked at this conditional and thought "ah-hah! there's the bug!" + # but Python actually makes that one big expression somehow, i.e. + # "x is x is x" is not the same thing as "(x is x) is x". + # That's pretty weird, dude. -- kmt, 1/07 + if (self.local_id is self.canonicalID is None): + return self.claimed_id + else: + return self.local_id or self.canonicalID + + def fromBasicServiceEndpoint(cls, endpoint): + """Create a new instance of this class from the endpoint + object passed in. + + @return: None or OpenIDServiceEndpoint for this endpoint object""" + type_uris = endpoint.matchTypes(cls.openid_type_uris) + + # If any Type URIs match and there is an endpoint URI + # specified, then this is an OpenID endpoint + if type_uris and endpoint.uri is not None: + openid_endpoint = cls() + openid_endpoint.parseService(endpoint.yadis_url, endpoint.uri, + endpoint.type_uris, + endpoint.service_element) + else: + openid_endpoint = None + + return openid_endpoint + + fromBasicServiceEndpoint = classmethod(fromBasicServiceEndpoint) + + def fromHTML(cls, uri, html): + """Parse the given document as HTML looking for an OpenID <link + rel=...> + + @rtype: [OpenIDServiceEndpoint] + """ + discovery_types = [ + (OPENID_2_0_TYPE, 'openid2.provider', 'openid2.local_id'), + (OPENID_1_1_TYPE, 'openid.server', 'openid.delegate'), + ] + + link_attrs = html_parse.parseLinkAttrs(html) + services = [] + for type_uri, op_endpoint_rel, local_id_rel in discovery_types: + op_endpoint_url = html_parse.findFirstHref(link_attrs, + op_endpoint_rel) + if op_endpoint_url is None: + continue + + service = cls() + service.claimed_id = uri + service.local_id = html_parse.findFirstHref(link_attrs, + local_id_rel) + service.server_url = op_endpoint_url + service.type_uris = [type_uri] + + services.append(service) + + return services + + fromHTML = classmethod(fromHTML) + + def fromXRDS(cls, uri, xrds): + """Parse the given document as XRDS looking for OpenID services. + + @rtype: [OpenIDServiceEndpoint] + + @raises XRDSError: When the XRDS does not parse. + + @since: 2.1.0 + """ + return extractServices(uri, xrds, cls) + + fromXRDS = classmethod(fromXRDS) + + def fromDiscoveryResult(cls, discoveryResult): + """Create endpoints from a DiscoveryResult. + + @type discoveryResult: L{DiscoveryResult} + + @rtype: list of L{OpenIDServiceEndpoint} + + @raises XRDSError: When the XRDS does not parse. + + @since: 2.1.0 + """ + if discoveryResult.isXRDS(): + method = cls.fromXRDS + else: + method = cls.fromHTML + return method(discoveryResult.normalized_uri, + discoveryResult.response_text) + + fromDiscoveryResult = classmethod(fromDiscoveryResult) + + def fromOPEndpointURL(cls, op_endpoint_url): + """Construct an OP-Identifier OpenIDServiceEndpoint object for + a given OP Endpoint URL + + @param op_endpoint_url: The URL of the endpoint + @rtype: OpenIDServiceEndpoint + """ + service = cls() + service.server_url = op_endpoint_url + service.type_uris = [OPENID_IDP_2_0_TYPE] + return service + + fromOPEndpointURL = classmethod(fromOPEndpointURL) + + def __str__(self): + return ("<%s.%s " + "server_url=%r " + "claimed_id=%r " + "local_id=%r " + "canonicalID=%r " + "used_yadis=%s " + ">" % (self.__class__.__module__, self.__class__.__name__, + self.server_url, self.claimed_id, self.local_id, + self.canonicalID, self.used_yadis)) + + +def findOPLocalIdentifier(service_element, type_uris): + """Find the OP-Local Identifier for this xrd:Service element. + + This considers openid:Delegate to be a synonym for xrd:LocalID if + both OpenID 1.X and OpenID 2.0 types are present. If only OpenID + 1.X is present, it returns the value of openid:Delegate. If only + OpenID 2.0 is present, it returns the value of xrd:LocalID. If + there is more than one LocalID tag and the values are different, + it raises a DiscoveryFailure. This is also triggered when the + xrd:LocalID and openid:Delegate tags are different. + + @param service_element: The xrd:Service element + @type service_element: ElementTree.Node + + @param type_uris: The xrd:Type values present in this service + element. This function could extract them, but higher level + code needs to do that anyway. + @type type_uris: [str] + + @raises DiscoveryFailure: when discovery fails. + + @returns: The OP-Local Identifier for this service element, if one + is present, or None otherwise. + @rtype: str or unicode or NoneType + """ + # XXX: Test this function on its own! + + # Build the list of tags that could contain the OP-Local Identifier + local_id_tags = [] + if (OPENID_1_1_TYPE in type_uris or OPENID_1_0_TYPE in type_uris): + local_id_tags.append(nsTag(OPENID_1_0_NS, 'Delegate')) + + if OPENID_2_0_TYPE in type_uris: + local_id_tags.append(nsTag(XRD_NS_2_0, 'LocalID')) + + # Walk through all the matching tags and make sure that they all + # have the same value + local_id = None + for local_id_tag in local_id_tags: + for local_id_element in service_element.findall(local_id_tag): + if local_id is None: + local_id = local_id_element.text + elif local_id != local_id_element.text: + format = 'More than one %r tag found in one service element' + message = format % (local_id_tag, ) + raise DiscoveryFailure(message, None) + + return local_id + + +def normalizeURL(url): + """Normalize a URL, converting normalization failures to + DiscoveryFailure""" + try: + normalized = urinorm.urinorm(url) + except ValueError as why: + raise DiscoveryFailure('Normalizing identifier: %s' % (why, ), None) + else: + return urllib.parse.urldefrag(normalized)[0] + + +def normalizeXRI(xri): + """Normalize an XRI, stripping its scheme if present""" + if xri.startswith("xri://"): + xri = xri[6:] + return xri + + +def arrangeByType(service_list, preferred_types): + """Rearrange service_list in a new list so services are ordered by + types listed in preferred_types. Return the new list.""" + + def enumerate(elts): + """Return an iterable that pairs the index of an element with + that element. + + For Python 2.2 compatibility""" + return list(zip(list(range(len(elts))), elts)) + + def bestMatchingService(service): + """Return the index of the first matching type, or something + higher if no type matches. + + This provides an ordering in which service elements that + contain a type that comes earlier in the preferred types list + come before service elements that come later. If a service + element has more than one type, the most preferred one wins. + """ + for i, t in enumerate(preferred_types): + if preferred_types[i] in service.type_uris: + return i + + return len(preferred_types) + + # Build a list with the service elements in tuples whose + # comparison will prefer the one with the best matching service + prio_services = [(bestMatchingService(s), orig_index, s) + for (orig_index, s) in enumerate(service_list)] + prio_services.sort() + + # Now that the services are sorted by priority, remove the sort + # keys from the list. + for i in range(len(prio_services)): + prio_services[i] = prio_services[i][2] + + return prio_services + + +def getOPOrUserServices(openid_services): + """Extract OP Identifier services. If none found, return the + rest, sorted with most preferred first according to + OpenIDServiceEndpoint.openid_type_uris. + + openid_services is a list of OpenIDServiceEndpoint objects. + + Returns a list of OpenIDServiceEndpoint objects.""" + + op_services = arrangeByType(openid_services, [OPENID_IDP_2_0_TYPE]) + + openid_services = arrangeByType(openid_services, + OpenIDServiceEndpoint.openid_type_uris) + + return op_services or openid_services + + +def discoverYadis(uri): + """Discover OpenID services for a URI. Tries Yadis and falls back + on old-style <link rel='...'> discovery if Yadis fails. + + @param uri: normalized identity URL + @type uri: str + + @return: (claimed_id, services) + @rtype: (str, list(OpenIDServiceEndpoint)) + + @raises DiscoveryFailure: when discovery fails. + """ + # Might raise a yadis.discover.DiscoveryFailure if no document + # came back for that URI at all. I don't think falling back + # to OpenID 1.0 discovery on the same URL will help, so don't + # bother to catch it. + response = yadisDiscover(uri) + + yadis_url = response.normalized_uri + body = response.response_text + try: + openid_services = OpenIDServiceEndpoint.fromXRDS(yadis_url, body) + except XRDSError: + # Does not parse as a Yadis XRDS file + openid_services = [] + + if not openid_services: + # Either not an XRDS or there are no OpenID services. + + if response.isXRDS(): + # if we got the Yadis content-type or followed the Yadis + # header, re-fetch the document without following the Yadis + # header, with no Accept header. + return discoverNoYadis(uri) + + # Try to parse the response as HTML. + # <link rel="..."> + openid_services = OpenIDServiceEndpoint.fromHTML(yadis_url, body) + + return (yadis_url, getOPOrUserServices(openid_services)) + + +def discoverXRI(iname): + endpoints = [] + iname = normalizeXRI(iname) + try: + canonicalID, services = xrires.ProxyResolver().query( + iname, OpenIDServiceEndpoint.openid_type_uris) + + if canonicalID is None: + raise XRDSError('No CanonicalID found for XRI %r' % (iname, )) + + flt = filters.mkFilter(OpenIDServiceEndpoint) + for service_element in services: + endpoints.extend(flt.getServiceEndpoints(iname, service_element)) + except XRDSError: + logger.exception('xrds error on ' + iname) + + for endpoint in endpoints: + # Is there a way to pass this through the filter to the endpoint + # constructor instead of tacking it on after? + endpoint.canonicalID = canonicalID + endpoint.claimed_id = canonicalID + endpoint.display_identifier = iname + + # FIXME: returned xri should probably be in some normal form + return iname, getOPOrUserServices(endpoints) + + +def discoverNoYadis(uri): + http_resp = fetchers.fetch(uri) + if http_resp.status not in (200, 206): + raise DiscoveryFailure( + 'HTTP Response status from identity URL host is not 200. ' + 'Got status %r' % (http_resp.status, ), http_resp) + + claimed_id = http_resp.final_url + openid_services = OpenIDServiceEndpoint.fromHTML(claimed_id, + http_resp.body) + return claimed_id, openid_services + + +def discoverURI(uri): + parsed = urllib.parse.urlparse(uri) + if parsed[0] and parsed[1]: + if parsed[0] not in ['http', 'https']: + raise DiscoveryFailure('URI scheme is not HTTP or HTTPS', None) + else: + uri = 'http://' + uri + + uri = normalizeURL(uri) + claimed_id, openid_services = discoverYadis(uri) + claimed_id = normalizeURL(claimed_id) + return claimed_id, openid_services + + +def discover(identifier): + if xri.identifierScheme(identifier) == "XRI": + return discoverXRI(identifier) + else: + return discoverURI(identifier) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/html_parse.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/html_parse.py new file mode 100644 index 0000000000000000000000000000000000000000..cc154eb5b682aa08fe76463d73db3bd490a25576 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/consumer/html_parse.py @@ -0,0 +1,278 @@ +""" +This module implements a VERY limited parser that finds <link> tags in +the head of HTML or XHTML documents and parses out their attributes +according to the OpenID spec. It is a liberal parser, but it requires +these things from the data in order to work: + + - There must be an open <html> tag + + - There must be an open <head> tag inside of the <html> tag + + - Only <link>s that are found inside of the <head> tag are parsed + (this is by design) + + - The parser follows the OpenID specification in resolving the + attributes of the link tags. This means that the attributes DO NOT + get resolved as they would by an XML or HTML parser. In particular, + only certain entities get replaced, and href attributes do not get + resolved relative to a base URL. + +From http://openid.net/specs.bml#linkrel: + + - The openid.server URL MUST be an absolute URL. OpenID consumers + MUST NOT attempt to resolve relative URLs. + + - The openid.server URL MUST NOT include entities other than &, + <, >, and ". + +The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds of +quoting are allowed for attributes. + +The parser deals with invalid markup in these ways: + + - Tag names are not case-sensitive + + - The <html> tag is accepted even when it is not at the top level + + - The <head> tag is accepted even when it is not a direct child of + the <html> tag, but a <html> tag must be an ancestor of the <head> + tag + + - <link> tags are accepted even when they are not direct children of + the <head> tag, but a <head> tag must be an ancestor of the <link> + tag + + - If there is no closing tag for an open <html> or <head> tag, the + remainder of the document is viewed as being inside of the tag. If + there is no closing tag for a <link> tag, the link tag is treated + as a short tag. Exceptions to this rule are that <html> closes + <html> and <body> or <head> closes <head> + + - Attributes of the <link> tag are not required to be quoted. + + - In the case of duplicated attribute names, the attribute coming + last in the tag will be the value returned. + + - Any text that does not parse as an attribute within a link tag will + be ignored. (e.g. <link pumpkin rel='openid.server' /> will ignore + pumpkin) + + - If there are more than one <html> or <head> tag, the parser only + looks inside of the first one. + + - The contents of <script> tags are ignored entirely, except unclosed + <script> tags. Unclosed <script> tags are ignored. + + - Any other invalid markup is ignored, including unclosed SGML + comments and unclosed <![CDATA[blocks. +""" + +__all__ = ['parseLinkAttrs'] + +import re + +flags = ( + re.DOTALL # Match newlines with '.' + | re.IGNORECASE | re.VERBOSE # Allow comments and whitespace in patterns + | re.UNICODE # Make \b respect Unicode word boundaries +) + +# Stuff to remove before we start looking for tags +removed_re = re.compile(r''' + # Comments + <!--.*?--> + + # CDATA blocks +| <!\[CDATA\[.*?\]\]> + + # script blocks +| <script\b + + # make sure script is not an XML namespace + (?!:) + + [^>]*>.*?</script> + +''', flags) + +tag_expr = r''' +# Starts with the tag name at a word boundary, where the tag name is +# not a namespace +<%(tag_name)s\b(?!:) + +# All of the stuff up to a ">", hopefully attributes. +(?P<attrs>[^>]*?) + +(?: # Match a short tag + /> + +| # Match a full tag + > + + (?P<contents>.*?) + + # Closed by + (?: # One of the specified close tags + </?%(closers)s\s*> + + # End of the string + | \Z + + ) + +) +''' + + +def tagMatcher(tag_name, *close_tags): + if close_tags: + options = '|'.join((tag_name, ) + close_tags) + closers = '(?:%s)' % (options, ) + else: + closers = tag_name + + expr = tag_expr % locals() + return re.compile(expr, flags) + + +# Must contain at least an open html and an open head tag +html_find = tagMatcher('html') +head_find = tagMatcher('head', 'body') +link_find = re.compile(r'<link\b(?!:)', flags) + +attr_find = re.compile(r''' +# Must start with a sequence of word-characters, followed by an equals sign +(?P<attr_name>\w+)= + +# Then either a quoted or unquoted attribute +(?: + + # Match everything that\'s between matching quote marks + (?P<qopen>["\'])(?P<q_val>.*?)(?P=qopen) +| + + # If the value is not quoted, match up to whitespace + (?P<unq_val>(?:[^\s<>/]|/(?!>))+) +) + +| + +(?P<end_link>[<>]) +''', flags) + +# Entity replacement: +replacements = { + 'amp': '&', + 'lt': '<', + 'gt': '>', + 'quot': '"', +} + +ent_replace = re.compile(r'&(%s);' % '|'.join(list(replacements.keys()))) + + +def replaceEnt(mo): + "Replace the entities that are specified by OpenID" + return replacements.get(mo.group(1), mo.group()) + + +def parseLinkAttrs(html, ignore_errors=False): + """Find all link tags in a string representing a HTML document and + return a list of their attributes. + + @param html: the text to parse + @type html: str or unicode + + @param ignore_errors: whether to return despite e.g. parsing errors + @type ignore_errors: bool + + @return: A list of dictionaries of attributes, one for each link tag + @rtype: [[(type(html), type(html))]] + """ + if isinstance(html, bytes): + # Attempt to decode as UTF-8, since that's the most modern -- also + # try Latin-1, since that's suggested by HTTP/1.1. If neither of + # those works, fall over. + try: + html = html.decode("utf-8") + except UnicodeDecodeError: + try: + html = html.decode("latin1") + except UnicodeDecodeError: + if ignore_errors: + # Optionally ignore the errors and act as if no link attrs + # were found here + return [] + else: + raise AssertionError("Unreadable HTML!") + + stripped = removed_re.sub('', html) + html_mo = html_find.search(stripped) + if html_mo is None or html_mo.start('contents') == -1: + return [] + + start, end = html_mo.span('contents') + head_mo = head_find.search(stripped, start, end) + if head_mo is None or head_mo.start('contents') == -1: + return [] + + start, end = head_mo.span('contents') + link_mos = link_find.finditer(stripped, head_mo.start(), head_mo.end()) + + matches = [] + for link_mo in link_mos: + start = link_mo.start() + 5 + link_attrs = {} + for attr_mo in attr_find.finditer(stripped, start): + if attr_mo.lastgroup == 'end_link': + break + + # Either q_val or unq_val must be present, but not both + # unq_val is a True (non-empty) value if it is present + attr_name, q_val, unq_val = attr_mo.group('attr_name', 'q_val', + 'unq_val') + attr_val = ent_replace.sub(replaceEnt, unq_val or q_val) + + link_attrs[attr_name] = attr_val + + matches.append(link_attrs) + + return matches + + +def relMatches(rel_attr, target_rel): + """Does this target_rel appear in the rel_str?""" + # XXX: TESTME + rels = rel_attr.strip().split() + for rel in rels: + rel = rel.lower() + if rel == target_rel: + return 1 + + return 0 + + +def linkHasRel(link_attrs, target_rel): + """Does this link have target_rel as a relationship?""" + # XXX: TESTME + rel_attr = link_attrs.get('rel') + return rel_attr and relMatches(rel_attr, target_rel) + + +def findLinksRel(link_attrs_list, target_rel): + """Filter the list of link attributes on whether it has target_rel + as a relationship.""" + # XXX: TESTME + matchesTarget = lambda attrs: linkHasRel(attrs, target_rel) + return list(filter(matchesTarget, link_attrs_list)) + + +def findFirstHref(link_attrs_list, target_rel): + """Return the value of the href attribute for the first link tag + in the list that has target_rel as a relationship.""" + # XXX: TESTME + matches = findLinksRel(link_attrs_list, target_rel) + if not matches: + return None + first = matches[0] + return first.get('href') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/cryptutil.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/cryptutil.py new file mode 100644 index 0000000000000000000000000000000000000000..7fdd628519b6bb676c2d6a709ed28a3d33f61acc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/cryptutil.py @@ -0,0 +1,154 @@ +"""Module containing a cryptographic-quality source of randomness and +other cryptographically useful functionality + +Python 2.4 needs no external support for this module, nor does Python +2.3 on a system with /dev/urandom. + +Other configurations will need a quality source of random bytes and +access to a function that will convert binary strings to long +integers. This module will work with the Python Cryptography Toolkit +(pycrypto) if it is present. pycrypto can be found with a search +engine, but is currently found at: + +http://www.amk.ca/python/code/crypto +""" + +__all__ = [ + 'base64ToLong', + 'binaryToLong', + 'hmacSha1', + 'hmacSha256', + 'longToBase64', + 'longToBinary', + 'randomString', + 'randrange', + 'sha1', + 'sha256', +] + +import hmac +import os +import random + +from openid.oidutil import toBase64, fromBase64 + +import hashlib + + +class HashContainer(object): + def __init__(self, hash_constructor): + self.new = hash_constructor + self.digest_size = hash_constructor().digest_size + + +sha1_module = HashContainer(hashlib.sha1) +sha256_module = HashContainer(hashlib.sha256) + + +def hmacSha1(key, text): + if isinstance(key, str): + key = bytes(key, encoding="utf-8") + if isinstance(text, str): + text = bytes(text, encoding="utf-8") + return hmac.new(key, text, sha1_module).digest() + + +def sha1(s): + if isinstance(s, str): + s = bytes(s, encoding="utf-8") + return sha1_module.new(s).digest() + + +def hmacSha256(key, text): + if isinstance(key, str): + key = bytes(key, encoding="utf-8") + if isinstance(text, str): + text = bytes(text, encoding="utf-8") + return hmac.new(key, text, sha256_module).digest() + + +def sha256(s): + if isinstance(s, str): + s = bytes(s, encoding="utf-8") + return sha256_module.new(s).digest() + + +SHA256_AVAILABLE = True + +try: + from Crypto.Util.number import long_to_bytes, bytes_to_long +except ImportError: + # In the case where we don't have pycrypto installed, define substitute + # functionality. + + import pickle + + def longToBinary(l): + if l == 0: + return b'\x00' + b = bytearray(pickle.encode_long(l)) + b.reverse() + return bytes(b) + + def binaryToLong(s): + if isinstance(s, str): + s = s.encode("utf-8") + b = bytearray(s) + b.reverse() + return pickle.decode_long(bytes(b)) +else: + # We have pycrypto, so wrap its functions instead. + + def longToBinary(l): + if l < 0: + raise ValueError('This function only supports positive integers') + + bytestring = long_to_bytes(l) + if bytestring[0] > 127: + return b'\x00' + bytestring + else: + return bytestring + + def binaryToLong(bytestring): + if not bytestring: + raise ValueError('Empty string passed to strToLong') + + if bytestring[0] > 127: + raise ValueError('This function only supports positive integers') + + return bytes_to_long(bytestring) + + +# A cryptographically safe source of random bytes +getBytes = os.urandom + +# A randrange function that works for longs +randrange = random.randrange + + +def longToBase64(l): + return toBase64(longToBinary(l)) + + +def base64ToLong(s): + return binaryToLong(fromBase64(s)) + + +def randomString(length, chrs=None): + """Produce a string of length random bytes, chosen from chrs.""" + if chrs is None: + return getBytes(length) + else: + n = len(chrs) + return ''.join([chrs[randrange(n)] for _ in range(length)]) + + +def const_eq(s1, s2): + if len(s1) != len(s2): + return False + + result = True + for i in range(len(s1)): + result = result and (s1[i] == s2[i]) + + return result diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/dh.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/dh.py new file mode 100644 index 0000000000000000000000000000000000000000..5de7e4ecbbceb67cc766d1bc4015752c1b3a5fec --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/dh.py @@ -0,0 +1,47 @@ +from openid import cryptutil + + +def strxor(x, y): + if len(x) != len(y): + raise ValueError('Inputs to strxor must have the same length') + + if isinstance(x, str): + x = x.encode("utf-8") + if isinstance(y, str): + y = y.encode("utf-8") + + return bytes([a ^ b for a, b in zip(x, y)]) + + +class DiffieHellman(object): + DEFAULT_MOD = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443 + + DEFAULT_GEN = 2 + + def fromDefaults(cls): + return cls(cls.DEFAULT_MOD, cls.DEFAULT_GEN) + + fromDefaults = classmethod(fromDefaults) + + def __init__(self, modulus, generator): + self.modulus = int(modulus) + self.generator = int(generator) + + self._setPrivate(cryptutil.randrange(1, modulus - 1)) + + def _setPrivate(self, private): + """This is here to make testing easier""" + self.private = private + self.public = pow(self.generator, self.private, self.modulus) + + def usingDefaultValues(self): + return (self.modulus == self.DEFAULT_MOD and + self.generator == self.DEFAULT_GEN) + + def getSharedSecret(self, composite): + return pow(composite, self.private, self.modulus) + + def xorSecret(self, composite, secret, hash_func): + dh_shared = self.getSharedSecret(composite) + hashed_dh_shared = hash_func(cryptutil.longToBinary(dh_shared)) + return strxor(secret, hashed_dh_shared) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extension.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extension.py new file mode 100644 index 0000000000000000000000000000000000000000..0052f0033b88a9d6480cf9de767caa5ce67cb64d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extension.py @@ -0,0 +1,51 @@ +import warnings + +from openid import message as message_module + + +class Extension(object): + """An interface for OpenID extensions. + + @ivar ns_uri: The namespace to which to add the arguments for this + extension + """ + ns_uri = None + ns_alias = None + + def getExtensionArgs(self): + """Get the string arguments that should be added to an OpenID + message for this extension. + + @returns: A dictionary of completely non-namespaced arguments + to be added. For example, if the extension's alias is + 'uncle', and this method returns {'meat':'Hot Rats'}, the + final message will contain {'openid.uncle.meat':'Hot Rats'} + """ + raise NotImplementedError() + + def toMessage(self, message=None): + """Add the arguments from this extension to the provided + message, or create a new message containing only those + arguments. + + @returns: The message with the extension arguments added + """ + if message is None: + warnings.warn( + 'Passing None to Extension.toMessage is deprecated. ' + 'Creating a message assuming you want OpenID 2.', + DeprecationWarning, + stacklevel=2) + message = message_module.Message(message_module.OPENID2_NS) + + implicit = message.isOpenID1() + + try: + message.namespaces.addAlias( + self.ns_uri, self.ns_alias, implicit=implicit) + except KeyError: + if message.namespaces.getAlias(self.ns_uri) != self.ns_alias: + raise + + message.updateArgs(self.ns_uri, self.getExtensionArgs()) + return message diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..710b200268d9b29772d21bada5b25eb3429a4b74 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__init__.py @@ -0,0 +1,5 @@ +"""OpenID Extension modules.""" + +__all__ = ['ax', 'pape', 'sreg'] + +from openid.extensions.draft import pape5 as pape diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7675a407b4b6ee21a9e3739acd7aea8bcd807ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/ax.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/ax.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..946ba9343b3658669407cb0a343e4d054d3cf302 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/ax.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/sreg.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/sreg.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b0812464ba2d8350e80f73b53548d7946409d95 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/__pycache__/sreg.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/ax.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/ax.py new file mode 100644 index 0000000000000000000000000000000000000000..d36fd00872cf20be9a61470b09b5026a8f886dfa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/ax.py @@ -0,0 +1,781 @@ +# -*- test-case-name: openid.test.test_ax -*- +"""Implements the OpenID Attribute Exchange specification, version 1.0. + +@since: 2.1.0 +""" + +__all__ = [ + 'AttributeRequest', + 'FetchRequest', + 'FetchResponse', + 'StoreRequest', + 'StoreResponse', +] + +from openid import extension +from openid.server.trustroot import TrustRoot +from openid.message import NamespaceMap, OPENID_NS + +# Use this as the 'count' value for an attribute in a FetchRequest to +# ask for as many values as the OP can provide. +UNLIMITED_VALUES = "unlimited" + +# Minimum supported alias length in characters. Here for +# completeness. +MINIMUM_SUPPORTED_ALIAS_LENGTH = 32 + + +def checkAlias(alias): + """ + Check an alias for invalid characters; raise AXError if any are + found. Return None if the alias is valid. + """ + if ',' in alias: + raise AXError("Alias %r must not contain comma" % (alias, )) + if '.' in alias: + raise AXError("Alias %r must not contain period" % (alias, )) + + +class AXError(ValueError): + """Results from data that does not meet the attribute exchange 1.0 + specification""" + + +class NotAXMessage(AXError): + """Raised when there is no Attribute Exchange mode in the message.""" + + def __repr__(self): + return self.__class__.__name__ + + def __str__(self): + return self.__class__.__name__ + + +class AXMessage(extension.Extension): + """Abstract class containing common code for attribute exchange messages + + @cvar ns_alias: The preferred namespace alias for attribute + exchange messages + + @cvar mode: The type of this attribute exchange message. This must + be overridden in subclasses. + """ + + # This class is abstract, so it's OK that it doesn't override the + # abstract method in Extension: + # + #pylint:disable-msg=W0223 + + ns_alias = 'ax' + ns_uri = 'http://openid.net/srv/ax/1.0' + mode = None # NOTE mode is only ever set to a str value, see below + + def _checkMode(self, ax_args): + """Raise an exception if the mode in the attribute exchange + arguments does not match what is expected for this class. + + @raises NotAXMessage: When there is no mode value in ax_args at all. + + @raises AXError: When mode does not match. + """ + mode = ax_args.get('mode') + if isinstance(mode, bytes): + mode = str(mode, encoding="utf-8") + if mode != self.mode: + if not mode: + raise NotAXMessage() + else: + raise AXError('Expected mode %r; got %r' % (self.mode, mode)) + + def _newArgs(self): + """Return a set of attribute exchange arguments containing the + basic information that must be in every attribute exchange + message. + """ + return {'mode': self.mode} + + +class AttrInfo(object): + """Represents a single attribute in an attribute exchange + request. This should be added to an AXRequest object in order to + request the attribute. + + @ivar required: Whether the attribute will be marked as required + when presented to the subject of the attribute exchange + request. + @type required: bool + + @ivar count: How many values of this type to request from the + subject. Defaults to one. + @type count: int + + @ivar type_uri: The identifier that determines what the attribute + represents and how it is serialized. For example, one type URI + representing dates could represent a Unix timestamp in base 10 + and another could represent a human-readable string. + @type type_uri: str + + @ivar alias: The name that should be given to this alias in the + request. If it is not supplied, a generic name will be + assigned. For example, if you want to call a Unix timestamp + value 'tstamp', set its alias to that value. If two attributes + in the same message request to use the same alias, the request + will fail to be generated. + @type alias: str or NoneType + """ + + # It's OK that this class doesn't have public methods (it's just a + # holder for a bunch of attributes): + # + #pylint:disable-msg=R0903 + + def __init__(self, type_uri, count=1, required=False, alias=None): + self.required = required + self.count = count + self.type_uri = type_uri + self.alias = alias + + if self.alias is not None: + checkAlias(self.alias) + + def wantsUnlimitedValues(self): + """ + When processing a request for this attribute, the OP should + call this method to determine whether all available attribute + values were requested. If self.count == UNLIMITED_VALUES, + this returns True. Otherwise this returns False, in which + case self.count is an integer. + """ + return self.count == UNLIMITED_VALUES + + +def toTypeURIs(namespace_map, alias_list_s): + """Given a namespace mapping and a string containing a + comma-separated list of namespace aliases, return a list of type + URIs that correspond to those aliases. + + @param namespace_map: The mapping from namespace URI to alias + @type namespace_map: openid.message.NamespaceMap + + @param alias_list_s: The string containing the comma-separated + list of aliases. May also be None for convenience. + @type alias_list_s: str or NoneType + + @returns: The list of namespace URIs that corresponds to the + supplied list of aliases. If the string was zero-length or + None, an empty list will be returned. + + @raise KeyError: If an alias is present in the list of aliases but + is not present in the namespace map. + """ + uris = [] + + if alias_list_s: + for alias in alias_list_s.split(','): + type_uri = namespace_map.getNamespaceURI(alias) + if type_uri is None: + raise KeyError('No type is defined for attribute name %r' % + (alias, )) + else: + uris.append(type_uri) + + return uris + + +class FetchRequest(AXMessage): + """An attribute exchange 'fetch_request' message. This message is + sent by a relying party when it wishes to obtain attributes about + the subject of an OpenID authentication request. + + @ivar requested_attributes: The attributes that have been + requested thus far, indexed by the type URI. + @type requested_attributes: {str:AttrInfo} + + @ivar update_url: A URL that will accept responses for this + attribute exchange request, even in the absence of the user + who made this request. + """ + mode = 'fetch_request' + + def __init__(self, update_url=None): + AXMessage.__init__(self) + self.requested_attributes = {} + self.update_url = update_url + + def add(self, attribute): + """Add an attribute to this attribute exchange request. + + @param attribute: The attribute that is being requested + @type attribute: C{L{AttrInfo}} + + @returns: None + + @raise KeyError: when the requested attribute is already + present in this fetch request. + """ + if attribute.type_uri in self.requested_attributes: + raise KeyError('The attribute %r has already been requested' % + (attribute.type_uri, )) + + self.requested_attributes[attribute.type_uri] = attribute + + def getExtensionArgs(self): + """Get the serialized form of this attribute fetch request. + + @returns: The fetch request message parameters + @rtype: {unicode:unicode} + """ + aliases = NamespaceMap() + + required = [] + if_available = [] + + ax_args = self._newArgs() + + for type_uri, attribute in self.requested_attributes.items(): + if attribute.alias is None: + alias = aliases.add(type_uri) + else: + # This will raise an exception when the second + # attribute with the same alias is added. I think it + # would be better to complain at the time that the + # attribute is added to this object so that the code + # that is adding it is identified in the stack trace, + # but it's more work to do so, and it won't be 100% + # accurate anyway, since the attributes are + # mutable. So for now, just live with the fact that + # we'll learn about the error later. + # + # The other possible approach is to hide the error and + # generate a new alias on the fly. I think that would + # probably be bad. + alias = aliases.addAlias(type_uri, attribute.alias) + + if attribute.required: + required.append(alias) + else: + if_available.append(alias) + + if attribute.count != 1: + ax_args['count.' + alias] = str(attribute.count) + + ax_args['type.' + alias] = type_uri + + if required: + ax_args['required'] = ','.join(required) + + if if_available: + ax_args['if_available'] = ','.join(if_available) + + return ax_args + + def getRequiredAttrs(self): + """Get the type URIs for all attributes that have been marked + as required. + + @returns: A list of the type URIs for attributes that have + been marked as required. + @rtype: [str] + """ + required = [] + for type_uri, attribute in self.requested_attributes.items(): + if attribute.required: + required.append(type_uri) + + return required + + def fromOpenIDRequest(cls, openid_request): + """Extract a FetchRequest from an OpenID message + + @param openid_request: The OpenID authentication request + containing the attribute fetch request + @type openid_request: C{L{openid.server.server.CheckIDRequest}} + + @rtype: C{L{FetchRequest}} or C{None} + @returns: The FetchRequest extracted from the message or None, if + the message contained no AX extension. + + @raises KeyError: if the AuthRequest is not consistent in its use + of namespace aliases. + + @raises AXError: When parseExtensionArgs would raise same. + + @see: L{parseExtensionArgs} + """ + message = openid_request.message + ax_args = message.getArgs(cls.ns_uri) + self = cls() + try: + self.parseExtensionArgs(ax_args) + except NotAXMessage as err: + return None + + if self.update_url: + # Update URL must match the openid.realm of the underlying + # OpenID 2 message. + realm = message.getArg(OPENID_NS, 'realm', + message.getArg(OPENID_NS, 'return_to')) + + if not realm: + raise AXError( + ("Cannot validate update_url %r " + "against absent realm") + % (self.update_url, )) + + tr = TrustRoot.parse(realm) + if not tr.validateURL(self.update_url): + raise AXError( + "Update URL %r failed validation against realm %r" % + (self.update_url, realm, )) + + return self + + fromOpenIDRequest = classmethod(fromOpenIDRequest) + + def parseExtensionArgs(self, ax_args): + """Given attribute exchange arguments, populate this FetchRequest. + + @param ax_args: Attribute Exchange arguments from the request. + As returned from L{Message.getArgs<openid.message.Message.getArgs>}. + @type ax_args: dict + + @raises KeyError: if the message is not consistent in its use + of namespace aliases. + + @raises NotAXMessage: If ax_args does not include an Attribute Exchange + mode. + + @raises AXError: If the data to be parsed does not follow the + attribute exchange specification. At least when + 'if_available' or 'required' is not specified for a + particular attribute type. + """ + # Raises an exception if the mode is not the expected value + self._checkMode(ax_args) + + aliases = NamespaceMap() + + for key, value in ax_args.items(): + if key.startswith('type.'): + alias = key[5:] + type_uri = value + aliases.addAlias(type_uri, alias) + + count_key = 'count.' + alias + count_s = ax_args.get(count_key) + if count_s: + try: + count = int(count_s) + if count <= 0: + raise AXError( + "Count %r must be greater than zero, got %r" % + (count_key, count_s, )) + except ValueError: + if count_s != UNLIMITED_VALUES: + raise AXError("Invalid count value for %r: %r" % + (count_key, count_s, )) + count = count_s + else: + count = 1 + + self.add(AttrInfo(type_uri, alias=alias, count=count)) + + required = toTypeURIs(aliases, ax_args.get('required')) + + for type_uri in required: + self.requested_attributes[type_uri].required = True + + if_available = toTypeURIs(aliases, ax_args.get('if_available')) + + all_type_uris = required + if_available + + for type_uri in aliases.iterNamespaceURIs(): + if type_uri not in all_type_uris: + raise AXError('Type URI %r was in the request but not ' + 'present in "required" or "if_available"' % + (type_uri, )) + + self.update_url = ax_args.get('update_url') + + def iterAttrs(self): + """Iterate over the AttrInfo objects that are + contained in this fetch_request. + """ + return iter(self.requested_attributes.values()) + + def __iter__(self): + """Iterate over the attribute type URIs in this fetch_request + """ + return iter(self.requested_attributes) + + def has_key(self, type_uri): + """Is the given type URI present in this fetch_request? + """ + return type_uri in self.requested_attributes + + __contains__ = has_key + + +class AXKeyValueMessage(AXMessage): + """An abstract class that implements a message that has attribute + keys and values. It contains the common code between + fetch_response and store_request. + """ + + # This class is abstract, so it's OK that it doesn't override the + # abstract method in Extension: + # + #pylint:disable-msg=W0223 + + def __init__(self): + AXMessage.__init__(self) + self.data = {} + + def addValue(self, type_uri, value): + """Add a single value for the given attribute type to the + message. If there are already values specified for this type, + this value will be sent in addition to the values already + specified. + + @param type_uri: The URI for the attribute + + @param value: The value to add to the response to the relying + party for this attribute + @type value: unicode + + @returns: None + """ + try: + values = self.data[type_uri] + except KeyError: + values = self.data[type_uri] = [] + + values.append(value) + + def setValues(self, type_uri, values): + """Set the values for the given attribute type. This replaces + any values that have already been set for this attribute. + + @param type_uri: The URI for the attribute + + @param values: A list of values to send for this attribute. + @type values: [unicode] + """ + + self.data[type_uri] = values + + def _getExtensionKVArgs(self, aliases=None): + """Get the extension arguments for the key/value pairs + contained in this message. + + @param aliases: An alias mapping. Set to None if you don't + care about the aliases for this request. + """ + if aliases is None: + aliases = NamespaceMap() + + ax_args = {} + + for type_uri, values in self.data.items(): + alias = aliases.add(type_uri) + + ax_args['type.' + alias] = type_uri + ax_args['count.' + alias] = str(len(values)) + + for i, value in enumerate(values): + key = 'value.%s.%d' % (alias, i + 1) + ax_args[key] = value + + return ax_args + + def parseExtensionArgs(self, ax_args): + """Parse attribute exchange key/value arguments into this + object. + + @param ax_args: The attribute exchange fetch_response + arguments, with namespacing removed. + @type ax_args: {unicode:unicode} + + @returns: None + + @raises ValueError: If the message has bad values for + particular fields + + @raises KeyError: If the namespace mapping is bad or required + arguments are missing + """ + self._checkMode(ax_args) + + aliases = NamespaceMap() + + for key, value in ax_args.items(): + if key.startswith('type.'): + type_uri = value + alias = key[5:] + checkAlias(alias) + aliases.addAlias(type_uri, alias) + + for type_uri, alias in aliases.items(): + try: + count_s = ax_args['count.' + alias] + except KeyError: + value = ax_args['value.' + alias] + + if value == '': + values = [] + else: + values = [value] + else: + count = int(count_s) + values = [] + for i in range(1, count + 1): + value_key = 'value.%s.%d' % (alias, i) + value = ax_args[value_key] + values.append(value) + + self.data[type_uri] = values + + def getSingle(self, type_uri, default=None): + """Get a single value for an attribute. If no value was sent + for this attribute, use the supplied default. If there is more + than one value for this attribute, this method will fail. + + @type type_uri: str + @param type_uri: The URI for the attribute + + @param default: The value to return if the attribute was not + sent in the fetch_response. + + @returns: The value of the attribute in the fetch_response + message, or the default supplied + @rtype: unicode or NoneType + + @raises ValueError: If there is more than one value for this + parameter in the fetch_response message. + @raises KeyError: If the attribute was not sent in this response + """ + values = self.data.get(type_uri) + if not values: + return default + elif len(values) == 1: + return values[0] + else: + raise AXError('More than one value present for %r' % (type_uri, )) + + def get(self, type_uri): + """Get the list of values for this attribute in the + fetch_response. + + XXX: what to do if the values are not present? default + parameter? this is funny because it's always supposed to + return a list, so the default may break that, though it's + provided by the user's code, so it might be okay. If no + default is supplied, should the return be None or []? + + @param type_uri: The URI of the attribute + + @returns: The list of values for this attribute in the + response. May be an empty list. + @rtype: [unicode] + + @raises KeyError: If the attribute was not sent in the response + """ + return self.data[type_uri] + + def count(self, type_uri): + """Get the number of responses for a particular attribute in + this fetch_response message. + + @param type_uri: The URI of the attribute + + @returns: The number of values sent for this attribute + + @raises KeyError: If the attribute was not sent in the + response. KeyError will not be raised if the number of + values was zero. + """ + return len(self.get(type_uri)) + + +class FetchResponse(AXKeyValueMessage): + """A fetch_response attribute exchange message + """ + mode = 'fetch_response' + + def __init__(self, request=None, update_url=None): + """ + @param request: When supplied, I will use namespace aliases + that match those in this request. I will also check to + make sure I do not respond with attributes that were not + requested. + + @type request: L{FetchRequest} + + @param update_url: By default, C{update_url} is taken from the + request. But if you do not supply the request, you may set + the C{update_url} here. + + @type update_url: str + """ + AXKeyValueMessage.__init__(self) + self.update_url = update_url + self.request = request + + def getExtensionArgs(self): + """Serialize this object into arguments in the attribute + exchange namespace + + @returns: The dictionary of unqualified attribute exchange + arguments that represent this fetch_response. + @rtype: {unicode;unicode} + """ + + aliases = NamespaceMap() + + zero_value_types = [] + + if self.request is not None: + # Validate the data in the context of the request (the + # same attributes should be present in each, and the + # counts in the response must be no more than the counts + # in the request) + + for type_uri in self.data: + if type_uri not in self.request: + raise KeyError( + 'Response attribute not present in request: %r' % + (type_uri, )) + + for attr_info in self.request.iterAttrs(): + # Copy the aliases from the request so that reading + # the response in light of the request is easier + if attr_info.alias is None: + aliases.add(attr_info.type_uri) + else: + aliases.addAlias(attr_info.type_uri, attr_info.alias) + + try: + values = self.data[attr_info.type_uri] + except KeyError: + values = [] + zero_value_types.append(attr_info) + + if (attr_info.count != UNLIMITED_VALUES) and \ + (attr_info.count < len(values)): + raise AXError( + 'More than the number of requested values were ' + 'specified for %r' % (attr_info.type_uri, )) + + kv_args = self._getExtensionKVArgs(aliases) + + # Add the KV args into the response with the args that are + # unique to the fetch_response + ax_args = self._newArgs() + + # For each requested attribute, put its type/alias and count + # into the response even if no data were returned. + for attr_info in zero_value_types: + alias = aliases.getAlias(attr_info.type_uri) + kv_args['type.' + alias] = attr_info.type_uri + kv_args['count.' + alias] = '0' + + update_url = ((self.request and self.request.update_url) or + self.update_url) + + if update_url: + ax_args['update_url'] = update_url + + ax_args.update(kv_args) + + return ax_args + + def parseExtensionArgs(self, ax_args): + """@see: {Extension.parseExtensionArgs<openid.extension.Extension.parseExtensionArgs>}""" + super(FetchResponse, self).parseExtensionArgs(ax_args) + self.update_url = ax_args.get('update_url') + + def fromSuccessResponse(cls, success_response, signed=True): + """Construct a FetchResponse object from an OpenID library + SuccessResponse object. + + @param success_response: A successful id_res response object + @type success_response: openid.consumer.consumer.SuccessResponse + + @param signed: Whether non-signed args should be + processsed. If True (the default), only signed arguments + will be processsed. + @type signed: bool + + @returns: A FetchResponse containing the data from the OpenID + message, or None if the SuccessResponse did not contain AX + extension data. + + @raises AXError: when the AX data cannot be parsed. + """ + self = cls() + ax_args = success_response.extensionResponse(self.ns_uri, signed) + + try: + self.parseExtensionArgs(ax_args) + except NotAXMessage as err: + return None + else: + return self + + fromSuccessResponse = classmethod(fromSuccessResponse) + + +class StoreRequest(AXKeyValueMessage): + """A store request attribute exchange message representation + """ + mode = 'store_request' + + def __init__(self, aliases=None): + """ + @param aliases: The namespace aliases to use when making this + store request. Leave as None to use defaults. + """ + super(StoreRequest, self).__init__() + self.aliases = aliases + + def getExtensionArgs(self): + """ + @see: L{Extension.getExtensionArgs<openid.extension.Extension.getExtensionArgs>} + """ + ax_args = self._newArgs() + kv_args = self._getExtensionKVArgs(self.aliases) + ax_args.update(kv_args) + return ax_args + + +class StoreResponse(AXMessage): + """An indication that the store request was processed along with + this OpenID transaction. + """ + + SUCCESS_MODE = 'store_response_success' + FAILURE_MODE = 'store_response_failure' + + def __init__(self, succeeded=True, error_message=None): + AXMessage.__init__(self) + + if succeeded and error_message is not None: + raise AXError('An error message may only be included in a ' + 'failing fetch response') + if succeeded: + self.mode = self.SUCCESS_MODE + else: + self.mode = self.FAILURE_MODE + + self.error_message = error_message + + def succeeded(self): + """Was this response a success response?""" + return self.mode == self.SUCCESS_MODE + + def getExtensionArgs(self): + """@see: {Extension.getExtensionArgs<openid.extension.Extension.getExtensionArgs>}""" + ax_args = self._newArgs() + if not self.succeeded() and self.error_message: + ax_args['error'] = self.error_message + + return ax_args diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c11f84e96f33b8f10532ae9af3a574c4bb543245 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape2.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape2.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..defbf485f833d899bd03172a4b666d07939986c6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape2.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape5.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape5.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..860530a91e6bb2976d671b8fc18329d14cbedd48 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/__pycache__/pape5.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape2.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape2.py new file mode 100644 index 0000000000000000000000000000000000000000..d0587e316080de8846e7a2f80075b995395a878a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape2.py @@ -0,0 +1,285 @@ +"""An implementation of the OpenID Provider Authentication Policy +Extension 1.0 + +@see: http://openid.net/developers/specs/ + +@since: 2.1.0 +""" + +__all__ = [ + 'Request', + 'Response', + 'ns_uri', + 'AUTH_PHISHING_RESISTANT', + 'AUTH_MULTI_FACTOR', + 'AUTH_MULTI_FACTOR_PHYSICAL', +] + +from openid.extension import Extension +import re + +ns_uri = "http://specs.openid.net/extensions/pape/1.0" + +AUTH_MULTI_FACTOR_PHYSICAL = \ + 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical' +AUTH_MULTI_FACTOR = \ + 'http://schemas.openid.net/pape/policies/2007/06/multi-factor' +AUTH_PHISHING_RESISTANT = \ + 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant' + +TIME_VALIDATOR = re.compile('^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$') + + +class Request(Extension): + """A Provider Authentication Policy request, sent from a relying + party to a provider + + @ivar preferred_auth_policies: The authentication policies that + the relying party prefers + @type preferred_auth_policies: [str] + + @ivar max_auth_age: The maximum time, in seconds, that the relying + party wants to allow to have elapsed before the user must + re-authenticate + @type max_auth_age: int or NoneType + """ + + ns_alias = 'pape' + + def __init__(self, preferred_auth_policies=None, max_auth_age=None): + super(Request, self).__init__() + if not preferred_auth_policies: + preferred_auth_policies = [] + + self.preferred_auth_policies = preferred_auth_policies + self.max_auth_age = max_auth_age + + def __bool__(self): + return bool(self.preferred_auth_policies or + self.max_auth_age is not None) + + def addPolicyURI(self, policy_uri): + """Add an acceptable authentication policy URI to this request + + This method is intended to be used by the relying party to add + acceptable authentication types to the request. + + @param policy_uri: The identifier for the preferred type of + authentication. + @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies + """ + if policy_uri not in self.preferred_auth_policies: + self.preferred_auth_policies.append(policy_uri) + + def getExtensionArgs(self): + """@see: C{L{Extension.getExtensionArgs}} + """ + ns_args = { + 'preferred_auth_policies': ' '.join(self.preferred_auth_policies) + } + + if self.max_auth_age is not None: + ns_args['max_auth_age'] = str(self.max_auth_age) + + return ns_args + + def fromOpenIDRequest(cls, request): + """Instantiate a Request object from the arguments in a + C{checkid_*} OpenID message + """ + self = cls() + args = request.message.getArgs(self.ns_uri) + + if args == {}: + return None + + self.parseExtensionArgs(args) + return self + + fromOpenIDRequest = classmethod(fromOpenIDRequest) + + def parseExtensionArgs(self, args): + """Set the state of this request to be that expressed in these + PAPE arguments + + @param args: The PAPE arguments without a namespace + + @rtype: None + + @raises ValueError: When the max_auth_age is not parseable as + an integer + """ + + # preferred_auth_policies is a space-separated list of policy URIs + self.preferred_auth_policies = [] + + policies_str = args.get('preferred_auth_policies') + if policies_str: + if isinstance(policies_str, bytes): + policies_str = str(policies_str, encoding="utf-8") + for uri in policies_str.split(' '): + if uri not in self.preferred_auth_policies: + self.preferred_auth_policies.append(uri) + + # max_auth_age is base-10 integer number of seconds + max_auth_age_str = args.get('max_auth_age') + self.max_auth_age = None + + if max_auth_age_str: + try: + self.max_auth_age = int(max_auth_age_str) + except ValueError: + pass + + def preferredTypes(self, supported_types): + """Given a list of authentication policy URIs that a provider + supports, this method returns the subsequence of those types + that are preferred by the relying party. + + @param supported_types: A sequence of authentication policy + type URIs that are supported by a provider + + @returns: The sub-sequence of the supported types that are + preferred by the relying party. This list will be ordered + in the order that the types appear in the supported_types + sequence, and may be empty if the provider does not prefer + any of the supported authentication types. + + @returntype: [str] + """ + return list( + filter(self.preferred_auth_policies.__contains__, supported_types)) + + +Request.ns_uri = ns_uri + + +class Response(Extension): + """A Provider Authentication Policy response, sent from a provider + to a relying party + """ + + ns_alias = 'pape' + + def __init__(self, + auth_policies=None, + auth_time=None, + nist_auth_level=None): + super(Response, self).__init__() + if auth_policies: + self.auth_policies = auth_policies + else: + self.auth_policies = [] + + self.auth_time = auth_time + self.nist_auth_level = nist_auth_level + + def addPolicyURI(self, policy_uri): + """Add a authentication policy to this response + + This method is intended to be used by the provider to add a + policy that the provider conformed to when authenticating the user. + + @param policy_uri: The identifier for the preferred type of + authentication. + @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies + """ + if policy_uri not in self.auth_policies: + self.auth_policies.append(policy_uri) + + def fromSuccessResponse(cls, success_response): + """Create a C{L{Response}} object from a successful OpenID + library response + (C{L{openid.consumer.consumer.SuccessResponse}}) response + message + + @param success_response: A SuccessResponse from consumer.complete() + @type success_response: C{L{openid.consumer.consumer.SuccessResponse}} + + @rtype: Response or None + @returns: A provider authentication policy response from the + data that was supplied with the C{id_res} response or None + if the provider sent no signed PAPE response arguments. + """ + self = cls() + + # PAPE requires that the args be signed. + args = success_response.getSignedNS(self.ns_uri) + + # Only try to construct a PAPE response if the arguments were + # signed in the OpenID response. If not, return None. + if args is not None: + self.parseExtensionArgs(args) + return self + else: + return None + + def parseExtensionArgs(self, args, strict=False): + """Parse the provider authentication policy arguments into the + internal state of this object + + @param args: unqualified provider authentication policy + arguments + + @param strict: Whether to raise an exception when bad data is + encountered + + @returns: None. The data is parsed into the internal fields of + this object. + """ + policies_str = args.get('auth_policies') + if policies_str and policies_str != 'none': + self.auth_policies = policies_str.split(' ') + + nist_level_str = args.get('nist_auth_level') + if nist_level_str: + try: + nist_level = int(nist_level_str) + except ValueError: + if strict: + raise ValueError( + 'nist_auth_level must be an integer between ' + 'zero and four, inclusive') + else: + self.nist_auth_level = None + else: + if 0 <= nist_level < 5: + self.nist_auth_level = nist_level + + auth_time = args.get('auth_time') + if auth_time: + if TIME_VALIDATOR.match(auth_time): + self.auth_time = auth_time + elif strict: + raise ValueError("auth_time must be in RFC3339 format") + + fromSuccessResponse = classmethod(fromSuccessResponse) + + def getExtensionArgs(self): + """@see: C{L{Extension.getExtensionArgs}} + """ + if len(self.auth_policies) == 0: + ns_args = { + 'auth_policies': 'none', + } + else: + ns_args = { + 'auth_policies': ' '.join(self.auth_policies), + } + + if self.nist_auth_level is not None: + if self.nist_auth_level not in list(range(0, 5)): + raise ValueError('nist_auth_level must be an integer between ' + 'zero and four, inclusive') + ns_args['nist_auth_level'] = str(self.nist_auth_level) + + if self.auth_time is not None: + if not TIME_VALIDATOR.match(self.auth_time): + raise ValueError('auth_time must be in RFC3339 format') + + ns_args['auth_time'] = self.auth_time + + return ns_args + + +Response.ns_uri = ns_uri diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape5.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape5.py new file mode 100644 index 0000000000000000000000000000000000000000..e413250241d781b1ece5aec66ab5027bd0c3ec78 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/draft/pape5.py @@ -0,0 +1,481 @@ +"""An implementation of the OpenID Provider Authentication Policy +Extension 1.0, Draft 5 + +@see: http://openid.net/developers/specs/ + +@since: 2.1.0 +""" + +__all__ = [ + 'Request', + 'Response', + 'ns_uri', + 'AUTH_PHISHING_RESISTANT', + 'AUTH_MULTI_FACTOR', + 'AUTH_MULTI_FACTOR_PHYSICAL', + 'LEVELS_NIST', + 'LEVELS_JISA', +] + +from openid.extension import Extension +import warnings +import re + +ns_uri = "http://specs.openid.net/extensions/pape/1.0" + +AUTH_MULTI_FACTOR_PHYSICAL = \ + 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical' +AUTH_MULTI_FACTOR = \ + 'http://schemas.openid.net/pape/policies/2007/06/multi-factor' +AUTH_PHISHING_RESISTANT = \ + 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant' +AUTH_NONE = \ + 'http://schemas.openid.net/pape/policies/2007/06/none' + +TIME_VALIDATOR = re.compile(r'^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$') + +LEVELS_NIST = 'http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf' +LEVELS_JISA = 'http://www.jisa.or.jp/spec/auth_level.html' + + +class PAPEExtension(Extension): + _default_auth_level_aliases = { + 'nist': LEVELS_NIST, + 'jisa': LEVELS_JISA, + } + + def __init__(self): + self.auth_level_aliases = self._default_auth_level_aliases.copy() + + def _addAuthLevelAlias(self, auth_level_uri, alias=None): + """Add an auth level URI alias to this request. + + @param auth_level_uri: The auth level URI to send in the + request. + + @param alias: The namespace alias to use for this auth level + in this message. May be None if the alias is not + important. + """ + if alias is None: + try: + alias = self._getAlias(auth_level_uri) + except KeyError: + alias = self._generateAlias() + else: + existing_uri = self.auth_level_aliases.get(alias) + if existing_uri is not None and existing_uri != auth_level_uri: + raise KeyError('Attempting to redefine alias %r from %r to %r', + alias, existing_uri, auth_level_uri) + + self.auth_level_aliases[alias] = auth_level_uri + + def _generateAlias(self): + """Return an unused auth level alias""" + for i in range(1000): + alias = 'cust%d' % (i, ) + if alias not in self.auth_level_aliases: + return alias + + raise RuntimeError('Could not find an unused alias (tried 1000!)') + + def _getAlias(self, auth_level_uri): + """Return the alias for the specified auth level URI. + + @raises KeyError: if no alias is defined + """ + for (alias, existing_uri) in self.auth_level_aliases.items(): + if auth_level_uri == existing_uri: + return alias + + raise KeyError(auth_level_uri) + + +class Request(PAPEExtension): + """A Provider Authentication Policy request, sent from a relying + party to a provider + + @ivar preferred_auth_policies: The authentication policies that + the relying party prefers + @type preferred_auth_policies: [str] + + @ivar max_auth_age: The maximum time, in seconds, that the relying + party wants to allow to have elapsed before the user must + re-authenticate + @type max_auth_age: int or NoneType + + @ivar preferred_auth_level_types: Ordered list of authentication + level namespace URIs + + @type preferred_auth_level_types: [str] + """ + + ns_alias = 'pape' + + def __init__(self, + preferred_auth_policies=None, + max_auth_age=None, + preferred_auth_level_types=None): + super(Request, self).__init__() + if preferred_auth_policies is None: + preferred_auth_policies = [] + + self.preferred_auth_policies = preferred_auth_policies + self.max_auth_age = max_auth_age + self.preferred_auth_level_types = [] + + if preferred_auth_level_types is not None: + for auth_level in preferred_auth_level_types: + self.addAuthLevel(auth_level) + + def __bool__(self): + return bool(self.preferred_auth_policies or + self.max_auth_age is not None or + self.preferred_auth_level_types) + + def addPolicyURI(self, policy_uri): + """Add an acceptable authentication policy URI to this request + + This method is intended to be used by the relying party to add + acceptable authentication types to the request. + + @param policy_uri: The identifier for the preferred type of + authentication. + @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-05.html#auth_policies + """ + if policy_uri not in self.preferred_auth_policies: + self.preferred_auth_policies.append(policy_uri) + + def addAuthLevel(self, auth_level_uri, alias=None): + self._addAuthLevelAlias(auth_level_uri, alias) + if auth_level_uri not in self.preferred_auth_level_types: + self.preferred_auth_level_types.append(auth_level_uri) + + def getExtensionArgs(self): + """@see: C{L{Extension.getExtensionArgs}} + """ + ns_args = { + 'preferred_auth_policies': ' '.join(self.preferred_auth_policies), + } + + if self.max_auth_age is not None: + ns_args['max_auth_age'] = str(self.max_auth_age) + + if self.preferred_auth_level_types: + preferred_types = [] + + for auth_level_uri in self.preferred_auth_level_types: + alias = self._getAlias(auth_level_uri) + ns_args['auth_level.ns.%s' % (alias, )] = auth_level_uri + preferred_types.append(alias) + + ns_args['preferred_auth_level_types'] = ' '.join(preferred_types) + + return ns_args + + def fromOpenIDRequest(cls, request): + """Instantiate a Request object from the arguments in a + C{checkid_*} OpenID message + """ + self = cls() + args = request.message.getArgs(self.ns_uri) + is_openid1 = request.message.isOpenID1() + + if args == {}: + return None + + self.parseExtensionArgs(args, is_openid1) + return self + + fromOpenIDRequest = classmethod(fromOpenIDRequest) + + def parseExtensionArgs(self, args, is_openid1, strict=False): + """Set the state of this request to be that expressed in these + PAPE arguments + + @param args: The PAPE arguments without a namespace + + @param strict: Whether to raise an exception if the input is + out of spec or otherwise malformed. If strict is false, + malformed input will be ignored. + + @param is_openid1: Whether the input should be treated as part + of an OpenID1 request + + @rtype: None + + @raises ValueError: When the max_auth_age is not parseable as + an integer + """ + + # preferred_auth_policies is a space-separated list of policy URIs + self.preferred_auth_policies = [] + + policies_str = args.get('preferred_auth_policies') + if policies_str: + if isinstance(policies_str, bytes): + policies_str = str(policies_str, encoding="utf-8") + for uri in policies_str.split(' '): + if uri not in self.preferred_auth_policies: + self.preferred_auth_policies.append(uri) + + # max_auth_age is base-10 integer number of seconds + max_auth_age_str = args.get('max_auth_age') + self.max_auth_age = None + + if max_auth_age_str: + try: + self.max_auth_age = int(max_auth_age_str) + except ValueError: + if strict: + raise + + # Parse auth level information + preferred_auth_level_types = args.get('preferred_auth_level_types') + if preferred_auth_level_types: + aliases = preferred_auth_level_types.strip().split() + + for alias in aliases: + key = 'auth_level.ns.%s' % (alias, ) + try: + uri = args[key] + except KeyError: + if is_openid1: + uri = self._default_auth_level_aliases.get(alias) + else: + uri = None + + if uri is None: + if strict: + raise ValueError('preferred auth level %r is not ' + 'defined in this message' % (alias, )) + else: + self.addAuthLevel(uri, alias) + + def preferredTypes(self, supported_types): + """Given a list of authentication policy URIs that a provider + supports, this method returns the subsequence of those types + that are preferred by the relying party. + + @param supported_types: A sequence of authentication policy + type URIs that are supported by a provider + + @returns: The sub-sequence of the supported types that are + preferred by the relying party. This list will be ordered + in the order that the types appear in the supported_types + sequence, and may be empty if the provider does not prefer + any of the supported authentication types. + + @returntype: [str] + """ + return list( + filter(self.preferred_auth_policies.__contains__, supported_types)) + + +Request.ns_uri = ns_uri + + +class Response(PAPEExtension): + """A Provider Authentication Policy response, sent from a provider + to a relying party + + @ivar auth_policies: List of authentication policies conformed to + by this OpenID assertion, represented as policy URIs + """ + + ns_alias = 'pape' + + def __init__(self, auth_policies=None, auth_time=None, auth_levels=None): + super(Response, self).__init__() + if auth_policies: + self.auth_policies = auth_policies + else: + self.auth_policies = [] + + self.auth_time = auth_time + self.auth_levels = {} + + if auth_levels is None: + auth_levels = {} + + for uri, level in auth_levels.items(): + self.setAuthLevel(uri, level) + + def setAuthLevel(self, level_uri, level, alias=None): + """Set the value for the given auth level type. + + @param level: string representation of an authentication level + valid for level_uri + + @param alias: An optional namespace alias for the given auth + level URI. May be omitted if the alias is not + significant. The library will use a reasonable default for + widely-used auth level types. + """ + self._addAuthLevelAlias(level_uri, alias) + self.auth_levels[level_uri] = level + + def getAuthLevel(self, level_uri): + """Return the auth level for the specified auth level + identifier + + @returns: A string that should map to the auth levels defined + for the auth level type + + @raises KeyError: If the auth level type is not present in + this message + """ + return self.auth_levels[level_uri] + + def _getNISTAuthLevel(self): + try: + return int(self.getAuthLevel(LEVELS_NIST)) + except KeyError: + return None + + nist_auth_level = property( + _getNISTAuthLevel, + doc="Backward-compatibility accessor for the NIST auth level") + + def addPolicyURI(self, policy_uri): + """Add a authentication policy to this response + + This method is intended to be used by the provider to add a + policy that the provider conformed to when authenticating the user. + + @param policy_uri: The identifier for the preferred type of + authentication. + @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies + """ + if policy_uri == AUTH_NONE: + raise RuntimeError( + 'To send no policies, do not set any on the response.') + + if policy_uri not in self.auth_policies: + self.auth_policies.append(policy_uri) + + def fromSuccessResponse(cls, success_response): + """Create a C{L{Response}} object from a successful OpenID + library response + (C{L{openid.consumer.consumer.SuccessResponse}}) response + message + + @param success_response: A SuccessResponse from consumer.complete() + @type success_response: C{L{openid.consumer.consumer.SuccessResponse}} + + @rtype: Response or None + @returns: A provider authentication policy response from the + data that was supplied with the C{id_res} response or None + if the provider sent no signed PAPE response arguments. + """ + self = cls() + + # PAPE requires that the args be signed. + args = success_response.getSignedNS(self.ns_uri) + is_openid1 = success_response.isOpenID1() + + # Only try to construct a PAPE response if the arguments were + # signed in the OpenID response. If not, return None. + if args is not None: + self.parseExtensionArgs(args, is_openid1) + return self + else: + return None + + def parseExtensionArgs(self, args, is_openid1, strict=False): + """Parse the provider authentication policy arguments into the + internal state of this object + + @param args: unqualified provider authentication policy + arguments + + @param strict: Whether to raise an exception when bad data is + encountered + + @returns: None. The data is parsed into the internal fields of + this object. + """ + policies_str = args.get('auth_policies') + if policies_str: + auth_policies = policies_str.split(' ') + elif strict: + raise ValueError('Missing auth_policies') + else: + auth_policies = [] + + if (len(auth_policies) > 1 and strict and AUTH_NONE in auth_policies): + raise ValueError('Got some auth policies, as well as the special ' + '"none" URI: %r' % (auth_policies, )) + + if 'none' in auth_policies: + msg = '"none" used as a policy URI (see PAPE draft < 5)' + if strict: + raise ValueError(msg) + else: + warnings.warn(msg, stacklevel=2) + + auth_policies = [ + u for u in auth_policies if u not in ['none', AUTH_NONE] + ] + + self.auth_policies = auth_policies + + for (key, val) in args.items(): + if key.startswith('auth_level.'): + alias = key[11:] + + # skip the already-processed namespace declarations + if alias.startswith('ns.'): + continue + + try: + uri = args['auth_level.ns.%s' % (alias, )] + except KeyError: + if is_openid1: + uri = self._default_auth_level_aliases.get(alias) + else: + uri = None + + if uri is None: + if strict: + raise ValueError('Undefined auth level alias: %r' % + (alias, )) + else: + self.setAuthLevel(uri, val, alias) + + auth_time = args.get('auth_time') + if auth_time: + if TIME_VALIDATOR.match(auth_time): + self.auth_time = auth_time + elif strict: + raise ValueError("auth_time must be in RFC3339 format") + + fromSuccessResponse = classmethod(fromSuccessResponse) + + def getExtensionArgs(self): + """@see: C{L{Extension.getExtensionArgs}} + """ + if len(self.auth_policies) == 0: + ns_args = { + 'auth_policies': AUTH_NONE, + } + else: + ns_args = { + 'auth_policies': ' '.join(self.auth_policies), + } + + for level_type, level in self.auth_levels.items(): + alias = self._getAlias(level_type) + ns_args['auth_level.ns.%s' % (alias, )] = level_type + ns_args['auth_level.%s' % (alias, )] = str(level) + + if self.auth_time is not None: + if not TIME_VALIDATOR.match(self.auth_time): + raise ValueError('auth_time must be in RFC3339 format') + + ns_args['auth_time'] = self.auth_time + + return ns_args + + +Response.ns_uri = ns_uri diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/sreg.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/sreg.py new file mode 100644 index 0000000000000000000000000000000000000000..b626d378e51be7d1e847d49459c97d4895c07d0d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/extensions/sreg.py @@ -0,0 +1,529 @@ +"""Simple registration request and response parsing and object representation + +This module contains objects representing simple registration requests +and responses that can be used with both OpenID relying parties and +OpenID providers. + + 1. The relying party creates a request object and adds it to the + C{L{AuthRequest<openid.consumer.consumer.AuthRequest>}} object + before making the C{checkid_} request to the OpenID provider:: + + auth_request.addExtension(SRegRequest(required=['email'])) + + 2. The OpenID provider extracts the simple registration request from + the OpenID request using C{L{SRegRequest.fromOpenIDRequest}}, + gets the user's approval and data, creates a C{L{SRegResponse}} + object and adds it to the C{id_res} response:: + + sreg_req = SRegRequest.fromOpenIDRequest(checkid_request) + # [ get the user's approval and data, informing the user that + # the fields in sreg_response were requested ] + sreg_resp = SRegResponse.extractResponse(sreg_req, user_data) + sreg_resp.toMessage(openid_response.fields) + + 3. The relying party uses C{L{SRegResponse.fromSuccessResponse}} to + extract the data from the OpenID response:: + + sreg_resp = SRegResponse.fromSuccessResponse(success_response) + +@since: 2.0 + +@var sreg_data_fields: The names of the data fields that are listed in + the sreg spec, and a description of them in English + +@var sreg_uri: The preferred URI to use for the simple registration + namespace and XRD Type value +""" + +from openid.message import registerNamespaceAlias, \ + NamespaceAliasRegistrationError +from openid.extension import Extension +import logging + +logger = logging.getLogger(__name__) + +try: + str #pylint:disable-msg=W0104 +except NameError: + # For Python 2.2 + str = (str, str) #pylint:disable-msg=W0622 + +__all__ = [ + 'SRegRequest', + 'SRegResponse', + 'data_fields', + 'ns_uri', + 'ns_uri_1_0', + 'ns_uri_1_1', + 'supportsSReg', +] + +# The data fields that are listed in the sreg spec +data_fields = { + 'fullname': 'Full Name', + 'nickname': 'Nickname', + 'dob': 'Date of Birth', + 'email': 'E-mail Address', + 'gender': 'Gender', + 'postcode': 'Postal Code', + 'country': 'Country', + 'language': 'Language', + 'timezone': 'Time Zone', +} + + +def checkFieldName(field_name): + """Check to see that the given value is a valid simple + registration data field name. + + @raise ValueError: if the field name is not a valid simple + registration data field name + """ + if field_name not in data_fields: + raise ValueError('%r is not a defined simple registration field' % + (field_name, )) + + +# URI used in the wild for Yadis documents advertising simple +# registration support +ns_uri_1_0 = 'http://openid.net/sreg/1.0' + +# URI in the draft specification for simple registration 1.1 +# <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html> +ns_uri_1_1 = 'http://openid.net/extensions/sreg/1.1' + +# This attribute will always hold the preferred URI to use when adding +# sreg support to an XRDS file or in an OpenID namespace declaration. +ns_uri = ns_uri_1_1 + +try: + registerNamespaceAlias(ns_uri_1_1, 'sreg') +except NamespaceAliasRegistrationError as e: + logger.exception('registerNamespaceAlias(%r, %r) failed: %s' % + (ns_uri_1_1, 'sreg', str(e), )) + + +def supportsSReg(endpoint): + """Does the given endpoint advertise support for simple + registration? + + @param endpoint: The endpoint object as returned by OpenID discovery + @type endpoint: openid.consumer.discover.OpenIDEndpoint + + @returns: Whether an sreg type was advertised by the endpoint + @rtype: bool + """ + return (endpoint.usesExtension(ns_uri_1_1) or + endpoint.usesExtension(ns_uri_1_0)) + + +class SRegNamespaceError(ValueError): + """The simple registration namespace was not found and could not + be created using the expected name (there's another extension + using the name 'sreg') + + This is not I{illegal}, for OpenID 2, although it probably + indicates a problem, since it's not expected that other extensions + will re-use the alias that is in use for OpenID 1. + + If this is an OpenID 1 request, then there is no recourse. This + should not happen unless some code has modified the namespaces for + the message that is being processed. + """ + + +def getSRegNS(message): + """Extract the simple registration namespace URI from the given + OpenID message. Handles OpenID 1 and 2, as well as both sreg + namespace URIs found in the wild, as well as missing namespace + definitions (for OpenID 1) + + @param message: The OpenID message from which to parse simple + registration fields. This may be a request or response message. + @type message: C{L{openid.message.Message}} + + @returns: the sreg namespace URI for the supplied message. The + message may be modified to define a simple registration + namespace. + @rtype: C{str} + + @raise ValueError: when using OpenID 1 if the message defines + the 'sreg' alias to be something other than a simple + registration type. + """ + # See if there exists an alias for one of the two defined simple + # registration types. + for sreg_ns_uri in [ns_uri_1_1, ns_uri_1_0]: + alias = message.namespaces.getAlias(sreg_ns_uri) + if alias is not None: + break + else: + # There is no alias for either of the types, so try to add + # one. We default to using the modern value (1.1) + sreg_ns_uri = ns_uri_1_1 + try: + message.namespaces.addAlias(ns_uri_1_1, 'sreg') + except KeyError as why: + # An alias for the string 'sreg' already exists, but it's + # defined for something other than simple registration + raise SRegNamespaceError(why) + + # we know that sreg_ns_uri defined, because it's defined in the + # else clause of the loop as well, so disable the warning + return sreg_ns_uri #pylint:disable-msg=W0631 + + +class SRegRequest(Extension): + """An object to hold the state of a simple registration request. + + @ivar required: A list of the required fields in this simple + registration request + @type required: [str] + + @ivar optional: A list of the optional fields in this simple + registration request + @type optional: [str] + + @ivar policy_url: The policy URL that was provided with the request + @type policy_url: str or NoneType + + @group Consumer: requestField, requestFields, getExtensionArgs, addToOpenIDRequest + @group Server: fromOpenIDRequest, parseExtensionArgs + """ + + ns_alias = 'sreg' + + def __init__(self, + required=None, + optional=None, + policy_url=None, + sreg_ns_uri=ns_uri): + """Initialize an empty simple registration request""" + Extension.__init__(self) + self.required = [] + self.optional = [] + self.policy_url = policy_url + self.ns_uri = sreg_ns_uri + + if required: + self.requestFields(required, required=True, strict=True) + + if optional: + self.requestFields(optional, required=False, strict=True) + + # Assign getSRegNS to a static method so that it can be + # overridden for testing. + _getSRegNS = staticmethod(getSRegNS) + + def fromOpenIDRequest(cls, request): + """Create a simple registration request that contains the + fields that were requested in the OpenID request with the + given arguments + + @param request: The OpenID request + @type request: openid.server.CheckIDRequest + + @returns: The newly created simple registration request + @rtype: C{L{SRegRequest}} + """ + self = cls() + + # Since we're going to mess with namespace URI mapping, don't + # mutate the object that was passed in. + message = request.message.copy() + + self.ns_uri = self._getSRegNS(message) + args = message.getArgs(self.ns_uri) + self.parseExtensionArgs(args) + + return self + + fromOpenIDRequest = classmethod(fromOpenIDRequest) + + def parseExtensionArgs(self, args, strict=False): + """Parse the unqualified simple registration request + parameters and add them to this object. + + This method is essentially the inverse of + C{L{getExtensionArgs}}. This method restores the serialized simple + registration request fields. + + If you are extracting arguments from a standard OpenID + checkid_* request, you probably want to use C{L{fromOpenIDRequest}}, + which will extract the sreg namespace and arguments from the + OpenID request. This method is intended for cases where the + OpenID server needs more control over how the arguments are + parsed than that method provides. + + >>> args = message.getArgs(ns_uri) + >>> request.parseExtensionArgs(args) + + @param args: The unqualified simple registration arguments + @type args: {str:str} + + @param strict: Whether requests with fields that are not + defined in the simple registration specification should be + tolerated (and ignored) + @type strict: bool + + @returns: None; updates this object + """ + for list_name in ['required', 'optional']: + required = (list_name == 'required') + items = args.get(list_name) + if items: + for field_name in items.split(','): + try: + self.requestField(field_name, required, strict) + except ValueError: + if strict: + raise + + self.policy_url = args.get('policy_url') + + def allRequestedFields(self): + """A list of all of the simple registration fields that were + requested, whether they were required or optional. + + @rtype: [str] + """ + return self.required + self.optional + + def wereFieldsRequested(self): + """Have any simple registration fields been requested? + + @rtype: bool + """ + return bool(self.allRequestedFields()) + + def __contains__(self, field_name): + """Was this field in the request?""" + return (field_name in self.required or field_name in self.optional) + + def requestField(self, field_name, required=False, strict=False): + """Request the specified field from the OpenID user + + @param field_name: the unqualified simple registration field name + @type field_name: str + + @param required: whether the given field should be presented + to the user as being a required to successfully complete + the request + + @param strict: whether to raise an exception when a field is + added to a request more than once + + @raise ValueError: when the field requested is not a simple + registration field or strict is set and the field was + requested more than once + """ + checkFieldName(field_name) + + if strict: + if field_name in self.required or field_name in self.optional: + raise ValueError('That field has already been requested') + else: + if field_name in self.required: + return + + if field_name in self.optional: + if required: + self.optional.remove(field_name) + else: + return + + if required: + self.required.append(field_name) + else: + self.optional.append(field_name) + + def requestFields(self, field_names, required=False, strict=False): + """Add the given list of fields to the request + + @param field_names: The simple registration data fields to request + @type field_names: [str] + + @param required: Whether these values should be presented to + the user as required + + @param strict: whether to raise an exception when a field is + added to a request more than once + + @raise ValueError: when a field requested is not a simple + registration field or strict is set and a field was + requested more than once + """ + if isinstance(field_names, str): + raise TypeError('Fields should be passed as a list of ' + 'strings (not %r)' % (type(field_names), )) + + for field_name in field_names: + self.requestField(field_name, required, strict=strict) + + def getExtensionArgs(self): + """Get a dictionary of unqualified simple registration + arguments representing this request. + + This method is essentially the inverse of + C{L{parseExtensionArgs}}. This method serializes the simple + registration request fields. + + @rtype: {str:str} + """ + args = {} + + if self.required: + args['required'] = ','.join(self.required) + + if self.optional: + args['optional'] = ','.join(self.optional) + + if self.policy_url: + args['policy_url'] = self.policy_url + + return args + + +class SRegResponse(Extension): + """Represents the data returned in a simple registration response + inside of an OpenID C{id_res} response. This object will be + created by the OpenID server, added to the C{id_res} response + object, and then extracted from the C{id_res} message by the + Consumer. + + @ivar data: The simple registration data, keyed by the unqualified + simple registration name of the field (i.e. nickname is keyed + by C{'nickname'}) + + @ivar ns_uri: The URI under which the simple registration data was + stored in the response message. + + @group Server: extractResponse + @group Consumer: fromSuccessResponse + @group Read-only dictionary interface: keys, iterkeys, items, iteritems, + __iter__, get, __getitem__, keys, has_key + """ + + ns_alias = 'sreg' + + def __init__(self, data=None, sreg_ns_uri=ns_uri): + Extension.__init__(self) + if data is None: + self.data = {} + else: + self.data = data + + self.ns_uri = sreg_ns_uri + + def extractResponse(cls, request, data): + """Take a C{L{SRegRequest}} and a dictionary of simple + registration values and create a C{L{SRegResponse}} + object containing that data. + + @param request: The simple registration request object + @type request: SRegRequest + + @param data: The simple registration data for this + response, as a dictionary from unqualified simple + registration field name to string (unicode) value. For + instance, the nickname should be stored under the key + 'nickname'. + @type data: {str:str} + + @returns: a simple registration response object + @rtype: SRegResponse + """ + self = cls() + self.ns_uri = request.ns_uri + for field in request.allRequestedFields(): + value = data.get(field) + if value is not None: + self.data[field] = value + return self + + extractResponse = classmethod(extractResponse) + + # Assign getSRegArgs to a static method so that it can be + # overridden for testing + _getSRegNS = staticmethod(getSRegNS) + + def fromSuccessResponse(cls, success_response, signed_only=True): + """Create a C{L{SRegResponse}} object from a successful OpenID + library response + (C{L{openid.consumer.consumer.SuccessResponse}}) response + message + + @param success_response: A SuccessResponse from consumer.complete() + @type success_response: C{L{openid.consumer.consumer.SuccessResponse}} + + @param signed_only: Whether to process only data that was + signed in the id_res message from the server. + @type signed_only: bool + + @rtype: SRegResponse + @returns: A simple registration response containing the data + that was supplied with the C{id_res} response. + """ + self = cls() + self.ns_uri = self._getSRegNS(success_response.message) + if signed_only: + args = success_response.getSignedNS(self.ns_uri) + else: + args = success_response.message.getArgs(self.ns_uri) + + if not args: + return None + + for field_name in data_fields: + if field_name in args: + self.data[field_name] = args[field_name] + + return self + + fromSuccessResponse = classmethod(fromSuccessResponse) + + def getExtensionArgs(self): + """Get the fields to put in the simple registration namespace + when adding them to an id_res message. + + @see: openid.extension + """ + return self.data + + # Read-only dictionary interface + def get(self, field_name, default=None): + """Like dict.get, except that it checks that the field name is + defined by the simple registration specification""" + checkFieldName(field_name) + return self.data.get(field_name, default) + + def items(self): + """All of the data values in this simple registration response + """ + return list(self.data.items()) + + def iteritems(self): + return iter(self.data.items()) + + def keys(self): + return list(self.data.keys()) + + def iterkeys(self): + return iter(self.data.keys()) + + def has_key(self, key): + return key in self + + def __contains__(self, field_name): + checkFieldName(field_name) + return field_name in self.data + + def __iter__(self): + return iter(self.data) + + def __getitem__(self, field_name): + checkFieldName(field_name) + return self.data[field_name] + + def __bool__(self): + return bool(self.data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/fetchers.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/fetchers.py new file mode 100644 index 0000000000000000000000000000000000000000..c109cd2fd026f8414ae5d53012232891f107e2a6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/fetchers.py @@ -0,0 +1,493 @@ +# -*- test-case-name: openid.test.test_fetchers -*- +""" +This module contains the HTTP fetcher interface and several implementations. +""" + +__all__ = [ + 'fetch', 'getDefaultFetcher', 'setDefaultFetcher', 'HTTPResponse', + 'HTTPFetcher', 'createHTTPFetcher', 'HTTPFetchingError', 'HTTPError' +] + +import urllib.request +import urllib.error +import urllib.parse +import http.client + +import time +import io +import sys +import contextlib + +import openid +import openid.urinorm + +# Try to import httplib2 for caching support +# http://bitworking.org/projects/httplib2/ +try: + import httplib2 +except ImportError: + # httplib2 not available + httplib2 = None + +# try to import pycurl, which will let us use CurlHTTPFetcher +try: + import pycurl +except ImportError: + pycurl = None + +USER_AGENT = "python-openid/%s (%s)" % (openid.__version__, sys.platform) +MAX_RESPONSE_KB = 1024 + + +def fetch(url, body=None, headers=None): + """Invoke the fetch method on the default fetcher. Most users + should need only this method. + + @raises Exception: any exceptions that may be raised by the default fetcher + """ + fetcher = getDefaultFetcher() + return fetcher.fetch(url, body, headers) + + +def createHTTPFetcher(): + """Create a default HTTP fetcher instance + + prefers Curl to urllib2.""" + if pycurl is None: + fetcher = Urllib2Fetcher() + else: + fetcher = CurlHTTPFetcher() + + return fetcher + + +# Contains the currently set HTTP fetcher. If it is set to None, the +# library will call createHTTPFetcher() to set it. Do not access this +# variable outside of this module. +_default_fetcher = None + + +def getDefaultFetcher(): + """Return the default fetcher instance + if no fetcher has been set, it will create a default fetcher. + + @return: the default fetcher + @rtype: HTTPFetcher + """ + global _default_fetcher + + if _default_fetcher is None: + setDefaultFetcher(createHTTPFetcher()) + + return _default_fetcher + + +def setDefaultFetcher(fetcher, wrap_exceptions=True): + """Set the default fetcher + + @param fetcher: The fetcher to use as the default HTTP fetcher + @type fetcher: HTTPFetcher + + @param wrap_exceptions: Whether to wrap exceptions thrown by the + fetcher wil HTTPFetchingError so that they may be caught + easier. By default, exceptions will be wrapped. In general, + unwrapped fetchers are useful for debugging of fetching errors + or if your fetcher raises well-known exceptions that you would + like to catch. + @type wrap_exceptions: bool + """ + global _default_fetcher + if fetcher is None or not wrap_exceptions: + _default_fetcher = fetcher + else: + _default_fetcher = ExceptionWrappingFetcher(fetcher) + + +def usingCurl(): + """Whether the currently set HTTP fetcher is a Curl HTTP fetcher.""" + fetcher = getDefaultFetcher() + if isinstance(fetcher, ExceptionWrappingFetcher): + fetcher = fetcher.fetcher + return isinstance(fetcher, CurlHTTPFetcher) + + +class HTTPResponse(object): + """XXX document attributes""" + headers = None + status = None + body = None + final_url = None + + def __init__(self, final_url=None, status=None, headers=None, body=None): + self.final_url = final_url + self.status = status + self.headers = headers + self.body = body + + def __repr__(self): + return "<%s status %s for %s>" % (self.__class__.__name__, self.status, + self.final_url) + + +class HTTPFetcher(object): + """ + This class is the interface for openid HTTP fetchers. This + interface is only important if you need to write a new fetcher for + some reason. + """ + + def fetch(self, url, body=None, headers=None): + """ + This performs an HTTP POST or GET, following redirects along + the way. If a body is specified, then the request will be a + POST. Otherwise, it will be a GET. + + + @param headers: HTTP headers to include with the request + @type headers: {str:str} + + @return: An object representing the server's HTTP response. If + there are network or protocol errors, an exception will be + raised. HTTP error responses, like 404 or 500, do not + cause exceptions. + + @rtype: L{HTTPResponse} + + @raise Exception: Different implementations will raise + different errors based on the underlying HTTP library. + """ + raise NotImplementedError + + +def _allowedURL(url): + parsed = urllib.parse.urlparse(url) + # scheme is the first item in the tuple + return parsed[0] in ('http', 'https') + + +class HTTPFetchingError(Exception): + """Exception that is wrapped around all exceptions that are raised + by the underlying fetcher when using the ExceptionWrappingFetcher + + @ivar why: The exception that caused this exception + """ + + def __init__(self, why=None): + Exception.__init__(self, why) + self.why = why + + +class ExceptionWrappingFetcher(HTTPFetcher): + """Fetcher that wraps another fetcher, causing all exceptions + + @cvar uncaught_exceptions: Exceptions that should be exposed to the + user if they are raised by the fetch call + """ + + uncaught_exceptions = (SystemExit, KeyboardInterrupt, MemoryError) + + def __init__(self, fetcher): + self.fetcher = fetcher + + def fetch(self, *args, **kwargs): + try: + return self.fetcher.fetch(*args, **kwargs) + except self.uncaught_exceptions: + raise + except: + exc_cls, exc_inst = sys.exc_info()[:2] + if exc_inst is None: + # string exceptions + exc_inst = exc_cls + + raise HTTPFetchingError(why=exc_inst) + + +class Urllib2Fetcher(HTTPFetcher): + """An C{L{HTTPFetcher}} that uses urllib2. + """ + + # Parameterized for the benefit of testing frameworks, see + # http://trac.openidenabled.com/trac/ticket/85 + urlopen = staticmethod(urllib.request.urlopen) + + def fetch(self, url, body=None, headers=None): + if not _allowedURL(url): + raise ValueError('Bad URL scheme: %r' % (url, )) + + if headers is None: + headers = {} + + headers.setdefault('User-Agent', "%s Python-urllib/%s" % + (USER_AGENT, urllib.request.__version__)) + + if isinstance(body, str): + body = bytes(body, encoding="utf-8") + + req = urllib.request.Request(url, data=body, headers=headers) + + url_resource = None + try: + url_resource = self.urlopen(req) + with contextlib.closing(url_resource): + return self._makeResponse(url_resource) + except urllib.error.HTTPError as why: + with contextlib.closing(why): + resp = self._makeResponse(why) + return resp + except (urllib.error.URLError, http.client.BadStatusLine) as why: + raise + except Exception as why: + raise AssertionError(why) + + def _makeResponse(self, urllib2_response): + ''' + Construct an HTTPResponse from the the urllib response. Attempt to + decode the response body from bytes to str if the necessary information + is available. + ''' + resp = HTTPResponse() + resp.body = urllib2_response.read(MAX_RESPONSE_KB * 1024) + resp.final_url = urllib2_response.geturl() + resp.headers = self._lowerCaseKeys( + dict(list(urllib2_response.info().items()))) + + if hasattr(urllib2_response, 'code'): + resp.status = urllib2_response.code + else: + resp.status = 200 + + _, extra_dict = self._parseHeaderValue( + resp.headers.get("content-type", "")) + # Try to decode the response body to a string, if there's a + # charset known; fall back to ISO-8859-1 otherwise, since that's + # what's suggested in HTTP/1.1 + charset = extra_dict.get('charset', 'latin1') + try: + resp.body = resp.body.decode(charset) + except Exception: + pass + + return resp + + def _lowerCaseKeys(self, headers_dict): + new_dict = {} + for k, v in headers_dict.items(): + new_dict[k.lower()] = v + return new_dict + + def _parseHeaderValue(self, header_value): + """ + Parse out a complex header value (such as Content-Type, with a value + like "text/html; charset=utf-8") into a main value and a dictionary of + extra information (in this case, 'text/html' and {'charset': 'utf8'}). + """ + values = header_value.split(';', 1) + if len(values) == 1: + # There's no extra info -- return the main value and an empty dict + return values[0], {} + main_value, extra_values = values[0], values[1].split(';') + extra_dict = {} + for value_string in extra_values: + try: + key, value = value_string.split('=', 1) + extra_dict[key.strip()] = value.strip() + except ValueError: + # Can't unpack it -- must be malformed. Ignore + pass + return main_value, extra_dict + + +class HTTPError(HTTPFetchingError): + """ + This exception is raised by the C{L{CurlHTTPFetcher}} when it + encounters an exceptional situation fetching a URL. + """ + pass + + +# XXX: define what we mean by paranoid, and make sure it is. +class CurlHTTPFetcher(HTTPFetcher): + """ + An C{L{HTTPFetcher}} that uses pycurl for fetching. + See U{http://pycurl.sourceforge.net/}. + """ + ALLOWED_TIME = 20 # seconds + + def __init__(self): + HTTPFetcher.__init__(self) + if pycurl is None: + raise RuntimeError('Cannot find pycurl library') + + def _parseHeaders(self, header_file): + header_file.seek(0) + + # Remove all non "name: value" header lines from the input + lines = [line.decode().strip() for line in header_file if b':' in line] + + headers = {} + for line in lines: + try: + name, value = line.split(':', 1) + except ValueError: + raise HTTPError("Malformed HTTP header line in response: %r" % + (line, )) + + value = value.strip() + + # HTTP headers are case-insensitive + name = name.lower() + headers[name] = value + + return headers + + def _checkURL(self, url): + # XXX: document that this can be overridden to match desired policy + # XXX: make sure url is well-formed and routeable + return _allowedURL(url) + + def fetch(self, url, body=None, headers=None): + stop = int(time.time()) + self.ALLOWED_TIME + off = self.ALLOWED_TIME + + if headers is None: + headers = {} + + headers.setdefault('User-Agent', + "%s %s" % (USER_AGENT, pycurl.version, )) + + header_list = [] + if headers is not None: + for header_name, header_value in headers.items(): + header = '%s: %s' % (header_name, header_value) + header_list.append(header.encode()) + + c = pycurl.Curl() + try: + c.setopt(pycurl.NOSIGNAL, 1) + + if header_list: + c.setopt(pycurl.HTTPHEADER, header_list) + + # Presence of a body indicates that we should do a POST + if body is not None: + c.setopt(pycurl.POST, 1) + c.setopt(pycurl.POSTFIELDS, body) + + while off > 0: + if not self._checkURL(url): + raise HTTPError("Fetching URL not allowed: %r" % (url, )) + + data = io.BytesIO() + + def write_data(chunk): + if data.tell() > (1024 * MAX_RESPONSE_KB): + return 0 + else: + return data.write(chunk) + + response_header_data = io.BytesIO() + c.setopt(pycurl.WRITEFUNCTION, write_data) + c.setopt(pycurl.HEADERFUNCTION, response_header_data.write) + c.setopt(pycurl.TIMEOUT, off) + c.setopt(pycurl.URL, openid.urinorm.urinorm(url)) + + c.perform() + + response_headers = self._parseHeaders(response_header_data) + code = c.getinfo(pycurl.RESPONSE_CODE) + if code in [301, 302, 303, 307]: + url = response_headers.get('location') + if url is None: + raise HTTPError( + 'Redirect (%s) returned without a location' % code) + + # Redirects are always GETs + c.setopt(pycurl.POST, 0) + + # There is no way to reset POSTFIELDS to empty and + # reuse the connection, but we only use it once. + else: + resp = HTTPResponse() + resp.headers = response_headers + resp.status = code + resp.final_url = url + resp.body = data.getvalue().decode() + return resp + + off = stop - int(time.time()) + + raise HTTPError("Timed out fetching: %r" % (url, )) + finally: + c.close() + + +class HTTPLib2Fetcher(HTTPFetcher): + """A fetcher that uses C{httplib2} for performing HTTP + requests. This implementation supports HTTP caching. + + @see: http://bitworking.org/projects/httplib2/ + """ + + def __init__(self, cache=None): + """@param cache: An object suitable for use as an C{httplib2} + cache. If a string is passed, it is assumed to be a + directory name. + """ + if httplib2 is None: + raise RuntimeError('Cannot find httplib2 library. ' + 'See http://bitworking.org/projects/httplib2/') + + super(HTTPLib2Fetcher, self).__init__() + + # An instance of the httplib2 object that performs HTTP requests + self.httplib2 = httplib2.Http(cache) + + # We want httplib2 to raise exceptions for errors, just like + # the other fetchers. + self.httplib2.force_exception_to_status_code = False + + def fetch(self, url, body=None, headers=None): + """Perform an HTTP request + + @raises Exception: Any exception that can be raised by httplib2 + + @see: C{L{HTTPFetcher.fetch}} + """ + if body: + method = 'POST' + else: + method = 'GET' + + if headers is None: + headers = {} + + # httplib2 doesn't check to make sure that the URL's scheme is + # 'http' so we do it here. + if not (url.startswith('http://') or url.startswith('https://')): + raise ValueError('URL is not a HTTP URL: %r' % (url, )) + + httplib2_response, content = self.httplib2.request( + url, method, body=body, headers=headers) + + # Translate the httplib2 response to our HTTP response abstraction + + # When a 400 is returned, there is no "content-location" + # header set. This seems like a bug to me. I can't think of a + # case where we really care about the final URL when it is an + # error response, but being careful about it can't hurt. + try: + final_url = httplib2_response['content-location'] + except KeyError: + # We're assuming that no redirects occurred + assert not httplib2_response.previous + + # And this should never happen for a successful response + assert httplib2_response.status != 200 + final_url = url + + return HTTPResponse( + body=content.decode(), # TODO Don't assume ASCII + final_url=final_url, + headers=dict(list(httplib2_response.items())), + status=httplib2_response.status, ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/kvform.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/kvform.py new file mode 100644 index 0000000000000000000000000000000000000000..f8985d9aec59d02fc22f8ec343ce89ff97472f71 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/kvform.py @@ -0,0 +1,134 @@ +import logging + +logger = logging.getLogger(__name__) + +__all__ = ['seqToKV', 'kvToSeq', 'dictToKV', 'kvToDict'] + + +class KVFormError(ValueError): + pass + + +def seqToKV(seq, strict=False): + """Represent a sequence of pairs of strings as newline-terminated + key:value pairs. The pairs are generated in the order given. + + @param seq: The pairs + @type seq: [(str, (unicode|str))] + + @return: A string representation of the sequence + @rtype: bytes + """ + + def err(msg): + formatted = 'seqToKV warning: %s: %r' % (msg, seq) + if strict: + raise KVFormError(formatted) + else: + logger.warning(formatted) + + lines = [] + for k, v in seq: + if isinstance(k, bytes): + k = k.decode('utf-8') + elif not isinstance(k, str): + err('Converting key to string: %r' % k) + k = str(k) + + if '\n' in k: + raise KVFormError( + 'Invalid input for seqToKV: key contains newline: %r' % (k, )) + + if ':' in k: + raise KVFormError( + 'Invalid input for seqToKV: key contains colon: %r' % (k, )) + + if k.strip() != k: + err('Key has whitespace at beginning or end: %r' % (k, )) + + if isinstance(v, bytes): + v = v.decode('utf-8') + elif not isinstance(v, str): + err('Converting value to string: %r' % (v, )) + v = str(v) + + if '\n' in v: + raise KVFormError( + 'Invalid input for seqToKV: value contains newline: %r' % + (v, )) + + if v.strip() != v: + err('Value has whitespace at beginning or end: %r' % (v, )) + + lines.append(k + ':' + v + '\n') + + return ''.join(lines).encode('utf-8') + + +def kvToSeq(data, strict=False): + """ + + After one parse, seqToKV and kvToSeq are inverses, with no warnings:: + + seq = kvToSeq(s) + seqToKV(kvToSeq(seq)) == seq + + @return str + """ + + def err(msg): + formatted = 'kvToSeq warning: %s: %r' % (msg, data) + if strict: + raise KVFormError(formatted) + else: + logger.warning(formatted) + + if isinstance(data, bytes): + data = data.decode("utf-8") + + lines = data.split('\n') + if lines[-1]: + err('Does not end in a newline') + else: + del lines[-1] + + pairs = [] + line_num = 0 + for line in lines: + line_num += 1 + + # Ignore blank lines + if not line.strip(): + continue + + pair = line.split(':', 1) + if len(pair) == 2: + k, v = pair + k_s = k.strip() + if k_s != k: + fmt = ('In line %d, ignoring leading or trailing ' + 'whitespace in key %r') + err(fmt % (line_num, k)) + + if not k_s: + err('In line %d, got empty key' % (line_num, )) + + v_s = v.strip() + if v_s != v: + fmt = ('In line %d, ignoring leading or trailing ' + 'whitespace in value %r') + err(fmt % (line_num, v)) + + pairs.append((k_s, v_s)) + else: + err('Line %d does not contain a colon' % line_num) + + return pairs + + +def dictToKV(d): + return seqToKV(sorted(d.items())) + + +def kvToDict(s): + return dict(kvToSeq(s)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/message.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/message.py new file mode 100644 index 0000000000000000000000000000000000000000..325c14d414e3244df57909376d8f5196d65ac2c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/message.py @@ -0,0 +1,678 @@ +"""Extension argument processing code +""" +__all__ = [ + 'Message', 'NamespaceMap', 'no_default', 'registerNamespaceAlias', + 'OPENID_NS', 'BARE_NS', 'OPENID1_NS', 'OPENID2_NS', 'SREG_URI', + 'IDENTIFIER_SELECT' +] + +import copy +import warnings +import urllib.request +import urllib.error + +from openid import oidutil +from openid import kvform +try: + ElementTree = oidutil.importElementTree() +except ImportError: + # No elementtree found, so give up, but don't fail to import, + # since we have fallbacks. + ElementTree = None + +# This doesn't REALLY belong here, but where is better? +IDENTIFIER_SELECT = 'http://specs.openid.net/auth/2.0/identifier_select' + +# URI for Simple Registration extension, the only commonly deployed +# OpenID 1.x extension, and so a special case +SREG_URI = 'http://openid.net/sreg/1.0' + +# The OpenID 1.X namespace URI +OPENID1_NS = 'http://openid.net/signon/1.0' +THE_OTHER_OPENID1_NS = 'http://openid.net/signon/1.1' + +OPENID1_NAMESPACES = OPENID1_NS, THE_OTHER_OPENID1_NS + +# The OpenID 2.0 namespace URI +OPENID2_NS = 'http://specs.openid.net/auth/2.0' + +# The namespace consisting of pairs with keys that are prefixed with +# "openid." but not in another namespace. +NULL_NAMESPACE = oidutil.Symbol('Null namespace') + +# The null namespace, when it is an allowed OpenID namespace +OPENID_NS = oidutil.Symbol('OpenID namespace') + +# The top-level namespace, excluding all pairs with keys that start +# with "openid." +BARE_NS = oidutil.Symbol('Bare namespace') + +# Limit, in bytes, of identity provider and return_to URLs, including +# response payload. See OpenID 1.1 specification, Appendix D. +OPENID1_URL_LIMIT = 2047 + +# All OpenID protocol fields. Used to check namespace aliases. +OPENID_PROTOCOL_FIELDS = [ + 'ns', + 'mode', + 'error', + 'return_to', + 'contact', + 'reference', + 'signed', + 'assoc_type', + 'session_type', + 'dh_modulus', + 'dh_gen', + 'dh_consumer_public', + 'claimed_id', + 'identity', + 'realm', + 'invalidate_handle', + 'op_endpoint', + 'response_nonce', + 'sig', + 'assoc_handle', + 'trust_root', + 'openid', +] + + +class UndefinedOpenIDNamespace(ValueError): + """Raised if the generic OpenID namespace is accessed when there + is no OpenID namespace set for this message.""" + + +class InvalidOpenIDNamespace(ValueError): + """Raised if openid.ns is not a recognized value. + + For recognized values, see L{Message.allowed_openid_namespaces} + """ + + def __str__(self): + s = "Invalid OpenID Namespace" + if self.args: + s += " %r" % (self.args[0], ) + return s + + +# Sentinel used for Message implementation to indicate that getArg +# should raise an exception instead of returning a default. +no_default = object() + +# Global namespace / alias registration map. See +# registerNamespaceAlias. +registered_aliases = {} + + +class NamespaceAliasRegistrationError(Exception): + """ + Raised when an alias or namespace URI has already been registered. + """ + pass + + +def registerNamespaceAlias(namespace_uri, alias): + """ + Registers a (namespace URI, alias) mapping in a global namespace + alias map. Raises NamespaceAliasRegistrationError if either the + namespace URI or alias has already been registered with a + different value. This function is required if you want to use a + namespace with an OpenID 1 message. + """ + global registered_aliases + + if registered_aliases.get(alias) == namespace_uri: + return + + if namespace_uri in list(registered_aliases.values()): + raise NamespaceAliasRegistrationError( + 'Namespace uri %r already registered' % (namespace_uri, )) + + if alias in registered_aliases: + raise NamespaceAliasRegistrationError('Alias %r already registered' % + (alias, )) + + registered_aliases[alias] = namespace_uri + + +class Message(object): + """ + In the implementation of this object, None represents the global + namespace as well as a namespace with no key. + + @cvar namespaces: A dictionary specifying specific + namespace-URI to alias mappings that should be used when + generating namespace aliases. + + @ivar ns_args: two-level dictionary of the values in this message, + grouped by namespace URI. The first level is the namespace + URI. + """ + + allowed_openid_namespaces = [OPENID1_NS, THE_OTHER_OPENID1_NS, OPENID2_NS] + + def __init__(self, openid_namespace=None): + """Create an empty Message. + + @raises InvalidOpenIDNamespace: if openid_namespace is not in + L{Message.allowed_openid_namespaces} + """ + self.args = {} + self.namespaces = NamespaceMap() + if openid_namespace is None: + self._openid_ns_uri = None + else: + implicit = openid_namespace in OPENID1_NAMESPACES + self.setOpenIDNamespace(openid_namespace, implicit) + + @classmethod + def fromPostArgs(cls, args): + """Construct a Message containing a set of POST arguments. + + """ + self = cls() + + # Partition into "openid." args and bare args + openid_args = {} + for key, value in args.items(): + if isinstance(value, list): + raise TypeError("query dict must have one value for each key, " + "not lists of values. Query is %r" % (args, )) + + try: + prefix, rest = key.split('.', 1) + except ValueError: + prefix = None + + if prefix != 'openid': + self.args[(BARE_NS, key)] = value + else: + openid_args[rest] = value + + self._fromOpenIDArgs(openid_args) + + return self + + @classmethod + def fromOpenIDArgs(cls, openid_args): + """Construct a Message from a parsed KVForm message. + + @raises InvalidOpenIDNamespace: if openid.ns is not in + L{Message.allowed_openid_namespaces} + """ + self = cls() + self._fromOpenIDArgs(openid_args) + return self + + def _fromOpenIDArgs(self, openid_args): + ns_args = [] + + # Resolve namespaces + for rest, value in openid_args.items(): + try: + ns_alias, ns_key = rest.split('.', 1) + except ValueError: + ns_alias = NULL_NAMESPACE + ns_key = rest + + if ns_alias == 'ns': + self.namespaces.addAlias(value, ns_key) + elif ns_alias == NULL_NAMESPACE and ns_key == 'ns': + # null namespace + self.setOpenIDNamespace(value, False) + else: + ns_args.append((ns_alias, ns_key, value)) + + # Implicitly set an OpenID namespace definition (OpenID 1) + if not self.getOpenIDNamespace(): + self.setOpenIDNamespace(OPENID1_NS, True) + + # Actually put the pairs into the appropriate namespaces + for (ns_alias, ns_key, value) in ns_args: + ns_uri = self.namespaces.getNamespaceURI(ns_alias) + if ns_uri is None: + # we found a namespaced arg without a namespace URI defined + ns_uri = self._getDefaultNamespace(ns_alias) + if ns_uri is None: + ns_uri = self.getOpenIDNamespace() + ns_key = '%s.%s' % (ns_alias, ns_key) + else: + self.namespaces.addAlias(ns_uri, ns_alias, implicit=True) + + self.setArg(ns_uri, ns_key, value) + + def _getDefaultNamespace(self, mystery_alias): + """OpenID 1 compatibility: look for a default namespace URI to + use for this alias.""" + global registered_aliases + # Only try to map an alias to a default if it's an + # OpenID 1.x message. + if self.isOpenID1(): + return registered_aliases.get(mystery_alias) + else: + return None + + def setOpenIDNamespace(self, openid_ns_uri, implicit): + """Set the OpenID namespace URI used in this message. + + @raises InvalidOpenIDNamespace: if the namespace is not in + L{Message.allowed_openid_namespaces} + """ + if isinstance(openid_ns_uri, bytes): + openid_ns_uri = str(openid_ns_uri, encoding="utf-8") + if openid_ns_uri not in self.allowed_openid_namespaces: + raise InvalidOpenIDNamespace(openid_ns_uri) + + self.namespaces.addAlias(openid_ns_uri, NULL_NAMESPACE, implicit) + self._openid_ns_uri = openid_ns_uri + + def getOpenIDNamespace(self): + return self._openid_ns_uri + + def isOpenID1(self): + return self.getOpenIDNamespace() in OPENID1_NAMESPACES + + def isOpenID2(self): + return self.getOpenIDNamespace() == OPENID2_NS + + def fromKVForm(cls, kvform_string): + """Create a Message from a KVForm string""" + return cls.fromOpenIDArgs(kvform.kvToDict(kvform_string)) + + fromKVForm = classmethod(fromKVForm) + + def copy(self): + return copy.deepcopy(self) + + def toPostArgs(self): + """ + Return all arguments with openid. in front of namespaced arguments. + @return bytes + """ + args = {} + + # Add namespace definitions to the output + for ns_uri, alias in self.namespaces.items(): + if self.namespaces.isImplicit(ns_uri): + continue + if alias == NULL_NAMESPACE: + ns_key = 'openid.ns' + else: + ns_key = 'openid.ns.' + alias + args[ns_key] = oidutil.toUnicode(ns_uri) + + for (ns_uri, ns_key), value in self.args.items(): + key = self.getKey(ns_uri, ns_key) + # Ensure the resulting value is an UTF-8 encoded *bytestring*. + args[key] = oidutil.toUnicode(value) + + return args + + def toArgs(self): + """Return all namespaced arguments, failing if any + non-namespaced arguments exist.""" + # FIXME - undocumented exception + post_args = self.toPostArgs() + kvargs = {} + for k, v in post_args.items(): + if not k.startswith('openid.'): + raise ValueError( + 'This message can only be encoded as a POST, because it ' + 'contains arguments that are not prefixed with "openid."') + else: + kvargs[k[7:]] = v + + return kvargs + + def toFormMarkup(self, + action_url, + form_tag_attrs=None, + submit_text="Continue"): + """Generate HTML form markup that contains the values in this + message, to be HTTP POSTed as x-www-form-urlencoded UTF-8. + + @param action_url: The URL to which the form will be POSTed + @type action_url: str + + @param form_tag_attrs: Dictionary of attributes to be added to + the form tag. 'accept-charset' and 'enctype' have defaults + that can be overridden. If a value is supplied for + 'action' or 'method', it will be replaced. + @type form_tag_attrs: {unicode: unicode} + + @param submit_text: The text that will appear on the submit + button for this form. + @type submit_text: unicode + + @returns: A string containing (X)HTML markup for a form that + encodes the values in this Message object. + @rtype: str + """ + if ElementTree is None: + raise RuntimeError('This function requires ElementTree.') + + assert action_url is not None + + form = ElementTree.Element('form') + + if form_tag_attrs: + for name, attr in form_tag_attrs.items(): + form.attrib[name] = attr + + form.attrib['action'] = oidutil.toUnicode(action_url) + form.attrib['method'] = 'post' + form.attrib['accept-charset'] = 'UTF-8' + form.attrib['enctype'] = 'application/x-www-form-urlencoded' + + for name, value in self.toPostArgs().items(): + attrs = { + 'type': 'hidden', + 'name': oidutil.toUnicode(name), + 'value': oidutil.toUnicode(value) + } + form.append(ElementTree.Element('input', attrs)) + + submit = ElementTree.Element( + 'input', + {'type': 'submit', + 'value': oidutil.toUnicode(submit_text)}) + form.append(submit) + + return str(ElementTree.tostring(form, encoding='utf-8'), + encoding="utf-8") + + def toURL(self, base_url): + """Generate a GET URL with the parameters in this message + attached as query parameters.""" + return oidutil.appendArgs(base_url, self.toPostArgs()) + + def toKVForm(self): + """Generate a KVForm string that contains the parameters in + this message. This will fail if the message contains arguments + outside of the 'openid.' prefix. + """ + return kvform.dictToKV(self.toArgs()) + + def toURLEncoded(self): + """Generate an x-www-urlencoded string""" + args = sorted(self.toPostArgs().items()) + return urllib.parse.urlencode(args) + + def _fixNS(self, namespace): + """Convert an input value into the internally used values of + this object + + @param namespace: The string or constant to convert + @type namespace: str or unicode or BARE_NS or OPENID_NS + """ + if isinstance(namespace, bytes): + namespace = str(namespace, encoding="utf-8") + + if namespace == OPENID_NS: + if self._openid_ns_uri is None: + raise UndefinedOpenIDNamespace('OpenID namespace not set') + else: + namespace = self._openid_ns_uri + + if namespace != BARE_NS and not isinstance(namespace, str): + raise TypeError( + "Namespace must be BARE_NS, OPENID_NS or a string. got %r" % + (namespace, )) + + if namespace != BARE_NS and ':' not in namespace: + fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r' + warnings.warn(fmt % (namespace, ), DeprecationWarning) + + if namespace == 'sreg': + fmt = 'Using %r instead of "sreg" as namespace' + warnings.warn( + fmt % (SREG_URI, ), + DeprecationWarning, ) + return SREG_URI + + return namespace + + def hasKey(self, namespace, ns_key): + namespace = self._fixNS(namespace) + return (namespace, ns_key) in self.args + + def getKey(self, namespace, ns_key): + """Get the key for a particular namespaced argument""" + namespace = self._fixNS(namespace) + if namespace == BARE_NS: + return ns_key + + ns_alias = self.namespaces.getAlias(namespace) + + # No alias is defined, so no key can exist + if ns_alias is None: + return None + + if ns_alias == NULL_NAMESPACE: + tail = ns_key + else: + tail = '%s.%s' % (ns_alias, ns_key) + + return 'openid.' + tail + + def getArg(self, namespace, key, default=None): + """Get a value for a namespaced key. + + @param namespace: The namespace in the message for this key + @type namespace: str + + @param key: The key to get within this namespace + @type key: str + + @param default: The value to use if this key is absent from + this message. Using the special value + openid.message.no_default will result in this method + raising a KeyError instead of returning the default. + + @rtype: str or the type of default + @raises KeyError: if default is no_default + @raises UndefinedOpenIDNamespace: if the message has not yet + had an OpenID namespace set + """ + namespace = self._fixNS(namespace) + args_key = (namespace, key) + try: + return self.args[args_key] + except KeyError: + if default is no_default: + raise KeyError((namespace, key)) + else: + return default + + def getArgs(self, namespace): + """Get the arguments that are defined for this namespace URI + + @returns: mapping from namespaced keys to values + @returntype: dict of {str:bytes} + """ + namespace = self._fixNS(namespace) + args = [] + for ((pair_ns, ns_key), value) in self.args.items(): + if pair_ns == namespace: + if isinstance(ns_key, bytes): + k = str(ns_key, encoding="utf-8") + else: + k = ns_key + if isinstance(value, bytes): + v = str(value, encoding="utf-8") + else: + v = value + args.append((k, v)) + return dict(args) + + def updateArgs(self, namespace, updates): + """Set multiple key/value pairs in one call + + @param updates: The values to set + @type updates: {unicode:unicode} + """ + namespace = self._fixNS(namespace) + for k, v in updates.items(): + self.setArg(namespace, k, v) + + def setArg(self, namespace, key, value): + """Set a single argument in this namespace""" + assert key is not None + assert value is not None + namespace = self._fixNS(namespace) + # try to ensure that internally it's consistent, at least: str -> str + if isinstance(value, bytes): + value = str(value, encoding="utf-8") + self.args[(namespace, key)] = value + if not (namespace is BARE_NS): + self.namespaces.add(namespace) + + def delArg(self, namespace, key): + namespace = self._fixNS(namespace) + del self.args[(namespace, key)] + + def __repr__(self): + return "<%s.%s %r>" % (self.__class__.__module__, + self.__class__.__name__, self.args) + + def __eq__(self, other): + return self.args == other.args + + def __ne__(self, other): + return not (self == other) + + def getAliasedArg(self, aliased_key, default=None): + if aliased_key == 'ns': + return self.getOpenIDNamespace() + + if aliased_key.startswith('ns.'): + uri = self.namespaces.getNamespaceURI(aliased_key[3:]) + if uri is None: + if default == no_default: + raise KeyError + else: + return default + else: + return uri + + try: + alias, key = aliased_key.split('.', 1) + except ValueError: + # need more than x values to unpack + ns = None + else: + ns = self.namespaces.getNamespaceURI(alias) + + if ns is None: + key = aliased_key + ns = self.getOpenIDNamespace() + + return self.getArg(ns, key, default) + + +class NamespaceMap(object): + """Maintains a bijective map between namespace uris and aliases. + """ + + def __init__(self): + self.alias_to_namespace = {} + self.namespace_to_alias = {} + self.implicit_namespaces = [] + + def getAlias(self, namespace_uri): + return self.namespace_to_alias.get(namespace_uri) + + def getNamespaceURI(self, alias): + return self.alias_to_namespace.get(alias) + + def iterNamespaceURIs(self): + """Return an iterator over the namespace URIs""" + return iter(self.namespace_to_alias) + + def iterAliases(self): + """Return an iterator over the aliases""" + return iter(self.alias_to_namespace) + + def items(self): + """Iterate over the mapping + + @returns: iterator of (namespace_uri, alias) + """ + return self.namespace_to_alias.items() + + def addAlias(self, namespace_uri, desired_alias, implicit=False): + """Add an alias from this namespace URI to the desired alias + """ + if isinstance(namespace_uri, bytes): + namespace_uri = str(namespace_uri, encoding="utf-8") + # Check that desired_alias is not an openid protocol field as + # per the spec. + assert desired_alias not in OPENID_PROTOCOL_FIELDS, \ + "%r is not an allowed namespace alias" % (desired_alias,) + + # Check that desired_alias does not contain a period as per + # the spec. + if isinstance(desired_alias, str): + assert '.' not in desired_alias, \ + "%r must not contain a dot" % (desired_alias,) + + # Check that there is not a namespace already defined for + # the desired alias + current_namespace_uri = self.alias_to_namespace.get(desired_alias) + if (current_namespace_uri is not None and + current_namespace_uri != namespace_uri): + + fmt = ('Cannot map %r to alias %r. ' + '%r is already mapped to alias %r') + + msg = fmt % (namespace_uri, desired_alias, current_namespace_uri, + desired_alias) + raise KeyError(msg) + + # Check that there is not already a (different) alias for + # this namespace URI + alias = self.namespace_to_alias.get(namespace_uri) + if alias is not None and alias != desired_alias: + fmt = ('Cannot map %r to alias %r. ' + 'It is already mapped to alias %r') + raise KeyError(fmt % (namespace_uri, desired_alias, alias)) + + assert (desired_alias == NULL_NAMESPACE or + type(desired_alias) in [str, str]), repr(desired_alias) + assert namespace_uri not in self.implicit_namespaces + self.alias_to_namespace[desired_alias] = namespace_uri + self.namespace_to_alias[namespace_uri] = desired_alias + if implicit: + self.implicit_namespaces.append(namespace_uri) + return desired_alias + + def add(self, namespace_uri): + """Add this namespace URI to the mapping, without caring what + alias it ends up with""" + # See if this namespace is already mapped to an alias + alias = self.namespace_to_alias.get(namespace_uri) + if alias is not None: + return alias + + # Fall back to generating a numerical alias + i = 0 + while True: + alias = 'ext' + str(i) + try: + self.addAlias(namespace_uri, alias) + except KeyError: + i += 1 + else: + return alias + + assert False, "Not reached" + + def isDefined(self, namespace_uri): + return namespace_uri in self.namespace_to_alias + + def __contains__(self, namespace_uri): + return self.isDefined(namespace_uri) + + def isImplicit(self, namespace_uri): + return namespace_uri in self.implicit_namespaces diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/oidutil.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/oidutil.py new file mode 100644 index 0000000000000000000000000000000000000000..26f8960353bbddbd0403cc00807ac2360e23c65e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/oidutil.py @@ -0,0 +1,235 @@ +"""This module contains general utility code that is used throughout +the library. +""" + +__all__ = [ + 'log', 'appendArgs', 'toBase64', 'fromBase64', 'autoSubmitHTML', + 'toUnicode' +] + +import binascii +import logging + +# import urllib.parse as urlparse +from urllib.parse import urlencode + +logger = logging.getLogger(__name__) + +xxe_safe_elementtree_modules = [ + 'defusedxml.cElementTree', + 'defusedxml.ElementTree', +] + +elementtree_modules = [ + 'xml.etree.cElementTree', + 'xml.etree.ElementTree', + 'cElementTree', + 'elementtree.ElementTree', +] + + +def toUnicode(value): + """Returns the given argument as a unicode object. + + @param value: A UTF-8 encoded string or a unicode (coercable) object + @type message: str or unicode + + @returns: Unicode object representing the input value. + """ + if isinstance(value, bytes): + return value.decode('utf-8') + return str(value) + + +def autoSubmitHTML(form, title='OpenID transaction in progress'): + if isinstance(form, bytes): + form = str(form, encoding="utf-8") + if isinstance(title, bytes): + title = str(title, encoding="utf-8") + html = """ +<html> +<head> + <title>%s</title> +</head> +<body onload="document.forms[0].submit();"> +%s +<script> +var elements = document.forms[0].elements; +for (var i = 0; i < elements.length; i++) { + elements[i].style.display = "none"; +} +</script> +</body> +</html> +""" % (title, form) + return html + + +def importSafeElementTree(module_names=None): + """Find a working ElementTree implementation that is not vulnerable + to XXE, using `defusedxml`. + + >>> XXESafeElementTree = importSafeElementTree() + + @param module_names: The names of modules to try to use as + a safe ElementTree. Defaults to C{L{xxe_safe_elementtree_modules}} + + @returns: An ElementTree module that is not vulnerable to XXE. + """ + if module_names is None: + module_names = xxe_safe_elementtree_modules + try: + return importElementTree(module_names) + except ImportError: + raise ImportError('Unable to find a ElementTree module ' + 'that is not vulnerable to XXE. ' + 'Tried importing %r' % (module_names, )) + + +def importElementTree(module_names=None): + """Find a working ElementTree implementation, trying the standard + places that such a thing might show up. + + >>> ElementTree = importElementTree() + + @param module_names: The names of modules to try to use as + ElementTree. Defaults to C{L{elementtree_modules}} + + @returns: An ElementTree module + """ + if module_names is None: + module_names = elementtree_modules + + for mod_name in module_names: + try: + ElementTree = __import__(mod_name, None, None, ['unused']) + except ImportError: + pass + else: + # Make sure it can actually parse XML + try: + ElementTree.XML('<unused/>') + except (SystemExit, MemoryError, AssertionError): + raise + except: + logger.exception( + 'Not using ElementTree library %r because it failed to ' + 'parse a trivial document: %s' % mod_name) + else: + return ElementTree + else: + raise ImportError('No ElementTree library found. ' + 'You may need to install one. ' + 'Tried importing %r' % (module_names, )) + + +def log(message, level=0): + """Handle a log message from the OpenID library. + + This is a legacy function which redirects to logger.error. + The logging module should be used instead of this + + @param message: A string containing a debugging message from the + OpenID library + @type message: str + + @param level: The severity of the log message. This parameter is + currently unused, but in the future, the library may indicate + more important information with a higher level value. + @type level: int or None + + @returns: Nothing. + """ + + logger.error("This is a legacy log message, please use the " + "logging module. Message: %s", message) + + +def appendArgs(url, args): + """Append query arguments to a HTTP(s) URL. If the URL already has + query arguemtns, these arguments will be added, and the existing + arguments will be preserved. Duplicate arguments will not be + detected or collapsed (both will appear in the output). + + @param url: The url to which the arguments will be appended + @type url: str + + @param args: The query arguments to add to the URL. If a + dictionary is passed, the items will be sorted before + appending them to the URL. If a sequence of pairs is passed, + the order of the sequence will be preserved. + @type args: A dictionary from string to string, or a sequence of + pairs of strings. + + @returns: The URL with the parameters added + @rtype: str + """ + if hasattr(args, 'items'): + args = sorted(args.items()) + else: + args = list(args) + + if not isinstance(url, str): + url = str(url, encoding="utf-8") + + if not args: + return url + + if '?' in url: + sep = '&' + else: + sep = '?' + + # Map unicode to UTF-8 if present. Do not make any assumptions + # about the encodings of plain bytes (str). + i = 0 + for k, v in args: + if not isinstance(k, bytes): + k = k.encode('utf-8') + + if not isinstance(v, bytes): + v = v.encode('utf-8') + + args[i] = (k, v) + i += 1 + + return '%s%s%s' % (url, sep, urlencode(args)) + + +def toBase64(s): + """Represent string / bytes s as base64, omitting newlines""" + if isinstance(s, str): + s = s.encode("utf-8") + return binascii.b2a_base64(s)[:-1] + + +def fromBase64(s): + if isinstance(s, str): + s = s.encode("utf-8") + try: + return binascii.a2b_base64(s) + except binascii.Error as why: + # Convert to a common exception type + raise ValueError(str(why)) + + +class Symbol(object): + """This class implements an object that compares equal to others + of the same type that have the same name. These are distict from + str or unicode objects. + """ + + def __init__(self, name): + self.name = name + + def __eq__(self, other): + return type(self) is type(other) and self.name == other.name + + def __ne__(self, other): + return not (self == other) + + def __hash__(self): + return hash((self.__class__, self.name)) + + def __repr__(self): + return '<Symbol %s>' % (self.name, ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c8fde25736a66e63bb5d32aedbd69ac86d3ba90e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__init__.py @@ -0,0 +1,6 @@ +""" +This package contains the portions of the library used only when +implementing an OpenID server. See L{openid.server.server}. +""" + +__all__ = ['server', 'trustroot'] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fefdf560197e7a74774b710d46d619193c9f6bce Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/server.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/server.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ba1a65bb826d8bf6c56ed555d58f2480946f036 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/server.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/trustroot.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/trustroot.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6586884842ce878adf3214a26b23f048d036640 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/__pycache__/trustroot.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/server.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/server.py new file mode 100644 index 0000000000000000000000000000000000000000..fa4fae22f2f0b9701e0f19b3ce93e95d10dcac9c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/server.py @@ -0,0 +1,1824 @@ +# -*- test-case-name: openid.test.test_server -*- +"""OpenID server protocol and logic. + +Overview +======== + + An OpenID server must perform three tasks: + + 1. Examine the incoming request to determine its nature and validity. + + 2. Make a decision about how to respond to this request. + + 3. Format the response according to the protocol. + + The first and last of these tasks may performed by + the L{decodeRequest<Server.decodeRequest>} and + L{encodeResponse<Server.encodeResponse>} methods of the + L{Server} object. Who gets to do the intermediate task -- deciding + how to respond to the request -- will depend on what type of request it + is. + + If it's a request to authenticate a user (a X{C{checkid_setup}} or + X{C{checkid_immediate}} request), you need to decide if you will assert + that this user may claim the identity in question. Exactly how you do + that is a matter of application policy, but it generally involves making + sure the user has an account with your system and is logged in, checking + to see if that identity is hers to claim, and verifying with the user that + she does consent to releasing that information to the party making the + request. + + Examine the properties of the L{CheckIDRequest} object, optionally + check L{CheckIDRequest.returnToVerified}, and and when you've come + to a decision, form a response by calling L{CheckIDRequest.answer}. + + Other types of requests relate to establishing associations between client + and server and verifying the authenticity of previous communications. + L{Server} contains all the logic and data necessary to respond to + such requests; just pass the request to L{Server.handleRequest}. + + +OpenID Extensions +================= + + Do you want to provide other information for your users + in addition to authentication? Version 2.0 of the OpenID + protocol allows consumers to add extensions to their requests. + For example, with sites using the U{Simple Registration + Extension<http://openid.net/specs/openid-simple-registration-extension-1_0.html>}, + a user can agree to have their nickname and e-mail address sent to a + site when they sign up. + + Since extensions do not change the way OpenID authentication works, + code to handle extension requests may be completely separate from the + L{OpenIDRequest} class here. But you'll likely want data sent back by + your extension to be signed. L{OpenIDResponse} provides methods with + which you can add data to it which can be signed with the other data in + the OpenID signature. + + For example:: + + # when request is a checkid_* request + response = request.answer(True) + # this will a signed 'openid.sreg.timezone' parameter to the response + # as well as a namespace declaration for the openid.sreg namespace + response.fields.setArg('http://openid.net/sreg/1.0', 'timezone', 'America/Los_Angeles') + + There are helper modules for a number of extensions, including + L{Attribute Exchange<openid.extensions.ax>}, + L{PAPE<openid.extensions.pape>}, and + L{Simple Registration<openid.extensions.sreg>} in the L{openid.extensions} + package. + +Stores +====== + + The OpenID server needs to maintain state between requests in order + to function. Its mechanism for doing this is called a store. The + store interface is defined in C{L{openid.store.interface.OpenIDStore}}. + Additionally, several concrete store implementations are provided, so that + most sites won't need to implement a custom store. For a store backed + by flat files on disk, see C{L{openid.store.filestore.FileOpenIDStore}}. + For stores based on MySQL or SQLite, see the C{L{openid.store.sqlstore}} + module. + + +Upgrading +========= + +From 1.0 to 1.1 +--------------- + + The keys by which a server looks up associations in its store have changed + in version 1.2 of this library. If your store has entries created from + version 1.0 code, you should empty it. + +From 1.1 to 2.0 +--------------- + + One of the additions to the OpenID protocol was a specified nonce + format for one-way nonces. As a result, the nonce table in the store + has changed. You'll need to run contrib/upgrade-store-1.1-to-2.0 to + upgrade your store, or you'll encounter errors about the wrong number + of columns in the oid_nonces table. + + If you've written your own custom store or code that interacts + directly with it, you'll need to review the change notes in + L{openid.store.interface}. + +@group Requests: OpenIDRequest, AssociateRequest, CheckIDRequest, + CheckAuthRequest + +@group Responses: OpenIDResponse + +@group HTTP Codes: HTTP_OK, HTTP_REDIRECT, HTTP_ERROR + +@group Response Encodings: ENCODE_KVFORM, ENCODE_HTML_FORM, ENCODE_URL +""" + +import time +import warnings +import logging +from copy import deepcopy + +from openid import cryptutil +from openid import oidutil +from openid import kvform +from openid.dh import DiffieHellman +from openid.store.nonce import mkNonce +from openid.server.trustroot import TrustRoot, verifyReturnTo +from openid.association import Association, default_negotiator, getSecretSize +from openid.message import Message, InvalidOpenIDNamespace, \ + OPENID_NS, OPENID2_NS, IDENTIFIER_SELECT, OPENID1_URL_LIMIT +from openid.urinorm import urinorm + +logger = logging.getLogger(__name__) + +HTTP_OK = 200 +HTTP_REDIRECT = 302 +HTTP_ERROR = 400 + +BROWSER_REQUEST_MODES = ['checkid_setup', 'checkid_immediate'] + +ENCODE_KVFORM = ('kvform', ) +ENCODE_URL = ('URL/redirect', ) +ENCODE_HTML_FORM = ('HTML form', ) + +UNUSED = None + + +class OpenIDRequest(object): + """I represent an incoming OpenID request. + + @cvar mode: the C{X{openid.mode}} of this request. + @type mode: str + """ + mode = None + + +class CheckAuthRequest(OpenIDRequest): + """A request to verify the validity of a previous response. + + @cvar mode: "X{C{check_authentication}}" + @type mode: str + + @ivar assoc_handle: The X{association handle} the response was signed with. + @type assoc_handle: str + @ivar signed: The message with the signature which wants checking. + @type signed: L{Message} + + @ivar invalidate_handle: An X{association handle} the client is asking + about the validity of. Optional, may be C{None}. + @type invalidate_handle: str + + @see: U{OpenID Specs, Mode: check_authentication + <http://openid.net/specs.bml#mode-check_authentication>} + """ + mode = "check_authentication" + + required_fields = ["identity", "return_to", "response_nonce"] + + def __init__(self, assoc_handle, signed, invalidate_handle=None): + """Construct me. + + These parameters are assigned directly as class attributes, see + my L{class documentation<CheckAuthRequest>} for their descriptions. + + @type assoc_handle: str + @type signed: L{Message} + @type invalidate_handle: str + """ + self.assoc_handle = assoc_handle + self.signed = signed + self.invalidate_handle = invalidate_handle + self.namespace = OPENID2_NS + + @classmethod + def fromMessage(klass, message, op_endpoint=UNUSED): + """Construct me from an OpenID Message. + + @param message: An OpenID check_authentication Message + @type message: L{openid.message.Message} + + @returntype: L{CheckAuthRequest} + """ + self = klass.__new__(klass) + self.message = message + self.namespace = message.getOpenIDNamespace() + self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle') + self.sig = message.getArg(OPENID_NS, 'sig') + + if (self.assoc_handle is None or self.sig is None): + fmt = "%s request missing required parameter from message %s" + raise ProtocolError(message, text=fmt % (self.mode, message)) + + self.invalidate_handle = message.getArg(OPENID_NS, 'invalidate_handle') + + self.signed = message.copy() + # openid.mode is currently check_authentication because + # that's the mode of this request. But the signature + # was made on something with a different openid.mode. + # http://article.gmane.org/gmane.comp.web.openid.general/537 + if self.signed.hasKey(OPENID_NS, "mode"): + self.signed.setArg(OPENID_NS, "mode", "id_res") + + return self + + def answer(self, signatory): + """Respond to this request. + + Given a L{Signatory}, I can check the validity of the signature and + the X{C{invalidate_handle}}. + + @param signatory: The L{Signatory} to use to check the signature. + @type signatory: L{Signatory} + + @returns: A response with an X{C{is_valid}} (and, if + appropriate X{C{invalidate_handle}}) field. + @returntype: L{OpenIDResponse} + """ + is_valid = signatory.verify(self.assoc_handle, self.signed) + # Now invalidate that assoc_handle so it this checkAuth message cannot + # be replayed. + signatory.invalidate(self.assoc_handle, dumb=True) + response = OpenIDResponse(self) + valid_str = (is_valid and "true") or "false" + response.fields.setArg(OPENID_NS, 'is_valid', valid_str) + + if self.invalidate_handle: + assoc = signatory.getAssociation( + self.invalidate_handle, dumb=False) + if not assoc: + response.fields.setArg(OPENID_NS, 'invalidate_handle', + self.invalidate_handle) + return response + + def __str__(self): + if self.invalidate_handle: + ih = " invalidate? %r" % (self.invalidate_handle, ) + else: + ih = "" + s = "<%s handle: %r sig: %r: signed: %r%s>" % ( + self.__class__.__name__, self.assoc_handle, self.sig, self.signed, + ih) + return s + + +class PlainTextServerSession(object): + """An object that knows how to handle association requests with no + session type. + + @cvar session_type: The session_type for this association + session. There is no type defined for plain-text in the OpenID + specification, so we use 'no-encryption'. + @type session_type: str + + @see: U{OpenID Specs, Mode: associate + <http://openid.net/specs.bml#mode-associate>} + @see: AssociateRequest + """ + session_type = 'no-encryption' + allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256'] + + def fromMessage(cls, unused_request): + return cls() + + fromMessage = classmethod(fromMessage) + + def answer(self, secret): + return {'mac_key': oidutil.toBase64(secret)} + + +class DiffieHellmanSHA1ServerSession(object): + """An object that knows how to handle association requests with the + Diffie-Hellman session type. + + @cvar session_type: The session_type for this association + session. + @type session_type: str + + @ivar dh: The Diffie-Hellman algorithm values for this request + @type dh: DiffieHellman + + @ivar consumer_pubkey: The public key sent by the consumer in the + associate request + @type consumer_pubkey: long + + @see: U{OpenID Specs, Mode: associate + <http://openid.net/specs.bml#mode-associate>} + @see: AssociateRequest + """ + session_type = 'DH-SHA1' + hash_func = staticmethod(cryptutil.sha1) + allowed_assoc_types = ['HMAC-SHA1'] + + def __init__(self, dh, consumer_pubkey): + self.dh = dh + self.consumer_pubkey = consumer_pubkey + + def fromMessage(cls, message): + """ + @param message: The associate request message + @type message: openid.message.Message + + @returntype: L{DiffieHellmanSHA1ServerSession} + + @raises ProtocolError: When parameters required to establish the + session are missing. + """ + dh_modulus = message.getArg(OPENID_NS, 'dh_modulus') + dh_gen = message.getArg(OPENID_NS, 'dh_gen') + if (dh_modulus is None and dh_gen is not None or dh_gen is None and + dh_modulus is not None): + + if dh_modulus is None: + missing = 'modulus' + else: + missing = 'generator' + + raise ProtocolError( + message, 'If non-default modulus or generator is ' + 'supplied, both must be supplied. Missing %s' % (missing, )) + + if dh_modulus or dh_gen: + dh_modulus = cryptutil.base64ToLong(dh_modulus) + dh_gen = cryptutil.base64ToLong(dh_gen) + dh = DiffieHellman(dh_modulus, dh_gen) + else: + dh = DiffieHellman.fromDefaults() + + consumer_pubkey = message.getArg(OPENID_NS, 'dh_consumer_public') + if consumer_pubkey is None: + raise ProtocolError(message, "Public key for DH-SHA1 session " + "not found in message %s" % (message, )) + + consumer_pubkey = cryptutil.base64ToLong(consumer_pubkey) + + return cls(dh, consumer_pubkey) + + fromMessage = classmethod(fromMessage) + + def answer(self, secret): + mac_key = self.dh.xorSecret(self.consumer_pubkey, secret, + self.hash_func) + return { + 'dh_server_public': cryptutil.longToBase64(self.dh.public), + 'enc_mac_key': oidutil.toBase64(mac_key), + } + + +class DiffieHellmanSHA256ServerSession(DiffieHellmanSHA1ServerSession): + session_type = 'DH-SHA256' + hash_func = staticmethod(cryptutil.sha256) + allowed_assoc_types = ['HMAC-SHA256'] + + +class AssociateRequest(OpenIDRequest): + """A request to establish an X{association}. + + @cvar mode: "X{C{check_authentication}}" + @type mode: str + + @ivar assoc_type: The type of association. The protocol currently only + defines one value for this, "X{C{HMAC-SHA1}}". + @type assoc_type: str + + @ivar session: An object that knows how to handle association + requests of a certain type. + + @see: U{OpenID Specs, Mode: associate + <http://openid.net/specs.bml#mode-associate>} + """ + + mode = "associate" + + session_classes = { + 'no-encryption': PlainTextServerSession, + 'DH-SHA1': DiffieHellmanSHA1ServerSession, + 'DH-SHA256': DiffieHellmanSHA256ServerSession, + } + + def __init__(self, session, assoc_type): + """Construct me. + + The session is assigned directly as a class attribute. See my + L{class documentation<AssociateRequest>} for its description. + """ + super(AssociateRequest, self).__init__() + self.session = session + self.assoc_type = assoc_type + self.namespace = OPENID2_NS + + def fromMessage(klass, message, op_endpoint=UNUSED): + """Construct me from an OpenID Message. + + @param message: The OpenID associate request + @type message: openid.message.Message + + @returntype: L{AssociateRequest} + """ + if message.isOpenID1(): + session_type = message.getArg(OPENID_NS, 'session_type') + if session_type == 'no-encryption': + logger.warning( + 'Received OpenID 1 request with a no-encryption ' + 'assocaition session type. Continuing anyway.') + elif not session_type: + session_type = 'no-encryption' + else: + session_type = message.getArg(OPENID2_NS, 'session_type') + if session_type is None: + raise ProtocolError( + message, text="session_type missing from request") + + try: + session_class = klass.session_classes[session_type] + except KeyError: + raise ProtocolError(message, + "Unknown session type %r" % (session_type, )) + + try: + session = session_class.fromMessage(message) + except ValueError as why: + raise ProtocolError(message, 'Error parsing %s session: %s' % + (session_class.session_type, why)) + + assoc_type = message.getArg(OPENID_NS, 'assoc_type', 'HMAC-SHA1') + if assoc_type not in session.allowed_assoc_types: + fmt = 'Session type %s does not support association type %s' + raise ProtocolError(message, fmt % (session_type, assoc_type)) + + self = klass(session, assoc_type) + self.message = message + self.namespace = message.getOpenIDNamespace() + return self + + fromMessage = classmethod(fromMessage) + + def answer(self, assoc): + """Respond to this request with an X{association}. + + @param assoc: The association to send back. + @type assoc: L{openid.association.Association} + + @returns: A response with the association information, encrypted + to the consumer's X{public key} if appropriate. + @returntype: L{OpenIDResponse} + """ + response = OpenIDResponse(self) + response.fields.updateArgs(OPENID_NS, { + 'expires_in': str(assoc.expiresIn), + 'assoc_type': self.assoc_type, + 'assoc_handle': assoc.handle, + }) + response.fields.updateArgs(OPENID_NS, + self.session.answer(assoc.secret)) + + if not (self.session.session_type == 'no-encryption' and + self.message.isOpenID1()): + # The session type "no-encryption" did not have a name + # in OpenID v1, it was just omitted. + response.fields.setArg(OPENID_NS, 'session_type', + self.session.session_type) + + return response + + def answerUnsupported(self, + message, + preferred_association_type=None, + preferred_session_type=None): + """Respond to this request indicating that the association + type or association session type is not supported.""" + if self.message.isOpenID1(): + raise ProtocolError(self.message) + + response = OpenIDResponse(self) + response.fields.setArg(OPENID_NS, 'error_code', 'unsupported-type') + response.fields.setArg(OPENID_NS, 'error', message) + + if preferred_association_type: + response.fields.setArg(OPENID_NS, 'assoc_type', + preferred_association_type) + + if preferred_session_type: + response.fields.setArg(OPENID_NS, 'session_type', + preferred_session_type) + + return response + + +class CheckIDRequest(OpenIDRequest): + """A request to confirm the identity of a user. + + This class handles requests for openid modes X{C{checkid_immediate}} + and X{C{checkid_setup}}. + + @cvar mode: "X{C{checkid_immediate}}" or "X{C{checkid_setup}}" + @type mode: str + + @ivar immediate: Is this an immediate-mode request? + @type immediate: bool + + @ivar identity: The OP-local identifier being checked. + @type identity: str + + @ivar claimed_id: The claimed identifier. Not present in OpenID 1.x + messages. + @type claimed_id: str + + @ivar trust_root: "Are you Frank?" asks the checkid request. "Who wants + to know?" C{trust_root}, that's who. This URL identifies the party + making the request, and the user will use that to make her decision + about what answer she trusts them to have. Referred to as "realm" in + OpenID 2.0. + @type trust_root: str + + @ivar return_to: The URL to send the user agent back to to reply to this + request. + @type return_to: str + + @ivar assoc_handle: Provided in smart mode requests, a handle for a + previously established association. C{None} for dumb mode requests. + @type assoc_handle: str + """ + + def __init__(self, + identity, + return_to, + trust_root=None, + immediate=False, + assoc_handle=None, + op_endpoint=None, + claimed_id=None): + """Construct me. + + These parameters are assigned directly as class attributes, see + my L{class documentation<CheckIDRequest>} for their descriptions. + + @raises MalformedReturnURL: When the C{return_to} URL is not a URL. + """ + self.assoc_handle = assoc_handle + self.identity = identity + self.claimed_id = claimed_id or identity + self.return_to = return_to + self.trust_root = trust_root or return_to + self.op_endpoint = op_endpoint + assert self.op_endpoint is not None + if immediate: + self.immediate = True + self.mode = "checkid_immediate" + else: + self.immediate = False + self.mode = "checkid_setup" + + if self.return_to is not None and \ + not TrustRoot.parse(self.return_to): + raise MalformedReturnURL(None, self.return_to) + if not self.trustRootValid(): + raise UntrustedReturnURL(None, self.return_to, self.trust_root) + self.message = None + + def _getNamespace(self): + warnings.warn( + 'The "namespace" attribute of CheckIDRequest objects ' + 'is deprecated. Use "message.getOpenIDNamespace()" ' + 'instead', + DeprecationWarning, + stacklevel=2) + return self.message.getOpenIDNamespace() + + namespace = property(_getNamespace) + + def fromMessage(klass, message, op_endpoint): + """Construct me from an OpenID message. + + @raises ProtocolError: When not all required parameters are present + in the message. + + @raises MalformedReturnURL: When the C{return_to} URL is not a URL. + + @raises UntrustedReturnURL: When the C{return_to} URL is outside + the C{trust_root}. + + @param message: An OpenID checkid_* request Message + @type message: openid.message.Message + + @param op_endpoint: The endpoint URL of the server that this + message was sent to. + @type op_endpoint: str + + @returntype: L{CheckIDRequest} + """ + self = klass.__new__(klass) + self.message = message + self.op_endpoint = op_endpoint + mode = message.getArg(OPENID_NS, 'mode') + if mode == "checkid_immediate": + self.immediate = True + self.mode = "checkid_immediate" + else: + self.immediate = False + self.mode = "checkid_setup" + + self.return_to = message.getArg(OPENID_NS, 'return_to') + if message.isOpenID1() and not self.return_to: + fmt = "Missing required field 'return_to' from %r" + raise ProtocolError(message, text=fmt % (message, )) + + self.identity = message.getArg(OPENID_NS, 'identity') + self.claimed_id = message.getArg(OPENID_NS, 'claimed_id') + if message.isOpenID1(): + if self.identity is None: + s = "OpenID 1 message did not contain openid.identity" + raise ProtocolError(message, text=s) + else: + if self.identity and not self.claimed_id: + s = ("OpenID 2.0 message contained openid.identity but not " + "claimed_id") + raise ProtocolError(message, text=s) + elif self.claimed_id and not self.identity: + s = ("OpenID 2.0 message contained openid.claimed_id but not " + "identity") + raise ProtocolError(message, text=s) + + # There's a case for making self.trust_root be a TrustRoot + # here. But if TrustRoot isn't currently part of the "public" API, + # I'm not sure it's worth doing. + + if message.isOpenID1(): + trust_root_param = 'trust_root' + else: + trust_root_param = 'realm' + + # Using 'or' here is slightly different than sending a default + # argument to getArg, as it will treat no value and an empty + # string as equivalent. + self.trust_root = (message.getArg(OPENID_NS, trust_root_param) or + self.return_to) + + if not message.isOpenID1(): + if self.return_to is self.trust_root is None: + raise ProtocolError( + message, + "openid.realm required when " + "openid.return_to absent") + + self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle') + + # Using TrustRoot.parse here is a bit misleading, as we're not + # parsing return_to as a trust root at all. However, valid URLs + # are valid trust roots, so we can use this to get an idea if it + # is a valid URL. Not all trust roots are valid return_to URLs, + # however (particularly ones with wildcards), so this is still a + # little sketchy. + if self.return_to is not None and \ + not TrustRoot.parse(self.return_to): + raise MalformedReturnURL(message, self.return_to) + + # I first thought that checking to see if the return_to is within + # the trust_root is premature here, a logic-not-decoding thing. But + # it was argued that this is really part of data validation. A + # request with an invalid trust_root/return_to is broken regardless of + # application, right? + if not self.trustRootValid(): + raise UntrustedReturnURL(message, self.return_to, self.trust_root) + + return self + + fromMessage = classmethod(fromMessage) + + def idSelect(self): + """Is the identifier to be selected by the IDP? + + @returntype: bool + """ + # So IDPs don't have to import the constant + return self.identity == IDENTIFIER_SELECT + + def trustRootValid(self): + """Is my return_to under my trust_root? + + @returntype: bool + """ + if not self.trust_root: + return True + tr = TrustRoot.parse(self.trust_root) + if tr is None: + raise MalformedTrustRoot(self.message, self.trust_root) + + if self.return_to is not None: + return tr.validateURL(self.return_to) + else: + return True + + def returnToVerified(self): + """Does the relying party publish the return_to URL for this + response under the realm? It is up to the provider to set a + policy for what kinds of realms should be allowed. This + return_to URL verification reduces vulnerability to data-theft + attacks based on open proxies, cross-site-scripting, or open + redirectors. + + This check should only be performed after making sure that the + return_to URL matches the realm. + + @see: L{trustRootValid} + + @raises openid.yadis.discover.DiscoveryFailure: if the realm + URL does not support Yadis discovery (and so does not + support the verification process). + + @raises openid.fetchers.HTTPFetchingError: if the realm URL + is not reachable. When this is the case, the RP may be hosted + on the user's intranet. + + @returntype: bool + + @returns: True if the realm publishes a document with the + return_to URL listed + + @since: 2.1.0 + """ + return verifyReturnTo(self.trust_root, self.return_to) + + def answer(self, allow, server_url=None, identity=None, claimed_id=None): + """Respond to this request. + + @param allow: Allow this user to claim this identity, and allow the + consumer to have this information? + @type allow: bool + + @param server_url: DEPRECATED. Passing C{op_endpoint} to the + L{Server} constructor makes this optional. + + When an OpenID 1.x immediate mode request does not succeed, + it gets back a URL where the request may be carried out + in a not-so-immediate fashion. Pass my URL in here (the + fully qualified address of this server's endpoint, i.e. + C{http://example.com/server}), and I will use it as a base for the + URL for a new request. + + Optional for requests where C{CheckIDRequest.immediate} is C{False} + or C{allow} is C{True}. + + @type server_url: str + + @param identity: The OP-local identifier to answer with. Only for use + when the relying party requested identifier selection. + @type identity: str or None + + @param claimed_id: The claimed identifier to answer with, for use + with identifier selection in the case where the claimed identifier + and the OP-local identifier differ, i.e. when the claimed_id uses + delegation. + + If C{identity} is provided but this is not, C{claimed_id} will + default to the value of C{identity}. When answering requests + that did not ask for identifier selection, the response + C{claimed_id} will default to that of the request. + + This parameter is new in OpenID 2.0. + @type claimed_id: str or None + + @returntype: L{OpenIDResponse} + + @change: Version 2.0 deprecates C{server_url} and adds C{claimed_id}. + + @raises NoReturnError: when I do not have a return_to. + """ + assert self.message is not None + + if not self.return_to: + raise NoReturnToError + + if not server_url: + if not self.message.isOpenID1() and not self.op_endpoint: + # In other words, that warning I raised in Server.__init__? + # You should pay attention to it now. + raise RuntimeError("%s should be constructed with op_endpoint " + "to respond to OpenID 2.0 messages." % + (self, )) + server_url = self.op_endpoint + + if allow: + mode = 'id_res' + elif self.message.isOpenID1(): + if self.immediate: + mode = 'id_res' + else: + mode = 'cancel' + else: + if self.immediate: + mode = 'setup_needed' + else: + mode = 'cancel' + + response = OpenIDResponse(self) + + if claimed_id and self.message.isOpenID1(): + namespace = self.message.getOpenIDNamespace() + raise VersionError("claimed_id is new in OpenID 2.0 and not " + "available for %s" % (namespace, )) + + if allow: + if self.identity == IDENTIFIER_SELECT: + if not identity: + raise ValueError( + "This request uses IdP-driven identifier selection." + "You must supply an identifier in the response.") + response_identity = identity + response_claimed_id = claimed_id or identity + + elif self.identity: + if identity and (self.identity != identity): + normalized_request_identity = urinorm(self.identity) + normalized_answer_identity = urinorm(identity) + + if (normalized_request_identity != + normalized_answer_identity): + raise ValueError( + "Request was for identity %r, cannot reply " + "with identity %r" % (self.identity, identity)) + + # The "identity" value in the response shall always be + # the same as that in the request, otherwise the RP is + # likely to not validate the response. + response_identity = self.identity + response_claimed_id = self.claimed_id + else: + if identity: + raise ValueError( + "This request specified no identity and you " + "supplied %r" % (identity, )) + response_identity = None + + if self.message.isOpenID1() and response_identity is None: + raise ValueError( + "Request was an OpenID 1 request, so response must " + "include an identifier.") + + response.fields.updateArgs(OPENID_NS, { + 'mode': mode, + 'return_to': self.return_to, + 'response_nonce': mkNonce(), + }) + + if server_url: + response.fields.setArg(OPENID_NS, 'op_endpoint', server_url) + + if response_identity is not None: + response.fields.setArg(OPENID_NS, 'identity', + response_identity) + if self.message.isOpenID2(): + response.fields.setArg(OPENID_NS, 'claimed_id', + response_claimed_id) + else: + response.fields.setArg(OPENID_NS, 'mode', mode) + if self.immediate: + if self.message.isOpenID1() and not server_url: + raise ValueError("setup_url is required for allow=False " + "in OpenID 1.x immediate mode.") + # Make a new request just like me, but with immediate=False. + setup_request = self.__class__( + self.identity, + self.return_to, + self.trust_root, + immediate=False, + assoc_handle=self.assoc_handle, + op_endpoint=self.op_endpoint, + claimed_id=self.claimed_id) + + # XXX: This API is weird. + setup_request.message = self.message + + setup_url = setup_request.encodeToURL(server_url) + response.fields.setArg(OPENID_NS, 'user_setup_url', setup_url) + + return response + + def encodeToURL(self, server_url): + """Encode this request as a URL to GET. + + @param server_url: URL of the OpenID server to make this request of. + @type server_url: str + + @returntype: str + + @raises NoReturnError: when I do not have a return_to. + """ + if not self.return_to: + raise NoReturnToError + + # Imported from the alternate reality where these classes are used + # in both the client and server code, so Requests are Encodable too. + # That's right, code imported from alternate realities all for the + # love of you, id_res/user_setup_url. + q = { + 'mode': self.mode, + 'identity': self.identity, + 'claimed_id': self.claimed_id, + 'return_to': self.return_to + } + if self.trust_root: + if self.message.isOpenID1(): + q['trust_root'] = self.trust_root + else: + q['realm'] = self.trust_root + if self.assoc_handle: + q['assoc_handle'] = self.assoc_handle + + response = Message(self.message.getOpenIDNamespace()) + response.updateArgs(OPENID_NS, q) + return response.toURL(server_url) + + def getCancelURL(self): + """Get the URL to cancel this request. + + Useful for creating a "Cancel" button on a web form so that operation + can be carried out directly without another trip through the server. + + (Except you probably want to make another trip through the server so + that it knows that the user did make a decision. Or you could simulate + this method by doing C{.answer(False).encodeToURL()}) + + @returntype: str + @returns: The return_to URL with openid.mode = cancel. + + @raises NoReturnError: when I do not have a return_to. + """ + if not self.return_to: + raise NoReturnToError + + if self.immediate: + raise ValueError("Cancel is not an appropriate response to " + "immediate mode requests.") + + response = Message(self.message.getOpenIDNamespace()) + response.setArg(OPENID_NS, 'mode', 'cancel') + return response.toURL(self.return_to) + + def __repr__(self): + return '<%s id:%r im:%s tr:%r ah:%r>' % ( + self.__class__.__name__, self.identity, self.immediate, + self.trust_root, self.assoc_handle) + + +class OpenIDResponse(object): + """I am a response to an OpenID request. + + @ivar request: The request I respond to. + @type request: L{OpenIDRequest} + + @ivar fields: My parameters as a dictionary with each key mapping to + one value. Keys are parameter names with no leading "C{openid.}". + e.g. "C{identity}" and "C{mac_key}", never "C{openid.identity}". + @type fields: L{openid.message.Message} + + @ivar signed: The names of the fields which should be signed. + @type signed: list of str + """ + + # Implementer's note: In a more symmetric client/server + # implementation, there would be more types of OpenIDResponse + # object and they would have validated attributes according to the + # type of response. But as it is, Response objects in a server are + # basically write-only, their only job is to go out over the wire, + # so this is just a loose wrapper around OpenIDResponse.fields. + + def __init__(self, request): + """Make a response to an L{OpenIDRequest}. + + @type request: L{OpenIDRequest} + """ + self.request = request + self.fields = Message(request.namespace) + + def __str__(self): + return "%s for %s: %s" % (self.__class__.__name__, + self.request.__class__.__name__, self.fields) + + def toFormMarkup(self, form_tag_attrs=None): + """Returns the form markup for this response. + + @param form_tag_attrs: Dictionary of attributes to be added to + the form tag. 'accept-charset' and 'enctype' have defaults + that can be overridden. If a value is supplied for + 'action' or 'method', it will be replaced. + + @returntype: str + + @since: 2.1.0 + """ + return self.fields.toFormMarkup( + self.request.return_to, form_tag_attrs=form_tag_attrs) + + def toHTML(self, form_tag_attrs=None): + """Returns an HTML document that auto-submits the form markup + for this response. + + @returntype: str + + @see: toFormMarkup + + @since: 2.1.? + """ + return oidutil.autoSubmitHTML(self.toFormMarkup(form_tag_attrs)) + + def renderAsForm(self): + """Returns True if this response's encoding is + ENCODE_HTML_FORM. Convenience method for server authors. + + @returntype: bool + + @since: 2.1.0 + """ + return self.whichEncoding() == ENCODE_HTML_FORM + + def needsSigning(self): + """Does this response require signing? + + @returntype: bool + """ + return self.fields.getArg(OPENID_NS, 'mode') == 'id_res' + + # implements IEncodable + def whichEncoding(self): + """How should I be encoded? + + @returns: one of ENCODE_URL, ENCODE_HTML_FORM, or ENCODE_KVFORM. + + @change: 2.1.0 added the ENCODE_HTML_FORM response. + """ + if self.request.mode in BROWSER_REQUEST_MODES: + if self.fields.getOpenIDNamespace() == OPENID2_NS and \ + len(self.encodeToURL()) > OPENID1_URL_LIMIT: + return ENCODE_HTML_FORM + else: + return ENCODE_URL + else: + return ENCODE_KVFORM + + def encodeToURL(self): + """Encode a response as a URL for the user agent to GET. + + You will generally use this URL with a HTTP redirect. + + @returns: A URL to direct the user agent back to. + @returntype: str + """ + return self.fields.toURL(self.request.return_to) + + def addExtension(self, extension_response): + """ + Add an extension response to this response message. + + @param extension_response: An object that implements the + extension interface for adding arguments to an OpenID + message. + @type extension_response: L{openid.extension} + + @returntype: None + """ + extension_response.toMessage(self.fields) + + def encodeToKVForm(self): + """Encode a response in key-value colon/newline format. + + This is a machine-readable format used to respond to messages which + came directly from the consumer and not through the user agent. + + @see: OpenID Specs, + U{Key-Value Colon/Newline format<http://openid.net/specs.bml#keyvalue>} + + @returntype: str + """ + return self.fields.toKVForm() + + +class WebResponse(object): + """I am a response to an OpenID request in terms a web server understands. + + I generally come from an L{Encoder}, either directly or from + L{Server.encodeResponse}. + + @ivar code: The HTTP code of this response. + @type code: int + + @ivar headers: Headers to include in this response. + @type headers: dict + + @ivar body: The body of this response. + @type body: str + """ + + def __init__(self, code=HTTP_OK, headers=None, body=b""): + """Construct me. + + These parameters are assigned directly as class attributes, see + my L{class documentation<WebResponse>} for their descriptions. + """ + self.code = code + if headers is not None: + self.headers = headers + else: + self.headers = {} + if isinstance(body, bytes): + body = str(body, encoding="utf-8") + self.body = body + + +class Signatory(object): + """I sign things. + + I also check signatures. + + All my state is encapsulated in an + L{OpenIDStore<openid.store.interface.OpenIDStore>}, which means + I'm not generally pickleable but I am easy to reconstruct. + + @cvar SECRET_LIFETIME: The number of seconds a secret remains valid. + @type SECRET_LIFETIME: int + """ + + SECRET_LIFETIME = 14 * 24 * 60 * 60 # 14 days, in seconds + + # keys have a bogus server URL in them because the filestore + # really does expect that key to be a URL. This seems a little + # silly for the server store, since I expect there to be only one + # server URL. + _normal_key = 'http://localhost/|normal' + _dumb_key = 'http://localhost/|dumb' + + def __init__(self, store): + """Create a new Signatory. + + @param store: The back-end where my associations are stored. + @type store: L{openid.store.interface.OpenIDStore} + """ + assert store is not None + self.store = store + + def verify(self, assoc_handle, message): + """Verify that the signature for some data is valid. + + @param assoc_handle: The handle of the association used to sign the + data. + @type assoc_handle: str + + @param message: The signed message to verify + @type message: openid.message.Message + + @returns: C{True} if the signature is valid, C{False} if not. + @returntype: bool + """ + assoc = self.getAssociation(assoc_handle, dumb=True) + if not assoc: + logger.error("failed to get assoc with handle %r to verify " + "message %r" % (assoc_handle, message)) + return False + + try: + valid = assoc.checkMessageSignature(message) + except ValueError as ex: + logger.exception("Error in verifying %s with %s: %s" % + (message, assoc, ex)) + return False + return valid + + def sign(self, response): + """Sign a response. + + I take a L{OpenIDResponse}, create a signature for everything + in its L{signed<OpenIDResponse.signed>} list, and return a new + copy of the response object with that signature included. + + @param response: A response to sign. + @type response: L{OpenIDResponse} + + @returns: A signed copy of the response. + @returntype: L{OpenIDResponse} + """ + signed_response = deepcopy(response) + assoc_handle = response.request.assoc_handle + if assoc_handle: + # normal mode + # disabling expiration check because even if the association + # is expired, we still need to know some properties of the + # association so that we may preserve those properties when + # creating the fallback association. + assoc = self.getAssociation( + assoc_handle, dumb=False, checkExpiration=False) + + if not assoc or assoc.expiresIn <= 0: + # fall back to dumb mode + signed_response.fields.setArg(OPENID_NS, 'invalidate_handle', + assoc_handle) + assoc_type = assoc and assoc.assoc_type or 'HMAC-SHA1' + if assoc and assoc.expiresIn <= 0: + # now do the clean-up that the disabled checkExpiration + # code didn't get to do. + self.invalidate(assoc_handle, dumb=False) + assoc = self.createAssociation( + dumb=True, assoc_type=assoc_type) + else: + # dumb mode. + assoc = self.createAssociation(dumb=True) + + try: + signed_response.fields = assoc.signMessage(signed_response.fields) + except kvform.KVFormError as err: + raise EncodingError(response, explanation=str(err)) + return signed_response + + def createAssociation(self, dumb=True, assoc_type='HMAC-SHA1'): + """Make a new association. + + @param dumb: Is this association for a dumb-mode transaction? + @type dumb: bool + + @param assoc_type: The type of association to create. Currently + there is only one type defined, C{HMAC-SHA1}. + @type assoc_type: str + + @returns: the new association. + @returntype: L{openid.association.Association} + """ + secret = cryptutil.getBytes(getSecretSize(assoc_type)) + uniq = oidutil.toBase64(cryptutil.getBytes(4)) + handle = '{%s}{%x}{%s}' % (assoc_type, int(time.time()), uniq) + + assoc = Association.fromExpiresIn(self.SECRET_LIFETIME, handle, secret, + assoc_type) + + if dumb: + key = self._dumb_key + else: + key = self._normal_key + self.store.storeAssociation(key, assoc) + return assoc + + def getAssociation(self, assoc_handle, dumb, checkExpiration=True): + """Get the association with the specified handle. + + @type assoc_handle: str + + @param dumb: Is this association used with dumb mode? + @type dumb: bool + + @returns: the association, or None if no valid association with that + handle was found. + @returntype: L{openid.association.Association} + """ + # Hmm. We've created an interface that deals almost entirely with + # assoc_handles. The only place outside the Signatory that uses this + # (and thus the only place that ever sees Association objects) is + # when creating a response to an association request, as it must have + # the association's secret. + + if assoc_handle is None: + raise ValueError("assoc_handle must not be None") + + if dumb: + key = self._dumb_key + else: + key = self._normal_key + assoc = self.store.getAssociation(key, assoc_handle) + if assoc is not None and assoc.expiresIn <= 0: + logger.info("requested %sdumb key %r is expired (by %s seconds)" % + ((not dumb) and 'not-' or '', assoc_handle, + assoc.expiresIn)) + if checkExpiration: + self.store.removeAssociation(key, assoc_handle) + assoc = None + return assoc + + def invalidate(self, assoc_handle, dumb): + """Invalidates the association with the given handle. + + @type assoc_handle: str + + @param dumb: Is this association used with dumb mode? + @type dumb: bool + """ + if dumb: + key = self._dumb_key + else: + key = self._normal_key + self.store.removeAssociation(key, assoc_handle) + + +class Encoder(object): + """I encode responses in to L{WebResponses<WebResponse>}. + + If you don't like L{WebResponses<WebResponse>}, you can do + your own handling of L{OpenIDResponses<OpenIDResponse>} with + L{OpenIDResponse.whichEncoding}, L{OpenIDResponse.encodeToURL}, and + L{OpenIDResponse.encodeToKVForm}. + """ + + responseFactory = WebResponse + + def encode(self, response): + """Encode a response to a L{WebResponse}. + + @raises EncodingError: When I can't figure out how to encode this + message. + """ + encode_as = response.whichEncoding() + if encode_as == ENCODE_KVFORM: + wr = self.responseFactory(body=response.encodeToKVForm()) + if isinstance(response, Exception): + wr.code = HTTP_ERROR + elif encode_as == ENCODE_URL: + location = response.encodeToURL() + wr = self.responseFactory( + code=HTTP_REDIRECT, headers={'location': location}) + elif encode_as == ENCODE_HTML_FORM: + wr = self.responseFactory(code=HTTP_OK, body=response.toHTML()) + else: + # Can't encode this to a protocol message. You should probably + # render it to HTML and show it to the user. + raise EncodingError(response) + return wr + + +class SigningEncoder(Encoder): + """I encode responses in to L{WebResponses<WebResponse>}, signing them when required. + """ + + def __init__(self, signatory): + """Create a L{SigningEncoder}. + + @param signatory: The L{Signatory} I will make signatures with. + @type signatory: L{Signatory} + """ + self.signatory = signatory + + def encode(self, response): + """Encode a response to a L{WebResponse}, signing it first if appropriate. + + @raises EncodingError: When I can't figure out how to encode this + message. + + @raises AlreadySigned: When this response is already signed. + + @returntype: L{WebResponse} + """ + # the isinstance is a bit of a kludge... it means there isn't really + # an adapter to make the interfaces quite match. + if (not isinstance(response, Exception)) and response.needsSigning(): + if not self.signatory: + raise ValueError("Must have a store to sign this request: %s" % + (response, ), response) + if response.fields.hasKey(OPENID_NS, 'sig'): + raise AlreadySigned(response) + response = self.signatory.sign(response) + return super(SigningEncoder, self).encode(response) + + +class Decoder(object): + """I decode an incoming web request in to a L{OpenIDRequest}. + """ + + _handlers = { + 'checkid_setup': CheckIDRequest.fromMessage, + 'checkid_immediate': CheckIDRequest.fromMessage, + 'check_authentication': CheckAuthRequest.fromMessage, + 'associate': AssociateRequest.fromMessage, + } + + def __init__(self, server): + """Construct a Decoder. + + @param server: The server which I am decoding requests for. + (Necessary because some replies reference their server.) + @type server: L{Server} + """ + self.server = server + + def decode(self, query): + """I transform query parameters into an L{OpenIDRequest}. + + If the query does not seem to be an OpenID request at all, I return + C{None}. + + @param query: The query parameters as a dictionary with each + key mapping to one value. + @type query: dict + + @raises ProtocolError: When the query does not seem to be a valid + OpenID request. + + @returntype: L{OpenIDRequest} + """ + if not query: + return None + + try: + message = Message.fromPostArgs(query) + except InvalidOpenIDNamespace as err: + # It's useful to have a Message attached to a ProtocolError, so we + # override the bad ns value to build a Message out of it. Kinda + # kludgy, since it's made of lies, but the parts that aren't lies + # are more useful than a 'None'. + query = query.copy() + query['openid.ns'] = OPENID2_NS + message = Message.fromPostArgs(query) + raise ProtocolError(message, str(err)) + + mode = message.getArg(OPENID_NS, 'mode') + if not mode: + fmt = "No mode value in message %s" + raise ProtocolError(message, text=fmt % (message, )) + + handler = self._handlers.get(mode, self.defaultDecoder) + return handler(message, self.server.op_endpoint) + + def defaultDecoder(self, message, server): + """Called to decode queries when no handler for that mode is found. + + @raises ProtocolError: This implementation always raises + L{ProtocolError}. + """ + mode = message.getArg(OPENID_NS, 'mode') + fmt = "Unrecognized OpenID mode %r" + raise ProtocolError(message, text=fmt % (mode, )) + + +class Server(object): + """I handle requests for an OpenID server. + + Some types of requests (those which are not C{checkid} requests) may be + handed to my L{handleRequest} method, and I will take care of it and + return a response. + + For your convenience, I also provide an interface to L{Decoder.decode} + and L{SigningEncoder.encode} through my methods L{decodeRequest} and + L{encodeResponse}. + + All my state is encapsulated in an + L{OpenIDStore<openid.store.interface.OpenIDStore>}, which means + I'm not generally pickleable but I am easy to reconstruct. + + Example:: + + oserver = Server(FileOpenIDStore(data_path), "http://example.com/op") + request = oserver.decodeRequest(query) + if request.mode in ['checkid_immediate', 'checkid_setup']: + if self.isAuthorized(request.identity, request.trust_root): + response = request.answer(True) + elif request.immediate: + response = request.answer(False) + else: + self.showDecidePage(request) + return + else: + response = oserver.handleRequest(request) + + webresponse = oserver.encode(response) + + @ivar signatory: I'm using this for associate requests and to sign things. + @type signatory: L{Signatory} + + @ivar decoder: I'm using this to decode things. + @type decoder: L{Decoder} + + @ivar encoder: I'm using this to encode things. + @type encoder: L{Encoder} + + @ivar op_endpoint: My URL. + @type op_endpoint: str + + @ivar negotiator: I use this to determine which kinds of + associations I can make and how. + @type negotiator: L{openid.association.SessionNegotiator} + """ + + def __init__(self, + store, + op_endpoint=None, + signatoryClass=Signatory, + encoderClass=SigningEncoder, + decoderClass=Decoder): + """A new L{Server}. + + @param store: The back-end where my associations are stored. + @type store: L{openid.store.interface.OpenIDStore} + + @param op_endpoint: My URL, the fully qualified address of this + server's endpoint, i.e. C{http://example.com/server} + @type op_endpoint: str + + @change: C{op_endpoint} is new in library version 2.0. It + currently defaults to C{None} for compatibility with + earlier versions of the library, but you must provide it + if you want to respond to any version 2 OpenID requests. + """ + self.store = store + self.signatory = signatoryClass(self.store) + self.encoder = encoderClass(self.signatory) + self.decoder = decoderClass(self) + self.negotiator = default_negotiator.copy() + + if not op_endpoint: + warnings.warn( + "%s.%s constructor requires op_endpoint parameter " + "for OpenID 2.0 servers" % + (self.__class__.__module__, self.__class__.__name__), + stacklevel=2) + self.op_endpoint = op_endpoint + + def handleRequest(self, request): + """Handle a request. + + Give me a request, I will give you a response. Unless it's a type + of request I cannot handle myself, in which case I will raise + C{NotImplementedError}. In that case, you can handle it yourself, + or add a method to me for handling that request type. + + @raises NotImplementedError: When I do not have a handler defined + for that type of request. + + @returntype: L{OpenIDResponse} + """ + handler = getattr(self, 'openid_' + request.mode, None) + if handler is not None: + return handler(request) + else: + raise NotImplementedError( + "%s has no handler for a request of mode %r." % + (self, request.mode)) + + def openid_check_authentication(self, request): + """Handle and respond to C{check_authentication} requests. + + @returntype: L{OpenIDResponse} + """ + return request.answer(self.signatory) + + def openid_associate(self, request): + """Handle and respond to C{associate} requests. + + @returntype: L{OpenIDResponse} + """ + # XXX: TESTME + assoc_type = request.assoc_type + session_type = request.session.session_type + if self.negotiator.isAllowed(assoc_type, session_type): + assoc = self.signatory.createAssociation( + dumb=False, assoc_type=assoc_type) + return request.answer(assoc) + else: + message = ('Association type %r is not supported with ' + 'session type %r' % (assoc_type, session_type)) + (preferred_assoc_type, preferred_session_type) = \ + self.negotiator.getAllowedType() + return request.answerUnsupported(message, preferred_assoc_type, + preferred_session_type) + + def decodeRequest(self, query): + """Transform query parameters into an L{OpenIDRequest}. + + If the query does not seem to be an OpenID request at all, I return + C{None}. + + @param query: The query parameters as a dictionary with each + key mapping to one value. + @type query: dict + + @raises ProtocolError: When the query does not seem to be a valid + OpenID request. + + @returntype: L{OpenIDRequest} + + @see: L{Decoder.decode} + """ + return self.decoder.decode(query) + + def encodeResponse(self, response): + """Encode a response to a L{WebResponse}, signing it first if appropriate. + + @raises EncodingError: When I can't figure out how to encode this + message. + + @raises AlreadySigned: When this response is already signed. + + @returntype: L{WebResponse} + + @see: L{SigningEncoder.encode} + """ + return self.encoder.encode(response) + + +class ProtocolError(Exception): + """A message did not conform to the OpenID protocol. + + @ivar message: The query that is failing to be a valid OpenID request. + @type message: openid.message.Message + """ + + def __init__(self, message, text=None, reference=None, contact=None): + """When an error occurs. + + @param message: The message that is failing to be a valid + OpenID request. + @type message: openid.message.Message + + @param text: A message about the encountered error. Set as C{args[0]}. + @type text: str + """ + self.openid_message = message + self.reference = reference + self.contact = contact + assert type(message) not in [str, str] + Exception.__init__(self, text) + + def getReturnTo(self): + """Get the return_to argument from the request, if any. + + @returntype: str + """ + if self.openid_message is None: + return None + else: + return self.openid_message.getArg(OPENID_NS, 'return_to') + + def hasReturnTo(self): + """Did this request have a return_to parameter? + + @returntype: bool + """ + return self.getReturnTo() is not None + + def toMessage(self): + """Generate a Message object for sending to the relying party, + after encoding. + """ + namespace = self.openid_message.getOpenIDNamespace() + reply = Message(namespace) + reply.setArg(OPENID_NS, 'mode', 'error') + reply.setArg(OPENID_NS, 'error', str(self)) + + if self.contact is not None: + reply.setArg(OPENID_NS, 'contact', str(self.contact)) + + if self.reference is not None: + reply.setArg(OPENID_NS, 'reference', str(self.reference)) + + return reply + + # implements IEncodable + + def encodeToURL(self): + return self.toMessage().toURL(self.getReturnTo()) + + def encodeToKVForm(self): + return self.toMessage().toKVForm() + + def toFormMarkup(self): + """Encode to HTML form markup for POST. + + @since: 2.1.0 + """ + return self.toMessage().toFormMarkup(self.getReturnTo()) + + def toHTML(self): + """Encode to a full HTML page, wrapping the form markup in a page + that will autosubmit the form. + + @since: 2.1.? + """ + return oidutil.autoSubmitHTML(self.toFormMarkup()) + + def whichEncoding(self): + """How should I be encoded? + + @returns: one of ENCODE_URL, ENCODE_KVFORM, or None. If None, + I cannot be encoded as a protocol message and should be + displayed to the user. + """ + if self.hasReturnTo(): + if self.openid_message.getOpenIDNamespace() == OPENID2_NS and \ + len(self.encodeToURL()) > OPENID1_URL_LIMIT: + return ENCODE_HTML_FORM + else: + return ENCODE_URL + + if self.openid_message is None: + return None + + mode = self.openid_message.getArg(OPENID_NS, 'mode') + if mode: + if mode not in BROWSER_REQUEST_MODES: + return ENCODE_KVFORM + + # According to the OpenID spec as of this writing, we are probably + # supposed to switch on request type here (GET versus POST) to figure + # out if we're supposed to print machine-readable or human-readable + # content at this point. GET/POST seems like a pretty lousy way of + # making the distinction though, as it's just as possible that the + # user agent could have mistakenly been directed to post to the + # server URL. + + # Basically, if your request was so broken that you didn't manage to + # include an openid.mode, I'm not going to worry too much about + # returning you something you can't parse. + return None + + +class VersionError(Exception): + """Raised when an operation was attempted that is not compatible with + the protocol version being used.""" + + +class NoReturnToError(Exception): + """Raised when a response to a request cannot be generated because + the request contains no return_to URL. + """ + pass + + +class EncodingError(Exception): + """Could not encode this as a protocol message. + + You should probably render it and show it to the user. + + @ivar response: The response that failed to encode. + @type response: L{OpenIDResponse} + """ + + def __init__(self, response, explanation=None): + Exception.__init__(self, response) + self.response = response + self.explanation = explanation + + def __str__(self): + if self.explanation: + s = '%s: %s' % (self.__class__.__name__, self.explanation) + else: + s = '%s for Response %s' % (self.__class__.__name__, self.response) + return s + + +class AlreadySigned(EncodingError): + """This response is already signed.""" + + +class UntrustedReturnURL(ProtocolError): + """A return_to is outside the trust_root.""" + + def __init__(self, message, return_to, trust_root): + ProtocolError.__init__(self, message) + self.return_to = return_to + self.trust_root = trust_root + + def __str__(self): + return "return_to %r not under trust_root %r" % (self.return_to, + self.trust_root) + + +class MalformedReturnURL(ProtocolError): + """The return_to URL doesn't look like a valid URL.""" + + def __init__(self, openid_message, return_to): + self.return_to = return_to + ProtocolError.__init__(self, openid_message) + + +class MalformedTrustRoot(ProtocolError): + """The trust root is not well-formed. + + @see: OpenID Specs, U{openid.trust_root<http://openid.net/specs.bml#mode-checkid_immediate>} + """ + pass + + +#class IEncodable: # Interface +# def encodeToURL(return_to): +# """Encode a response as a URL for redirection. +# +# @returns: A URL to direct the user agent back to. +# @returntype: str +# """ +# pass +# +# def encodeToKvform(): +# """Encode a response in key-value colon/newline format. +# +# This is a machine-readable format used to respond to messages which +# came directly from the consumer and not through the user agent. +# +# @see: OpenID Specs, +# U{Key-Value Colon/Newline format<http://openid.net/specs.bml#keyvalue>} +# +# @returntype: str +# """ +# pass +# +# def whichEncoding(): +# """How should I be encoded? +# +# @returns: one of ENCODE_URL, ENCODE_KVFORM, or None. If None, +# I cannot be encoded as a protocol message and should be +# displayed to the user. +# """ +# pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/server/trustroot.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/trustroot.py new file mode 100644 index 0000000000000000000000000000000000000000..9d0cb032f4eb8017b3d8f7096e486078e540f491 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/server/trustroot.py @@ -0,0 +1,456 @@ +# -*- test-case-name: openid.test.test_rpverify -*- +""" +This module contains the C{L{TrustRoot}} class, which helps handle +trust root checking. This module is used by the +C{L{openid.server.server}} module, but it is also available to server +implementers who wish to use it for additional trust root checking. + +It also implements relying party return_to URL verification, based on +the realm. +""" + +__all__ = [ + 'TrustRoot', + 'RP_RETURN_TO_URL_TYPE', + 'extractReturnToURLs', + 'returnToMatches', + 'verifyReturnTo', +] + +from openid import urinorm +from openid.yadis import services + +from urllib.parse import urlparse, urlunparse +import re +import logging + +logger = logging.getLogger(__name__) + +############################################ +_protocols = ['http', 'https'] +_top_level_domains = [ + 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', + 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', + 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', + 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', + 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', + 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', + 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', + 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', + 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', + 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', + 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', + 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', + 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', + 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', + 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', + 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', + 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', + 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', + 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', + 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', + 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', + 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', + 'xn--0zwm56d', 'xn--11b5bs3a9aj6g', 'xn--80akhbyknj4f', 'xn--9t4b11yi5a', + 'xn--deba0ad', 'xn--g6w251d', 'xn--hgbk6aj7f53bba', 'xn--hlcj6aya9esc7a', + 'xn--jxalpdlp', 'xn--kgbechtv', 'xn--zckzah', 'ye', 'yt', 'yu', 'za', 'zm', + 'zw' +] + +# Build from RFC3986, section 3.2.2. Used to reject hosts with invalid +# characters. +host_segment_re = re.compile( + r"(?:[-a-zA-Z0-9!$&'\(\)\*+,;=._~]|%[a-zA-Z0-9]{2})+$") + + +class RealmVerificationRedirected(Exception): + """Attempting to verify this realm resulted in a redirect. + + @since: 2.1.0 + """ + + def __init__(self, relying_party_url, rp_url_after_redirects): + self.relying_party_url = relying_party_url + self.rp_url_after_redirects = rp_url_after_redirects + + def __str__(self): + return ("Attempting to verify %r resulted in " + "redirect to %r" % (self.relying_party_url, + self.rp_url_after_redirects)) + + +def _parseURL(url): + try: + url = urinorm.urinorm(url) + except ValueError: + return None + proto, netloc, path, params, query, frag = urlparse(url) + if not path: + # Python <2.4 does not parse URLs with no path properly + if not query and '?' in netloc: + netloc, query = netloc.split('?', 1) + + path = '/' + + path = urlunparse(('', '', path, params, query, frag)) + + if ':' in netloc: + try: + host, port = netloc.split(':') + except ValueError: + return None + + if not re.match(r'\d+$', port): + return None + else: + host = netloc + port = '' + + host = host.lower() + if not host_segment_re.match(host): + return None + + return proto, host, port, path + + +class TrustRoot(object): + """ + This class represents an OpenID trust root. The C{L{parse}} + classmethod accepts a trust root string, producing a + C{L{TrustRoot}} object. The method OpenID server implementers + would be most likely to use is the C{L{isSane}} method, which + checks the trust root for given patterns that indicate that the + trust root is too broad or points to a local network resource. + + @sort: parse, isSane + """ + + def __init__(self, unparsed, proto, wildcard, host, port, path): + self.unparsed = unparsed + self.proto = proto + self.wildcard = wildcard + self.host = host + self.port = port + self.path = path + + def isSane(self): + """ + This method checks the to see if a trust root represents a + reasonable (sane) set of URLs. 'http://*.com/', for example + is not a reasonable pattern, as it cannot meaningfully specify + the site claiming it. This function attempts to find many + related examples, but it can only work via heuristics. + Negative responses from this method should be treated as + advisory, used only to alert the user to examine the trust + root carefully. + + + @return: Whether the trust root is sane + + @rtype: C{bool} + """ + + if self.host == 'localhost': + return True + + host_parts = self.host.split('.') + if self.wildcard: + assert host_parts[0] == '', host_parts + del host_parts[0] + + # If it's an absolute domain name, remove the empty string + # from the end. + if host_parts and not host_parts[-1]: + del host_parts[-1] + + if not host_parts: + return False + + # Do not allow adjacent dots + if '' in host_parts: + return False + + tld = host_parts[-1] + if tld not in _top_level_domains: + return False + + if len(host_parts) == 1: + return False + + if self.wildcard: + if len(tld) == 2 and len(host_parts[-2]) <= 3: + # It's a 2-letter tld with a short second to last segment + # so there needs to be more than two segments specified + # (e.g. *.co.uk is insane) + return len(host_parts) > 2 + + # Passed all tests for insanity. + return True + + def validateURL(self, url): + """ + Validates a URL against this trust root. + + + @param url: The URL to check + + @type url: C{str} + + + @return: Whether the given URL is within this trust root. + + @rtype: C{bool} + """ + + url_parts = _parseURL(url) + if url_parts is None: + return False + + proto, host, port, path = url_parts + + if proto != self.proto: + return False + + if port != self.port: + return False + + if '*' in host: + return False + + if not self.wildcard: + if host != self.host: + return False + elif ((not host.endswith(self.host)) and ('.' + host) != self.host): + return False + + if path != self.path: + path_len = len(self.path) + trust_prefix = self.path[:path_len] + url_prefix = path[:path_len] + + # must be equal up to the length of the path, at least + if trust_prefix != url_prefix: + return False + + # These characters must be on the boundary between the end + # of the trust root's path and the start of the URL's + # path. + if '?' in self.path: + allowed = '&' + else: + allowed = '?/' + + return (self.path[-1] in allowed or path[path_len] in allowed) + + return True + + def parse(cls, trust_root): + """ + This method creates a C{L{TrustRoot}} instance from the given + input, if possible. + + + @param trust_root: This is the trust root to parse into a + C{L{TrustRoot}} object. + + @type trust_root: C{str} + + + @return: A C{L{TrustRoot}} instance if trust_root parses as a + trust root, C{None} otherwise. + + @rtype: C{NoneType} or C{L{TrustRoot}} + """ + url_parts = _parseURL(trust_root) + if url_parts is None: + return None + + proto, host, port, path = url_parts + + # check for valid prototype + if proto not in _protocols: + return None + + # check for URI fragment + if path.find('#') != -1: + return None + + # extract wildcard if it is there + if host.find('*', 1) != -1: + # wildcard must be at start of domain: *.foo.com, not foo.*.com + return None + + if host.startswith('*'): + # Starts with star, so must have a dot after it (if a + # domain is specified) + if len(host) > 1 and host[1] != '.': + return None + + host = host[1:] + wilcard = True + else: + wilcard = False + + # we have a valid trust root + tr = cls(trust_root, proto, wilcard, host, port, path) + + return tr + + parse = classmethod(parse) + + def checkSanity(cls, trust_root_string): + """str -> bool + + is this a sane trust root? + """ + trust_root = cls.parse(trust_root_string) + if trust_root is None: + return False + else: + return trust_root.isSane() + + checkSanity = classmethod(checkSanity) + + def checkURL(cls, trust_root, url): + """quick func for validating a url against a trust root. See the + TrustRoot class if you need more control.""" + tr = cls.parse(trust_root) + return tr is not None and tr.validateURL(url) + + checkURL = classmethod(checkURL) + + def buildDiscoveryURL(self): + """Return a discovery URL for this realm. + + This function does not check to make sure that the realm is + valid. Its behaviour on invalid inputs is undefined. + + @rtype: str + + @returns: The URL upon which relying party discovery should be run + in order to verify the return_to URL + + @since: 2.1.0 + """ + if self.wildcard: + # Use "www." in place of the star + assert self.host.startswith('.'), self.host + www_domain = 'www' + self.host + return '%s://%s%s' % (self.proto, www_domain, self.path) + else: + return self.unparsed + + def __repr__(self): + return "TrustRoot(%r, %r, %r, %r, %r, %r)" % ( + self.unparsed, self.proto, self.wildcard, self.host, self.port, + self.path) + + def __str__(self): + return repr(self) + + +# The URI for relying party discovery, used in realm verification. +# +# XXX: This should probably live somewhere else (like in +# openid.consumer or openid.yadis somewhere) +RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to' + + +def _extractReturnURL(endpoint): + """If the endpoint is a relying party OpenID return_to endpoint, + return the endpoint URL. Otherwise, return None. + + This function is intended to be used as a filter for the Yadis + filtering interface. + + @see: C{L{openid.yadis.services}} + @see: C{L{openid.yadis.filters}} + + @param endpoint: An XRDS BasicServiceEndpoint, as returned by + performing Yadis dicovery. + + @returns: The endpoint URL or None if the endpoint is not a + relying party endpoint. + @rtype: str or NoneType + """ + if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]): + return endpoint.uri + else: + return None + + +def returnToMatches(allowed_return_to_urls, return_to): + """Is the return_to URL under one of the supplied allowed + return_to URLs? + + @since: 2.1.0 + """ + + for allowed_return_to in allowed_return_to_urls: + # A return_to pattern works the same as a realm, except that + # it's not allowed to use a wildcard. We'll model this by + # parsing it as a realm, and not trying to match it if it has + # a wildcard. + + return_realm = TrustRoot.parse(allowed_return_to) + if ( # Parses as a trust root + return_realm is not None and + + # Does not have a wildcard + not return_realm.wildcard and + + # Matches the return_to that we passed in with it + return_realm.validateURL(return_to)): + return True + + # No URL in the list matched + return False + + +def getAllowedReturnURLs(relying_party_url): + """Given a relying party discovery URL return a list of return_to URLs. + + @since: 2.1.0 + """ + (rp_url_after_redirects, return_to_urls) = services.getServiceEndpoints( + relying_party_url, _extractReturnURL) + + if rp_url_after_redirects != relying_party_url: + # Verification caused a redirect + raise RealmVerificationRedirected(relying_party_url, + rp_url_after_redirects) + + return return_to_urls + + +# _vrfy parameter is there to make testing easier +def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs): + """Verify that a return_to URL is valid for the given realm. + + This function builds a discovery URL, performs Yadis discovery on + it, makes sure that the URL does not redirect, parses out the + return_to URLs, and finally checks to see if the current return_to + URL matches the return_to. + + @raises DiscoveryFailure: When Yadis discovery fails + @returns: True if the return_to URL is valid for the realm + + @since: 2.1.0 + """ + realm = TrustRoot.parse(realm_str) + if realm is None: + # The realm does not parse as a URL pattern + return False + + try: + allowable_urls = _vrfy(realm.buildDiscoveryURL()) + except RealmVerificationRedirected as err: + logger.exception(str(err)) + return False + + if returnToMatches(allowable_urls, return_to): + return True + else: + logger.error("Failed to validate return_to %r for realm %r, was not " + "in %s" % (return_to, realm_str, allowable_urls)) + return False diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/sreg.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/sreg.py new file mode 100644 index 0000000000000000000000000000000000000000..d665a5d041c811fe35952161ff3282e27c32af88 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/sreg.py @@ -0,0 +1,7 @@ +"""moved to L{openid.extensions.sreg}""" + +import warnings +warnings.warn("openid.sreg has moved to openid.extensions.sreg", + DeprecationWarning) + +from openid.extensions.sreg import * diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..76509b51988bca323b0ee107ea5779a90d4a8b21 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__init__.py @@ -0,0 +1,8 @@ +""" +This package contains the modules related to this library's use of +persistent storage. + +@sort: interface, filestore, sqlstore, memstore +""" + +__all__ = ['interface', 'filestore', 'sqlstore', 'memstore', 'nonce'] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e27d9067be22c665f2105bb2ffefef73c98ff4c2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/filestore.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/filestore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f5e11bf85b7e6bf947fc048224f64ae02cfca35 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/filestore.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/interface.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/interface.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1cb1c71b71531a8099e94b6d4138fcb1dfe7ce85 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/interface.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/memstore.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/memstore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e48f54dd80378e82c182a72894fb033c6d43dab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/memstore.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/nonce.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/nonce.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb62053696e775d0a0e7bfd91599cbada1ebe062 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/nonce.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/sqlstore.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/sqlstore.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b7c983dee0b03a01adccb036422ff8240f3c2f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/__pycache__/sqlstore.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/filestore.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/filestore.py new file mode 100644 index 0000000000000000000000000000000000000000..f5f2954035d5efdab769b22edfb54187d81e8f3a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/filestore.py @@ -0,0 +1,399 @@ +""" +This module contains an C{L{OpenIDStore}} implementation backed by +flat files. +""" + +import string +import os +import os.path +import time +import logging + +from errno import EEXIST, ENOENT + +from tempfile import mkstemp + +from openid.association import Association +from openid.store.interface import OpenIDStore +from openid.store import nonce +from openid import cryptutil, oidutil + +logger = logging.getLogger(__name__) + +_filename_allowed = string.ascii_letters + string.digits + '.' +_isFilenameSafe = set(_filename_allowed).__contains__ + + +def _safe64(s): + h64 = oidutil.toBase64(cryptutil.sha1(s)) + # to be able to manipulate it, make it a bytearray + h64 = bytearray(h64) + h64 = h64.replace(b'+', b'_') + h64 = h64.replace(b'/', b'.') + h64 = h64.replace(b'=', b'') + return bytes(h64) + + +def _filenameEscape(s): + filename_chunks = [] + for c in s: + if _isFilenameSafe(c): + filename_chunks.append(c) + else: + filename_chunks.append('_%02X' % ord(c)) + return ''.join(filename_chunks) + + +def _removeIfPresent(filename): + """Attempt to remove a file, returning whether the file existed at + the time of the call. + + str -> bool + """ + try: + os.unlink(filename) + except OSError as why: + if why.errno == ENOENT: + # Someone beat us to it, but it's gone, so that's OK + return 0 + else: + raise + else: + # File was present + return 1 + + +def _ensureDir(dir_name): + """Create dir_name as a directory if it does not exist. If it + exists, make sure that it is, in fact, a directory. + + Can raise OSError + + str -> NoneType + """ + try: + os.makedirs(dir_name) + except OSError as why: + if why.errno != EEXIST or not os.path.isdir(dir_name): + raise + + +class FileOpenIDStore(OpenIDStore): + """ + This is a filesystem-based store for OpenID associations and + nonces. This store should be safe for use in concurrent systems + on both windows and unix (excluding NFS filesystems). There are a + couple race conditions in the system, but those failure cases have + been set up in such a way that the worst-case behavior is someone + having to try to log in a second time. + + Most of the methods of this class are implementation details. + People wishing to just use this store need only pay attention to + the C{L{__init__}} method. + + Methods of this object can raise OSError if unexpected filesystem + conditions, such as bad permissions or missing directories, occur. + """ + + def __init__(self, directory): + """ + Initializes a new FileOpenIDStore. This initializes the + nonce and association directories, which are subdirectories of + the directory passed in. + + @param directory: This is the directory to put the store + directories in. + + @type directory: C{str} + """ + # Make absolute + directory = os.path.normpath(os.path.abspath(directory)) + + self.nonce_dir = os.path.join(directory, 'nonces') + + self.association_dir = os.path.join(directory, 'associations') + + # Temp dir must be on the same filesystem as the assciations + # directory + self.temp_dir = os.path.join(directory, 'temp') + + self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds + + self._setup() + + def _setup(self): + """Make sure that the directories in which we store our data + exist. + + () -> NoneType + """ + _ensureDir(self.nonce_dir) + _ensureDir(self.association_dir) + _ensureDir(self.temp_dir) + + def _mktemp(self): + """Create a temporary file on the same filesystem as + self.association_dir. + + The temporary directory should not be cleaned if there are any + processes using the store. If there is no active process using + the store, it is safe to remove all of the files in the + temporary directory. + + () -> (file, str) + """ + fd, name = mkstemp(dir=self.temp_dir) + try: + file_obj = os.fdopen(fd, 'wb') + return file_obj, name + except: + _removeIfPresent(name) + raise + + def getAssociationFilename(self, server_url, handle): + """Create a unique filename for a given server url and + handle. This implementation does not assume anything about the + format of the handle. The filename that is returned will + contain the domain name from the server URL for ease of human + inspection of the data directory. + + (str, str) -> str + """ + if server_url.find('://') == -1: + raise ValueError('Bad server URL: %r' % server_url) + + proto, rest = server_url.split('://', 1) + domain = _filenameEscape(rest.split('/', 1)[0]) + url_hash = _safe64(server_url) + if handle: + handle_hash = _safe64(handle) + else: + handle_hash = '' + + filename = '%s-%s-%s-%s' % (proto, domain, url_hash, handle_hash) + + return os.path.join(self.association_dir, filename) + + def storeAssociation(self, server_url, association): + """Store an association in the association directory. + + (str, Association) -> NoneType + """ + association_s = association.serialize() # NOTE: UTF-8 encoded bytes + filename = self.getAssociationFilename(server_url, association.handle) + tmp_file, tmp = self._mktemp() + + try: + try: + tmp_file.write(association_s) + os.fsync(tmp_file.fileno()) + finally: + tmp_file.close() + + try: + os.rename(tmp, filename) + except OSError as why: + if why.errno != EEXIST: + raise + + # We only expect EEXIST to happen only on Windows. It's + # possible that we will succeed in unlinking the existing + # file, but not in putting the temporary file in place. + try: + os.unlink(filename) + except OSError as why: + if why.errno == ENOENT: + pass + else: + raise + + # Now the target should not exist. Try renaming again, + # giving up if it fails. + os.rename(tmp, filename) + except: + # If there was an error, don't leave the temporary file + # around. + _removeIfPresent(tmp) + raise + + def getAssociation(self, server_url, handle=None): + """Retrieve an association. If no handle is specified, return + the association with the latest expiration. + + (str, str or NoneType) -> Association or NoneType + """ + if handle is None: + handle = '' + + # The filename with the empty handle is a prefix of all other + # associations for the given server URL. + filename = self.getAssociationFilename(server_url, handle) + + if handle: + return self._getAssociation(filename) + else: + association_files = os.listdir(self.association_dir) + matching_files = [] + # strip off the path to do the comparison + name = os.path.basename(filename) + for association_file in association_files: + if association_file.startswith(name): + matching_files.append(association_file) + + matching_associations = [] + # read the matching files and sort by time issued + for name in matching_files: + full_name = os.path.join(self.association_dir, name) + association = self._getAssociation(full_name) + if association is not None: + matching_associations.append( + (association.issued, association)) + + matching_associations.sort() + + # return the most recently issued one. + if matching_associations: + (_, assoc) = matching_associations[-1] + return assoc + else: + return None + + def _getAssociation(self, filename): + try: + assoc_file = open(filename, 'rb') + except IOError as why: + if why.errno == ENOENT: + # No association exists for that URL and handle + return None + else: + raise + + try: + assoc_s = assoc_file.read() + finally: + assoc_file.close() + + try: + association = Association.deserialize(assoc_s) + except ValueError: + _removeIfPresent(filename) + return None + + # Clean up expired associations + if association.expiresIn == 0: + _removeIfPresent(filename) + return None + else: + return association + + def removeAssociation(self, server_url, handle): + """Remove an association if it exists. Do nothing if it does not. + + (str, str) -> bool + """ + assoc = self.getAssociation(server_url, handle) + if assoc is None: + return 0 + else: + filename = self.getAssociationFilename(server_url, handle) + return _removeIfPresent(filename) + + def useNonce(self, server_url, timestamp, salt): + """Return whether this nonce is valid. + + str -> bool + """ + if abs(timestamp - time.time()) > nonce.SKEW: + return False + + if server_url: + proto, rest = server_url.split('://', 1) + else: + # Create empty proto / rest values for empty server_url, + # which is part of a consumer-generated nonce. + proto, rest = '', '' + + domain = _filenameEscape(rest.split('/', 1)[0]) + url_hash = _safe64(server_url) + salt_hash = _safe64(salt) + + filename = '%08x-%s-%s-%s-%s' % (timestamp, proto, domain, url_hash, + salt_hash) + + filename = os.path.join(self.nonce_dir, filename) + try: + fd = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o200) + except OSError as why: + if why.errno == EEXIST: + return False + else: + raise + else: + os.close(fd) + return True + + def _allAssocs(self): + all_associations = [] + + association_filenames = [ + os.path.join(self.association_dir, filename) + for filename in os.listdir(self.association_dir) + ] + for association_filename in association_filenames: + try: + association_file = open(association_filename, 'rb') + except IOError as why: + if why.errno == ENOENT: + logger.exception("%s disappeared during %s._allAssocs" % ( + association_filename, self.__class__.__name__)) + else: + raise + else: + try: + assoc_s = association_file.read() + finally: + association_file.close() + + # Remove expired or corrupted associations + try: + association = Association.deserialize(assoc_s) + except ValueError: + _removeIfPresent(association_filename) + else: + all_associations.append( + (association_filename, association)) + + return all_associations + + def cleanup(self): + """Remove expired entries from the database. This is + potentially expensive, so only run when it is acceptable to + take time. + + () -> NoneType + """ + self.cleanupAssociations() + self.cleanupNonces() + + def cleanupAssociations(self): + removed = 0 + for assoc_filename, assoc in self._allAssocs(): + if assoc.expiresIn == 0: + _removeIfPresent(assoc_filename) + removed += 1 + return removed + + def cleanupNonces(self): + nonces = os.listdir(self.nonce_dir) + now = time.time() + + removed = 0 + # Check all nonces for expiry + for nonce_fname in nonces: + timestamp = nonce_fname.split('-', 1)[0] + timestamp = int(timestamp, 16) + if abs(timestamp - now) > nonce.SKEW: + filename = os.path.join(self.nonce_dir, nonce_fname) + _removeIfPresent(filename) + removed += 1 + return removed diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/interface.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..63776572d00834f96150b83c28d99c51347f0035 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/interface.py @@ -0,0 +1,198 @@ +""" +This module contains the definition of the C{L{OpenIDStore}} +interface. +""" + + +class OpenIDStore(object): + """ + This is the interface for the store objects the OpenID library + uses. It is a single class that provides all of the persistence + mechanisms that the OpenID library needs, for both servers and + consumers. + + @change: Version 2.0 removed the C{storeNonce}, C{getAuthKey}, and C{isDumb} + methods, and changed the behavior of the C{L{useNonce}} method + to support one-way nonces. It added C{L{cleanupNonces}}, + C{L{cleanupAssociations}}, and C{L{cleanup}}. + + @sort: storeAssociation, getAssociation, removeAssociation, + useNonce + """ + + def storeAssociation(self, server_url, association): + """ + This method puts a C{L{Association + <openid.association.Association>}} object into storage, + retrievable by server URL and handle. + + + @param server_url: The URL of the identity server that this + association is with. Because of the way the server + portion of the library uses this interface, don't assume + there are any limitations on the character set of the + input string. In particular, expect to see unescaped + non-url-safe characters in the server_url field. + + @type server_url: C{str} + + + @param association: The C{L{Association + <openid.association.Association>}} to store. + + @type association: C{L{Association + <openid.association.Association>}} + + + @return: C{None} + + @rtype: C{NoneType} + """ + raise NotImplementedError + + def getAssociation(self, server_url, handle=None): + """ + This method returns an C{L{Association + <openid.association.Association>}} object from storage that + matches the server URL and, if specified, handle. It returns + C{None} if no such association is found or if the matching + association is expired. + + If no handle is specified, the store may return any + association which matches the server URL. If multiple + associations are valid, the recommended return value for this + method is the one most recently issued. + + This method is allowed (and encouraged) to garbage collect + expired associations when found. This method must not return + expired associations. + + + @param server_url: The URL of the identity server to get the + association for. Because of the way the server portion of + the library uses this interface, don't assume there are + any limitations on the character set of the input string. + In particular, expect to see unescaped non-url-safe + characters in the server_url field. + + @type server_url: C{str} + + + @param handle: This optional parameter is the handle of the + specific association to get. If no specific handle is + provided, any valid association matching the server URL is + returned. + + @type handle: C{str} or C{NoneType} + + + @return: The C{L{Association + <openid.association.Association>}} for the given identity + server. + + @rtype: C{L{Association <openid.association.Association>}} or + C{NoneType} + """ + raise NotImplementedError + + def removeAssociation(self, server_url, handle): + """ + This method removes the matching association if it's found, + and returns whether the association was removed or not. + + + @param server_url: The URL of the identity server the + association to remove belongs to. Because of the way the + server portion of the library uses this interface, don't + assume there are any limitations on the character set of + the input string. In particular, expect to see unescaped + non-url-safe characters in the server_url field. + + @type server_url: C{str} + + + @param handle: This is the handle of the association to + remove. If there isn't an association found that matches + both the given URL and handle, then there was no matching + handle found. + + @type handle: C{str} + + + @return: Returns whether or not the given association existed. + + @rtype: C{bool} or C{int} + """ + raise NotImplementedError + + def useNonce(self, server_url, timestamp, salt): + """Called when using a nonce. + + This method should return C{True} if the nonce has not been + used before, and store it for a while to make sure nobody + tries to use the same value again. If the nonce has already + been used or the timestamp is not current, return C{False}. + + You may use L{openid.store.nonce.SKEW} for your timestamp window. + + @change: In earlier versions, round-trip nonces were used and + a nonce was only valid if it had been previously stored + with C{storeNonce}. Version 2.0 uses one-way nonces, + requiring a different implementation here that does not + depend on a C{storeNonce} call. (C{storeNonce} is no + longer part of the interface.) + + @param server_url: The URL of the server from which the nonce + originated. + + @type server_url: C{str} + + @param timestamp: The time that the nonce was created (to the + nearest second), in seconds since January 1 1970 UTC. + @type timestamp: C{int} + + @param salt: A random string that makes two nonces from the + same server issued during the same second unique. + @type salt: str + + @return: Whether or not the nonce was valid. + + @rtype: C{bool} + """ + raise NotImplementedError + + def cleanupNonces(self): + """Remove expired nonces from the store. + + Discards any nonce from storage that is old enough that its + timestamp would not pass L{useNonce}. + + This method is not called in the normal operation of the + library. It provides a way for store admins to keep + their storage from filling up with expired data. + + @return: the number of nonces expired. + @returntype: int + """ + raise NotImplementedError + + def cleanupAssociations(self): + """Remove expired associations from the store. + + This method is not called in the normal operation of the + library. It provides a way for store admins to keep + their storage from filling up with expired data. + + @return: the number of associations expired. + @returntype: int + """ + raise NotImplementedError + + def cleanup(self): + """Shortcut for C{L{cleanupNonces}()}, C{L{cleanupAssociations}()}. + + This method is not called in the normal operation of the + library. It provides a way for store admins to keep + their storage from filling up with expired data. + """ + return self.cleanupNonces(), self.cleanupAssociations() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/memstore.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/memstore.py new file mode 100644 index 0000000000000000000000000000000000000000..21e3e69c09170e7263fdd795280dd7b24a033452 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/memstore.py @@ -0,0 +1,126 @@ +"""A simple store using only in-process memory.""" + +from openid.store import nonce + +import copy +import time + + +class ServerAssocs(object): + def __init__(self): + self.assocs = {} + + def set(self, assoc): + self.assocs[assoc.handle] = assoc + + def get(self, handle): + return self.assocs.get(handle) + + def remove(self, handle): + try: + del self.assocs[handle] + except KeyError: + return False + else: + return True + + def best(self): + """Returns association with the oldest issued date. + + or None if there are no associations. + """ + best = None + for assoc in list(self.assocs.values()): + if best is None or best.issued < assoc.issued: + best = assoc + return best + + def cleanup(self): + """Remove expired associations. + + @return: tuple of (removed associations, remaining associations) + """ + remove = [] + for handle, assoc in self.assocs.items(): + if assoc.expiresIn == 0: + remove.append(handle) + for handle in remove: + del self.assocs[handle] + return len(remove), len(self.assocs) + + +class MemoryStore(object): + """In-process memory store. + + Use for single long-running processes. No persistence supplied. + """ + + def __init__(self): + self.server_assocs = {} + self.nonces = {} + + def _getServerAssocs(self, server_url): + try: + return self.server_assocs[server_url] + except KeyError: + assocs = self.server_assocs[server_url] = ServerAssocs() + return assocs + + def storeAssociation(self, server_url, assoc): + assocs = self._getServerAssocs(server_url) + assocs.set(copy.deepcopy(assoc)) + + def getAssociation(self, server_url, handle=None): + assocs = self._getServerAssocs(server_url) + if handle is None: + return assocs.best() + else: + return assocs.get(handle) + + def removeAssociation(self, server_url, handle): + assocs = self._getServerAssocs(server_url) + return assocs.remove(handle) + + def useNonce(self, server_url, timestamp, salt): + if abs(timestamp - time.time()) > nonce.SKEW: + return False + + anonce = (str(server_url), int(timestamp), str(salt)) + if anonce in self.nonces: + return False + else: + self.nonces[anonce] = None + return True + + def cleanupNonces(self): + now = time.time() + expired = [] + for anonce in self.nonces.keys(): + if abs(anonce[1] - now) > nonce.SKEW: + # removing items while iterating over the set could be bad. + expired.append(anonce) + + for anonce in expired: + del self.nonces[anonce] + return len(expired) + + def cleanupAssociations(self): + remove_urls = [] + removed_assocs = 0 + for server_url, assocs in self.server_assocs.items(): + removed, remaining = assocs.cleanup() + removed_assocs += removed + if not remaining: + remove_urls.append(server_url) + + # Remove entries from server_assocs that had none remaining. + for server_url in remove_urls: + del self.server_assocs[server_url] + return removed_assocs + + def __eq__(self, other): + return ((self.server_assocs == other.server_assocs) and + (self.nonces == other.nonces)) + + def __ne__(self, other): + return not (self == other) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/nonce.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/nonce.py new file mode 100644 index 0000000000000000000000000000000000000000..06c12149a4b12c4aa1ae32073838a0abe0e9c357 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/nonce.py @@ -0,0 +1,101 @@ +__all__ = [ + 'split', + 'mkNonce', + 'checkTimestamp', +] + +from openid import cryptutil +from time import strptime, strftime, gmtime, time +from calendar import timegm +import string + +NONCE_CHARS = string.ascii_letters + string.digits + +# Keep nonces for five hours (allow five hours for the combination of +# request time and clock skew). This is probably way more than is +# necessary, but there is not much overhead in storing nonces. +SKEW = 60 * 60 * 5 + +time_fmt = '%Y-%m-%dT%H:%M:%SZ' +time_str_len = len('0000-00-00T00:00:00Z') + + +def split(nonce_string): + """Extract a timestamp from the given nonce string + + @param nonce_string: the nonce from which to extract the timestamp + @type nonce_string: str + + @returns: A pair of a Unix timestamp and the salt characters + @returntype: (int, str) + + @raises ValueError: if the nonce does not start with a correctly + formatted time string + """ + timestamp_str = nonce_string[:time_str_len] + try: + timestamp = timegm(strptime(timestamp_str, time_fmt)) + except AssertionError: # Python 2.2 + timestamp = -1 + if timestamp < 0: + raise ValueError('time out of range') + return timestamp, nonce_string[time_str_len:] + + +def checkTimestamp(nonce_string, allowed_skew=SKEW, now=None): + """Is the timestamp that is part of the specified nonce string + within the allowed clock-skew of the current time? + + @param nonce_string: The nonce that is being checked + @type nonce_string: str + + @param allowed_skew: How many seconds should be allowed for + completing the request, allowing for clock skew. + @type allowed_skew: int + + @param now: The current time, as a Unix timestamp + @type now: int + + @returntype: bool + @returns: Whether the timestamp is correctly formatted and within + the allowed skew of the current time. + """ + try: + stamp, _ = split(nonce_string) + except ValueError: + return False + else: + if now is None: + now = time() + + # Time after which we should not use the nonce + past = now - allowed_skew + + # Time that is too far in the future for us to allow + future = now + allowed_skew + + # the stamp is not too far in the future and is not too far in + # the past + return past <= stamp <= future + + +def mkNonce(when=None): + """Generate a nonce with the current timestamp + + @param when: Unix timestamp representing the issue time of the + nonce. Defaults to the current time. + @type when: int + + @returntype: str + @returns: A string that should be usable as a one-way nonce + + @see: time + """ + salt = cryptutil.randomString(6, NONCE_CHARS) + if when is None: + t = gmtime() + else: + t = gmtime(when) + + time_str = strftime(time_fmt, t) + return time_str + salt diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/store/sqlstore.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/sqlstore.py new file mode 100644 index 0000000000000000000000000000000000000000..1fb6a34563427221de56ae0c4188d4ba91d15b9f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/store/sqlstore.py @@ -0,0 +1,510 @@ +""" +This module contains C{L{OpenIDStore}} implementations that use +various SQL databases to back them. + +Example of how to initialize a store database:: + +python -c 'from openid.store import sqlstore; import pysqlite2.dbapi2;' + 'sqlstore.SQLiteStore(pysqlite2.dbapi2.connect("cstore.db")).createTables()' +""" +import re +import time + +from openid.association import Association +from openid.store.interface import OpenIDStore +from openid.store import nonce + + +def _inTxn(func): + def wrapped(self, *args, **kwargs): + return self._callInTransaction(func, self, *args, **kwargs) + + if hasattr(func, '__name__'): + try: + wrapped.__name__ = func.__name__[4:] + except TypeError: + pass + + if hasattr(func, '__doc__'): + wrapped.__doc__ = func.__doc__ + + return wrapped + + +class SQLStore(OpenIDStore): + """ + This is the parent class for the SQL stores, which contains the + logic common to all of the SQL stores. + + The table names used are determined by the class variables + C{L{associations_table}} and + C{L{nonces_table}}. To change the name of the tables used, pass + new table names into the constructor. + + To create the tables with the proper schema, see the + C{L{createTables}} method. + + This class shouldn't be used directly. Use one of its subclasses + instead, as those contain the code necessary to use a specific + database. + + All methods other than C{L{__init__}} and C{L{createTables}} + should be considered implementation details. + + + @cvar associations_table: This is the default name of the table to + keep associations in + + @cvar nonces_table: This is the default name of the table to keep + nonces in. + + + @sort: __init__, createTables + """ + + associations_table = 'oid_associations' + nonces_table = 'oid_nonces' + + def __init__(self, conn, associations_table=None, nonces_table=None): + """ + This creates a new SQLStore instance. It requires an + established database connection be given to it, and it allows + overriding the default table names. + + + @param conn: This must be an established connection to a + database of the correct type for the SQLStore subclass + you're using. + + @type conn: A python database API compatible connection + object. + + + @param associations_table: This is an optional parameter to + specify the name of the table used for storing + associations. The default value is specified in + C{L{SQLStore.associations_table}}. + + @type associations_table: C{str} + + + @param nonces_table: This is an optional parameter to specify + the name of the table used for storing nonces. The + default value is specified in C{L{SQLStore.nonces_table}}. + + @type nonces_table: C{str} + """ + self.conn = conn + self.cur = None + self._statement_cache = {} + self._table_names = { + 'associations': associations_table or self.associations_table, + 'nonces': nonces_table or self.nonces_table, + } + self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds + + # DB API extension: search for "Connection Attributes .Error, + # .ProgrammingError, etc." in + # http://www.python.org/dev/peps/pep-0249/ + if (hasattr(self.conn, 'IntegrityError') and + hasattr(self.conn, 'OperationalError')): + self.exceptions = self.conn + + if not (hasattr(self.exceptions, 'IntegrityError') and + hasattr(self.exceptions, 'OperationalError')): + raise RuntimeError("Error using database connection module " + "(Maybe it can't be imported?)") + + def blobDecode(self, blob): + """Convert a blob as returned by the SQL engine into a str object. + + str -> str""" + return blob + + def blobEncode(self, s): + """Convert a str object into the necessary object for storing + in the database as a blob.""" + return s + + def _getSQL(self, sql_name): + try: + return self._statement_cache[sql_name] + except KeyError: + sql = getattr(self, sql_name) + sql %= self._table_names + self._statement_cache[sql_name] = sql + return sql + + def _execSQL(self, sql_name, *args): + sql = self._getSQL(sql_name) + + # Kludge because we have reports of postgresql not quoting + # arguments if they are passed in as unicode instead of str. + # Currently the strings in our tables just have ascii in them, + # so this ought to be safe. + def unicode_to_str(arg): + if isinstance(arg, str): + return str(arg) + else: + return arg + + str_args = list(map(unicode_to_str, args)) + self.cur.execute(sql, str_args) + + def __getattr__(self, attr): + # if the attribute starts with db_, use a default + # implementation that looks up the appropriate SQL statement + # as an attribute of this object and executes it. + if attr[:3] == 'db_': + sql_name = attr[3:] + '_sql' + + def func(*args): + return self._execSQL(sql_name, *args) + + setattr(self, attr, func) + return func + else: + raise AttributeError('Attribute %r not found' % (attr, )) + + def _callInTransaction(self, func, *args, **kwargs): + """Execute the given function inside of a transaction, with an + open cursor. If no exception is raised, the transaction is + comitted, otherwise it is rolled back.""" + # No nesting of transactions + self.conn.rollback() + + try: + self.cur = self.conn.cursor() + try: + ret = func(*args, **kwargs) + finally: + self.cur.close() + self.cur = None + except: + self.conn.rollback() + raise + else: + self.conn.commit() + + return ret + + def txn_createTables(self): + """ + This method creates the database tables necessary for this + store to work. It should not be called if the tables already + exist. + """ + self.db_create_nonce() + self.db_create_assoc() + + createTables = _inTxn(txn_createTables) + + def txn_storeAssociation(self, server_url, association): + """Set the association for the server URL. + + Association -> NoneType + """ + a = association + self.db_set_assoc(server_url, a.handle, + self.blobEncode(a.secret), a.issued, a.lifetime, + a.assoc_type) + + storeAssociation = _inTxn(txn_storeAssociation) + + def txn_getAssociation(self, server_url, handle=None): + """Get the most recent association that has been set for this + server URL and handle. + + str -> NoneType or Association + """ + if handle is not None: + self.db_get_assoc(server_url, handle) + else: + self.db_get_assocs(server_url) + + rows = self.cur.fetchall() + if len(rows) == 0: + return None + else: + associations = [] + for values in rows: + values = list(values) + values[1] = self.blobDecode(values[1]) + assoc = Association(*values) + if assoc.expiresIn == 0: + self.txn_removeAssociation(server_url, assoc.handle) + else: + associations.append((assoc.issued, assoc)) + + if associations: + associations.sort() + return associations[-1][1] + else: + return None + + getAssociation = _inTxn(txn_getAssociation) + + def txn_removeAssociation(self, server_url, handle): + """Remove the association for the given server URL and handle, + returning whether the association existed at all. + + (str, str) -> bool + """ + self.db_remove_assoc(server_url, handle) + return self.cur.rowcount > 0 # -1 is undefined + + removeAssociation = _inTxn(txn_removeAssociation) + + def txn_useNonce(self, server_url, timestamp, salt): + """Return whether this nonce is present, and if it is, then + remove it from the set. + + str -> bool""" + if abs(timestamp - time.time()) > nonce.SKEW: + return False + + try: + self.db_add_nonce(server_url, timestamp, salt) + except self.exceptions.IntegrityError: + # The key uniqueness check failed + return False + else: + # The nonce was successfully added + return True + + useNonce = _inTxn(txn_useNonce) + + def txn_cleanupNonces(self): + self.db_clean_nonce(int(time.time()) - nonce.SKEW) + return self.cur.rowcount + + cleanupNonces = _inTxn(txn_cleanupNonces) + + def txn_cleanupAssociations(self): + self.db_clean_assoc(int(time.time())) + return self.cur.rowcount + + cleanupAssociations = _inTxn(txn_cleanupAssociations) + + +class SQLiteStore(SQLStore): + """ + This is an SQLite-based specialization of C{L{SQLStore}}. + + To create an instance, see C{L{SQLStore.__init__}}. To create the + tables it will use, see C{L{SQLStore.createTables}}. + + All other methods are implementation details. + """ + + create_nonce_sql = """ + CREATE TABLE %(nonces)s ( + server_url VARCHAR, + timestamp INTEGER, + salt CHAR(40), + UNIQUE(server_url, timestamp, salt) + ); + """ + + create_assoc_sql = """ + CREATE TABLE %(associations)s + ( + server_url VARCHAR(2047), + handle VARCHAR(255), + secret BLOB(128), + issued INTEGER, + lifetime INTEGER, + assoc_type VARCHAR(64), + PRIMARY KEY (server_url, handle) + ); + """ + + set_assoc_sql = ('INSERT OR REPLACE INTO %(associations)s ' + '(server_url, handle, secret, issued, ' + 'lifetime, assoc_type) ' + 'VALUES (?, ?, ?, ?, ?, ?);') + get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type ' + 'FROM %(associations)s WHERE server_url = ?;') + get_assoc_sql = ( + 'SELECT handle, secret, issued, lifetime, assoc_type ' + 'FROM %(associations)s WHERE server_url = ? AND handle = ?;') + + get_expired_sql = ('SELECT server_url ' + 'FROM %(associations)s WHERE issued + lifetime < ?;') + + remove_assoc_sql = ('DELETE FROM %(associations)s ' + 'WHERE server_url = ? AND handle = ?;') + + clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < ?;' + + add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (?, ?, ?);' + + clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < ?;' + + def blobEncode(self, s): + return memoryview(s) + + def useNonce(self, *args, **kwargs): + # Older versions of the sqlite wrapper do not raise + # IntegrityError as they should, so we have to detect the + # message from the OperationalError. + try: + return super(SQLiteStore, self).useNonce(*args, **kwargs) + except self.exceptions.OperationalError as why: + if re.match('^columns .* are not unique$', str(why)): + return False + else: + raise + + +class MySQLStore(SQLStore): + """ + This is a MySQL-based specialization of C{L{SQLStore}}. + + Uses InnoDB tables for transaction support. + + To create an instance, see C{L{SQLStore.__init__}}. To create the + tables it will use, see C{L{SQLStore.createTables}}. + + All other methods are implementation details. + """ + + try: + import MySQLdb as exceptions + except ImportError: + exceptions = None + + create_nonce_sql = """ + CREATE TABLE %(nonces)s ( + server_url BLOB NOT NULL, + timestamp INTEGER NOT NULL, + salt CHAR(40) NOT NULL, + PRIMARY KEY (server_url(255), timestamp, salt) + ) + ENGINE=InnoDB; + """ + + create_assoc_sql = """ + CREATE TABLE %(associations)s + ( + server_url BLOB NOT NULL, + handle VARCHAR(255) NOT NULL, + secret BLOB NOT NULL, + issued INTEGER NOT NULL, + lifetime INTEGER NOT NULL, + assoc_type VARCHAR(64) NOT NULL, + PRIMARY KEY (server_url(255), handle) + ) + ENGINE=InnoDB; + """ + + set_assoc_sql = ('REPLACE INTO %(associations)s ' + 'VALUES (%%s, %%s, %%s, %%s, %%s, %%s);') + get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type' + ' FROM %(associations)s WHERE server_url = %%s;') + get_expired_sql = ('SELECT server_url ' + 'FROM %(associations)s WHERE issued + lifetime < %%s;') + + get_assoc_sql = ( + 'SELECT handle, secret, issued, lifetime, assoc_type' + ' FROM %(associations)s WHERE server_url = %%s AND handle = %%s;') + remove_assoc_sql = ('DELETE FROM %(associations)s ' + 'WHERE server_url = %%s AND handle = %%s;') + + clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < %%s;' + + add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (%%s, %%s, %%s);' + + clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < %%s;' + + +class PostgreSQLStore(SQLStore): + """ + This is a PostgreSQL-based specialization of C{L{SQLStore}}. + + To create an instance, see C{L{SQLStore.__init__}}. To create the + tables it will use, see C{L{SQLStore.createTables}}. + + All other methods are implementation details. + """ + + try: + import psycopg2 + except ImportError: + from psycopg2cffi import compat + compat.register() + + exceptions = None + + create_nonce_sql = """ + CREATE TABLE %(nonces)s ( + server_url VARCHAR(2047) NOT NULL, + timestamp INTEGER NOT NULL, + salt CHAR(40) NOT NULL, + PRIMARY KEY (server_url, timestamp, salt) + ); + """ + + create_assoc_sql = """ + CREATE TABLE %(associations)s + ( + server_url VARCHAR(2047) NOT NULL, + handle VARCHAR(255) NOT NULL, + secret BYTEA NOT NULL, + issued INTEGER NOT NULL, + lifetime INTEGER NOT NULL, + assoc_type VARCHAR(64) NOT NULL, + PRIMARY KEY (server_url, handle), + CONSTRAINT secret_length_constraint CHECK (LENGTH(secret) <= 128) + ); + """ + + def db_set_assoc(self, server_url, handle, secret, issued, lifetime, + assoc_type): + """ + Set an association. This is implemented as a method because + REPLACE INTO is not supported by PostgreSQL (and is not + standard SQL). + """ + result = self.db_get_assoc(server_url, handle) + rows = self.cur.fetchall() + if len(rows): + # Update the table since this associations already exists. + return self.db_update_assoc(secret, issued, lifetime, assoc_type, + server_url, handle) + else: + # Insert a new record because this association wasn't + # found. + return self.db_new_assoc(server_url, handle, secret, issued, + lifetime, assoc_type) + + new_assoc_sql = ('INSERT INTO %(associations)s ' + 'VALUES (%%s, %%s, %%s, %%s, %%s, %%s);') + update_assoc_sql = ('UPDATE %(associations)s SET ' + 'secret = %%s, issued = %%s, ' + 'lifetime = %%s, assoc_type = %%s ' + 'WHERE server_url = %%s AND handle = %%s;') + get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type' + ' FROM %(associations)s WHERE server_url = %%s;') + get_expired_sql = ('SELECT server_url ' + 'FROM %(associations)s WHERE issued + lifetime < %%s;') + + get_assoc_sql = ( + 'SELECT handle, secret, issued, lifetime, assoc_type' + ' FROM %(associations)s WHERE server_url = %%s AND handle = %%s;') + remove_assoc_sql = ('DELETE FROM %(associations)s ' + 'WHERE server_url = %%s AND handle = %%s;') + + clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < %%s;' + + add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (%%s, %%s, %%s);' + + clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < %%s;' + + def blobEncode(self, blob): + from psycopg2 import Binary + + return Binary(blob) + + def blobDecode(self, blob): + return blob.tobytes() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/urinorm.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/urinorm.py new file mode 100644 index 0000000000000000000000000000000000000000..5fb49b4d4646167ba74bfe6140e5762285a258bf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/urinorm.py @@ -0,0 +1,161 @@ +import re + +from openid import codecutil # registers 'oid_percent_escape' encoding handler + +# from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt) +uri_pattern = r'^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?' +uri_re = re.compile(uri_pattern) + +# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" +# +# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +# / "*" / "+" / "," / ";" / "=" +# +# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + +uri_illegal_char_re = re.compile(r"[^-A-Za-z0-9:/?#[\]@!$&'()*+,;=._~%]", + re.UNICODE) + +authority_pattern = r'^([^@]*@)?([^:]*)(:.*)?' +authority_re = re.compile(authority_pattern) + +pct_encoded_pattern = r'%([0-9A-Fa-f]{2})' +pct_encoded_re = re.compile(pct_encoded_pattern) + +_unreserved = [False] * 256 +for _ in range(ord('A'), ord('Z') + 1): + _unreserved[_] = True +for _ in range(ord('0'), ord('9') + 1): + _unreserved[_] = True +for _ in range(ord('a'), ord('z') + 1): + _unreserved[_] = True +_unreserved[ord('-')] = True +_unreserved[ord('.')] = True +_unreserved[ord('_')] = True +_unreserved[ord('~')] = True + + +def _pct_encoded_replace_unreserved(mo): + try: + i = int(mo.group(1), 16) + if _unreserved[i]: + return chr(i) + else: + return mo.group().upper() + + except ValueError: + return mo.group() + + +def _pct_encoded_replace(mo): + try: + return chr(int(mo.group(1), 16)) + except ValueError: + return mo.group() + + +def remove_dot_segments(path): + result_segments = [] + + while path: + if path.startswith('../'): + path = path[3:] + elif path.startswith('./'): + path = path[2:] + elif path.startswith('/./'): + path = path[2:] + elif path == '/.': + path = '/' + elif path.startswith('/../'): + path = path[3:] + if result_segments: + result_segments.pop() + elif path == '/..': + path = '/' + if result_segments: + result_segments.pop() + elif path == '..' or path == '.': + path = '' + else: + i = 0 + if path[0] == '/': + i = 1 + i = path.find('/', i) + if i == -1: + i = len(path) + result_segments.append(path[:i]) + path = path[i:] + + return ''.join(result_segments) + + +def urinorm(uri): + ''' + Normalize a URI + ''' + # TODO: use urllib.parse instead of these complex regular expressions + if isinstance(uri, bytes): + uri = str(uri, encoding='utf-8') + + uri = uri.encode('ascii', errors='oid_percent_escape').decode('utf-8') + # _escapeme_re.sub(_pct_escape_unicode, uri).encode('ascii').decode() + + illegal_mo = uri_illegal_char_re.search(uri) + if illegal_mo: + raise ValueError('Illegal characters in URI: %r at position %s' % + (illegal_mo.group(), illegal_mo.start())) + + uri_mo = uri_re.match(uri) + + scheme = uri_mo.group(2) + if scheme is None: + raise ValueError('No scheme specified') + + scheme = scheme.lower() + if scheme not in ('http', 'https'): + raise ValueError('Not an absolute HTTP or HTTPS URI: %r' % (uri, )) + + authority = uri_mo.group(4) + if authority is None: + raise ValueError('Not an absolute URI: %r' % (uri, )) + + authority_mo = authority_re.match(authority) + if authority_mo is None: + raise ValueError('URI does not have a valid authority: %r' % (uri, )) + + userinfo, host, port = authority_mo.groups() + + if userinfo is None: + userinfo = '' + + if '%' in host: + host = host.lower() + host = pct_encoded_re.sub(_pct_encoded_replace, host) + host = host.encode('idna').decode() + else: + host = host.lower() + + if port: + if (port == ':' or (scheme == 'http' and port == ':80') or + (scheme == 'https' and port == ':443')): + port = '' + else: + port = '' + + authority = userinfo + host + port + + path = uri_mo.group(5) + path = pct_encoded_re.sub(_pct_encoded_replace_unreserved, path) + path = remove_dot_segments(path) + if not path: + path = '/' + + query = uri_mo.group(6) + if query is None: + query = '' + + fragment = uri_mo.group(8) + if fragment is None: + fragment = '' + + return scheme + '://' + authority + path + query + fragment diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ef806e87508dac5c9701356b287e311b281af402 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__init__.py @@ -0,0 +1,17 @@ +#-*- coding: utf-8 -*- + +__all__ = [ + 'constants', + 'discover', + 'etxrd', + 'filters', + 'manager', + 'parsehtml', + 'services', + 'xri', + 'xrires', +] + +version_info = (2, 0, 0) + +__version__ = ".".join(str(x) for x in version_info) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34ea43101dfac33052810c1c3daca0a86d32296b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/accept.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/accept.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fd853b0d1c4cfe7f731ddca435807dffb4aeddc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/accept.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/constants.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/constants.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..284393ab628015325d36ce82a2ef003f32cab245 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/constants.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/discover.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/discover.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24486fa2efcc780ddab014122f1e043225f270a3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/discover.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/etxrd.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/etxrd.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db46a4f1d1cd399062082cec779e8b14b897cd81 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/etxrd.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/filters.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/filters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50017b0257c4f1948e957b16915433974c216a69 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/filters.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/manager.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/manager.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb54b0f139b7032f11d842b05f4efbb968c12c48 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/manager.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/parsehtml.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/parsehtml.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93bbd7cb001cb519920ac319c1182dc58a33bb14 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/parsehtml.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/services.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/services.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76b439a01bdae389202deb2d4fb5e9f18ff16f80 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/services.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xri.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xri.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fcc7814da712fab15c331324a3fdcb073b57ac8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xri.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xrires.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xrires.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94aeb50d862b04b628cff831f7403bf941e925f8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/__pycache__/xrires.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/accept.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/accept.py new file mode 100644 index 0000000000000000000000000000000000000000..2f18aa662a7ab2751b4666a82b23d2b6b121379e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/accept.py @@ -0,0 +1,137 @@ +"""Functions for generating and parsing HTTP Accept: headers for +supporting server-directed content negotiation. +""" + + +def generateAcceptHeader(*elements): + """Generate an accept header value + + [str or (str, float)] -> str + """ + parts = [] + for element in elements: + if type(element) is str: + qs = "1.0" + mtype = element + else: + mtype, q = element + q = float(q) + if q > 1 or q <= 0: + raise ValueError('Invalid preference factor: %r' % q) + + qs = '%0.1f' % (q, ) + + parts.append((qs, mtype)) + + parts.sort() + chunks = [] + for q, mtype in parts: + if q == '1.0': + chunks.append(mtype) + else: + chunks.append('%s; q=%s' % (mtype, q)) + + return ', '.join(chunks) + + +def parseAcceptHeader(value): + """Parse an accept header, ignoring any accept-extensions + + returns a list of tuples containing main MIME type, MIME subtype, + and quality markdown. + + str -> [(str, str, float)] + """ + chunks = [chunk.strip() for chunk in value.split(',')] + accept = [] + for chunk in chunks: + parts = [s.strip() for s in chunk.split(';')] + + mtype = parts.pop(0) + if '/' not in mtype: + # This is not a MIME type, so ignore the bad data + continue + + main, sub = mtype.split('/', 1) + + for ext in parts: + if '=' in ext: + k, v = ext.split('=', 1) + if k == 'q': + try: + q = float(v) + break + except ValueError: + # Ignore poorly formed q-values + pass + else: + q = 1.0 + + accept.append((q, main, sub)) + + accept.sort() + accept.reverse() + return [(main, sub, q) for (q, main, sub) in accept] + + +def matchTypes(accept_types, have_types): + """Given the result of parsing an Accept: header, and the + available MIME types, return the acceptable types with their + quality markdowns. + + For example: + + >>> acceptable = parseAcceptHeader('text/html, text/plain; q=0.5') + >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg']) + [('text/html', 1.0), ('text/plain', 0.5)] + + + Type signature: ([(str, str, float)], [str]) -> [(str, float)] + """ + if not accept_types: + # Accept all of them + default = 1 + else: + default = 0 + + match_main = {} + match_sub = {} + for (main, sub, q) in accept_types: + if main == '*': + default = max(default, q) + continue + elif sub == '*': + match_main[main] = max(match_main.get(main, 0), q) + else: + match_sub[(main, sub)] = max(match_sub.get((main, sub), 0), q) + + accepted_list = [] + order_maintainer = 0 + for mtype in have_types: + main, sub = mtype.split('/') + if (main, sub) in match_sub: + q = match_sub[(main, sub)] + else: + q = match_main.get(main, default) + + if q: + accepted_list.append((1 - q, order_maintainer, q, mtype)) + order_maintainer += 1 + + accepted_list.sort() + return [(mtype, q) for (_, _, q, mtype) in accepted_list] + + +def getAcceptable(accept_header, have_types): + """Parse the accept header and return a list of available types in + preferred order. If a type is unacceptable, it will not be in the + resulting list. + + This is a convenience wrapper around matchTypes and + parseAcceptHeader. + + (str, [str]) -> [str] + """ + accepted = parseAcceptHeader(accept_header) + preferred = matchTypes(accepted, have_types) + return [mtype for (mtype, _) in preferred] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/constants.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..5d3072387ebda2f5c8f1b9d8bc63f27a80208af9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/constants.py @@ -0,0 +1,12 @@ +__all__ = ['YADIS_HEADER_NAME', 'YADIS_CONTENT_TYPE', 'YADIS_ACCEPT_HEADER'] +from openid.yadis.accept import generateAcceptHeader + +YADIS_HEADER_NAME = 'X-XRDS-Location' +YADIS_CONTENT_TYPE = 'application/xrds+xml' + +# A value suitable for using as an accept header when performing YADIS +# discovery, unless the application has special requirements +YADIS_ACCEPT_HEADER = generateAcceptHeader( + ('text/html', 0.3), + ('application/xhtml+xml', 0.5), + (YADIS_CONTENT_TYPE, 1.0), ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/discover.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/discover.py new file mode 100644 index 0000000000000000000000000000000000000000..af11b1036b17aa4ec2ec5fe3b4116151550658f0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/discover.py @@ -0,0 +1,169 @@ +# -*- test-case-name: openid.test.test_yadis_discover -*- +__all__ = ['discover', 'DiscoveryResult', 'DiscoveryFailure'] + +from io import StringIO + +from openid import fetchers + +from openid.yadis.constants import \ + YADIS_HEADER_NAME, YADIS_CONTENT_TYPE, YADIS_ACCEPT_HEADER +from openid.yadis.parsehtml import MetaNotFound, findHTMLMeta + + +class DiscoveryFailure(Exception): + """Raised when a YADIS protocol error occurs in the discovery process""" + identity_url = None + + def __init__(self, message, http_response): + Exception.__init__(self, message) + self.http_response = http_response + + +class DiscoveryResult(object): + """Contains the result of performing Yadis discovery on a URI""" + + # The URI that was passed to the fetcher + request_uri = None + + # The result of following redirects from the request_uri + normalized_uri = None + + # The URI from which the response text was returned (set to + # None if there was no XRDS document found) + xrds_uri = None + + # The content-type returned with the response_text + content_type = None + + # The document returned from the xrds_uri + response_text = None + + def __init__(self, request_uri): + """Initialize the state of the object + + sets all attributes to None except the request_uri + """ + self.request_uri = request_uri + + def usedYadisLocation(self): + """Was the Yadis protocol's indirection used?""" + if self.xrds_uri is None: + return False + return self.normalized_uri != self.xrds_uri + + def isXRDS(self): + """Is the response text supposed to be an XRDS document?""" + return (self.usedYadisLocation() or + self.content_type == YADIS_CONTENT_TYPE) + + +def discover(uri): + """Discover services for a given URI. + + @param uri: The identity URI as a well-formed http or https + URI. The well-formedness and the protocol are not checked, but + the results of this function are undefined if those properties + do not hold. + + @return: DiscoveryResult object + + @raises Exception: Any exception that can be raised by fetching a URL with + the given fetcher. + @raises DiscoveryFailure: When the HTTP response does not have a 200 code. + """ + result = DiscoveryResult(uri) + resp = fetchers.fetch(uri, headers={'Accept': YADIS_ACCEPT_HEADER}) + if resp.status not in (200, 206): + raise DiscoveryFailure( + 'HTTP Response status from identity URL host is not 200. ' + 'Got status %r' % (resp.status, ), resp) + + # Note the URL after following redirects + result.normalized_uri = resp.final_url + + # Attempt to find out where to go to discover the document + # or if we already have it + result.content_type = resp.headers.get('content-type') + + result.xrds_uri = whereIsYadis(resp) + + if result.xrds_uri and result.usedYadisLocation(): + resp = fetchers.fetch(result.xrds_uri) + if resp.status not in (200, 206): + exc = DiscoveryFailure( + 'HTTP Response status from Yadis host is not 200. ' + 'Got status %r' % (resp.status, ), resp) + exc.identity_url = result.normalized_uri + raise exc + result.content_type = resp.headers.get('content-type') + + result.response_text = resp.body + return result + + +def whereIsYadis(resp): + """Given a HTTPResponse, return the location of the Yadis document. + + May be the URL just retrieved, another URL, or None if no suitable URL can + be found. + + [non-blocking] + + @returns: str or None + """ + # Attempt to find out where to go to discover the document + # or if we already have it + content_type = resp.headers.get('content-type') + + # According to the spec, the content-type header must be an exact + # match, or else we have to look for an indirection. + if (content_type and + content_type.split(';', 1)[0].lower() == YADIS_CONTENT_TYPE): + return resp.final_url + else: + # Try the header + yadis_loc = resp.headers.get(YADIS_HEADER_NAME.lower()) + + if not yadis_loc: + # Parse as HTML if the header is missing. + # + # XXX: do we want to do something with content-type, like + # have a whitelist or a blacklist (for detecting that it's + # HTML)? + + # Decode body by encoding of file + content_type = content_type or '' + encoding = content_type.rsplit(';', 1) + if (len(encoding) == 2 and + encoding[1].strip().startswith('charset=')): + encoding = encoding[1].split('=', 1)[1].strip() + else: + encoding = 'utf-8' + + if isinstance(resp.body, bytes): + try: + content = resp.body.decode(encoding) + except UnicodeError: + # All right, the detected encoding has failed. Try with + # UTF-8 (even if there was no detected encoding and we've + # defaulted to UTF-8, it's not that expensive an operation) + try: + content = resp.body.decode('utf-8') + except UnicodeError: + # At this point the content cannot be decoded to a str + # using the detected encoding or falling back to utf-8, + # so we have to resort to replacing undecodable chars. + # This *will* result in broken content but there isn't + # anything else that can be done. + content = resp.body.decode(encoding, 'replace') + else: + content = resp.body + + try: + yadis_loc = findHTMLMeta(StringIO(content)) + except (MetaNotFound, UnicodeError): + # UnicodeError: Response body could not be encoded and xrds + # location could not be found before troubles occur. + pass + + return yadis_loc diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/etxrd.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/etxrd.py new file mode 100644 index 0000000000000000000000000000000000000000..85e739afa9476d91a0db776d7565516008353614 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/etxrd.py @@ -0,0 +1,318 @@ +# -*- test-case-name: yadis.test.test_etxrd -*- +""" +ElementTree interface to an XRD document. +""" + +__all__ = [ + 'nsTag', + 'mkXRDTag', + 'isXRDS', + 'parseXRDS', + 'getCanonicalID', + 'getYadisXRD', + 'getPriorityStrict', + 'getPriority', + 'prioSort', + 'iterServices', + 'expandService', + 'expandServices', +] + +import sys +import random +import functools + +from datetime import datetime +from time import strptime + +from openid.oidutil import importElementTree, importSafeElementTree + +ElementTree = importElementTree() +SafeElementTree = importSafeElementTree() + +from openid.yadis import xri + + +class XRDSError(Exception): + """An error with the XRDS document.""" + + # The exception that triggered this exception + reason = None + + +class XRDSFraud(XRDSError): + """Raised when there's an assertion in the XRDS that it does not have + the authority to make. + """ + + +def parseXRDS(text): + """Parse the given text as an XRDS document. + + @return: ElementTree containing an XRDS document + + @raises XRDSError: When there is a parse error or the document does + not contain an XRDS. + """ + try: + # lxml prefers to parse bytestrings, and occasionally chokes on a + # combination of text strings and declared XML encodings -- see + # https://github.com/necaris/python3-openid/issues/19 + # To avoid this, we ensure that the 'text' we're parsing is actually + # a bytestring + bytestring = text.encode('utf8') if isinstance(text, str) else text + element = SafeElementTree.XML(bytestring) + except (SystemExit, MemoryError, AssertionError, ImportError): + raise + except Exception as why: + exc = XRDSError('Error parsing document as XML') + exc.reason = why + raise exc + else: + tree = ElementTree.ElementTree(element) + if not isXRDS(tree): + raise XRDSError('Not an XRDS document') + + return tree + + +XRD_NS_2_0 = 'xri://$xrd*($v*2.0)' +XRDS_NS = 'xri://$xrds' + + +def nsTag(ns, t): + return '{%s}%s' % (ns, t) + + +def mkXRDTag(t): + """basestring -> basestring + + Create a tag name in the XRD 2.0 XML namespace suitable for using + with ElementTree + """ + return nsTag(XRD_NS_2_0, t) + + +def mkXRDSTag(t): + """basestring -> basestring + + Create a tag name in the XRDS XML namespace suitable for using + with ElementTree + """ + return nsTag(XRDS_NS, t) + + +# Tags that are used in Yadis documents +root_tag = mkXRDSTag('XRDS') +service_tag = mkXRDTag('Service') +xrd_tag = mkXRDTag('XRD') +type_tag = mkXRDTag('Type') +uri_tag = mkXRDTag('URI') +expires_tag = mkXRDTag('Expires') + +# Other XRD tags +canonicalID_tag = mkXRDTag('CanonicalID') + + +def isXRDS(xrd_tree): + """Is this document an XRDS document?""" + root = xrd_tree.getroot() + return root.tag == root_tag + + +def getYadisXRD(xrd_tree): + """Return the XRD element that should contain the Yadis services""" + xrd = None + + # for the side-effect of assigning the last one in the list to the + # xrd variable + for xrd in xrd_tree.findall(xrd_tag): + pass + + # There were no elements found, or else xrd would be set to the + # last one + if xrd is None: + raise XRDSError('No XRD present in tree') + + return xrd + + +def getXRDExpiration(xrd_element, default=None): + """Return the expiration date of this XRD element, or None if no + expiration was specified. + + @type xrd_element: ElementTree node + + @param default: The value to use as the expiration if no + expiration was specified in the XRD. + + @rtype: datetime.datetime + + @raises ValueError: If the xrd:Expires element is present, but its + contents are not formatted according to the specification. + """ + expires_element = xrd_element.find(expires_tag) + if expires_element is None: + return default + else: + expires_string = expires_element.text + + # Will raise ValueError if the string is not the expected format + expires_time = strptime(expires_string, "%Y-%m-%dT%H:%M:%SZ") + return datetime(*expires_time[0:6]) + + +def getCanonicalID(iname, xrd_tree): + """Return the CanonicalID from this XRDS document. + + @param iname: the XRI being resolved. + @type iname: unicode + + @param xrd_tree: The XRDS output from the resolver. + @type xrd_tree: ElementTree + + @returns: The XRI CanonicalID or None. + @returntype: unicode or None + """ + xrd_list = xrd_tree.findall(xrd_tag) + xrd_list.reverse() + + try: + canonicalID = xri.XRI(xrd_list[0].findall(canonicalID_tag)[0].text) + except IndexError: + return None + + childID = canonicalID.lower() + + for xrd in xrd_list[1:]: + parent_sought = childID.rsplit("!", 1)[0] + parent = xri.XRI(xrd.findtext(canonicalID_tag)) + if parent_sought != parent.lower(): + raise XRDSFraud("%r can not come from %s" % (childID, parent)) + + childID = parent_sought + + root = xri.rootAuthority(iname) + if not xri.providerIsAuthoritative(root, childID): + raise XRDSFraud("%r can not come from root %r" % (childID, root)) + + return canonicalID + + +@functools.total_ordering +class _Max(object): + """ + Value that compares greater than any other value. + + Should only be used as a singleton. Implemented for use as a + priority value for when a priority is not specified. + """ + + def __lt__(self, other): + return isinstance(other, self.__class__) + + def __eq__(self, other): + return isinstance(other, self.__class__) + + +Max = _Max() + + +def getPriorityStrict(element): + """Get the priority of this element. + + Raises ValueError if the value of the priority is invalid. If no + priority is specified, it returns a value that compares greater + than any other value. + """ + prio_str = element.get('priority') + if prio_str is not None: + prio_val = int(prio_str) + if prio_val >= 0: + return prio_val + else: + raise ValueError('Priority values must be non-negative integers') + + # Any errors in parsing the priority fall through to here + return Max + + +def getPriority(element): + """Get the priority of this element + + Returns Max if no priority is specified or the priority value is invalid. + """ + try: + return getPriorityStrict(element) + except ValueError: + return Max + + +def prioSort(elements): + """Sort a list of elements that have priority attributes""" + # Randomize the services before sorting so that equal priority + # elements are load-balanced. + random.shuffle(elements) + + sorted_elems = sorted(elements, key=getPriority) + return sorted_elems + + +def iterServices(xrd_tree): + """Return an iterable over the Service elements in the Yadis XRD + + sorted by priority""" + xrd = getYadisXRD(xrd_tree) + return prioSort(xrd.findall(service_tag)) + + +def sortedURIs(service_element): + """Given a Service element, return a list of the contents of all + URI tags in priority order.""" + return [ + uri_element.text + for uri_element in prioSort(service_element.findall(uri_tag)) + ] + + +def getTypeURIs(service_element): + """Given a Service element, return a list of the contents of all + Type tags""" + return [ + type_element.text for type_element in service_element.findall(type_tag) + ] + + +def expandService(service_element): + """Take a service element and expand it into an iterator of: + ([type_uri], uri, service_element) + """ + uris = sortedURIs(service_element) + if not uris: + uris = [None] + + expanded = [] + for uri in uris: + type_uris = getTypeURIs(service_element) + expanded.append((type_uris, uri, service_element)) + + return expanded + + +def expandServices(service_elements): + """Take a sorted iterator of service elements and expand it into a + sorted iterator of: + ([type_uri], uri, service_element) + + There may be more than one item in the resulting list for each + service element if there is more than one URI or type for a + service, but each triple will be unique. + + If there is no URI or Type for a Service element, it will not + appear in the result. + """ + expanded = [] + for service_element in service_elements: + expanded.extend(expandService(service_element)) + + return expanded diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/filters.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/filters.py new file mode 100644 index 0000000000000000000000000000000000000000..81bafee634420472de68b41306975616ab0fc50b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/filters.py @@ -0,0 +1,213 @@ +"""This module contains functions and classes used for extracting +endpoint information out of a Yadis XRD file using the ElementTree XML +parser. +""" + +__all__ = [ + 'BasicServiceEndpoint', + 'mkFilter', + 'IFilter', + 'TransformFilterMaker', + 'CompoundFilter', +] + +from openid.yadis.etxrd import expandService +try: + from collections.abc import Callable +except ImportError: + from collections import Callable + + +class BasicServiceEndpoint(object): + """Generic endpoint object that contains parsed service + information, as well as a reference to the service element from + which it was generated. If there is more than one xrd:Type or + xrd:URI in the xrd:Service, this object represents just one of + those pairs. + + This object can be used as a filter, because it implements + fromBasicServiceEndpoint. + + The simplest kind of filter you can write implements + fromBasicServiceEndpoint, which takes one of these objects. + """ + + def __init__(self, yadis_url, type_uris, uri, service_element): + self.type_uris = type_uris + self.yadis_url = yadis_url + self.uri = uri + self.service_element = service_element + + def matchTypes(self, type_uris): + """Query this endpoint to see if it has any of the given type + URIs. This is useful for implementing other endpoint classes + that e.g. need to check for the presence of multiple versions + of a single protocol. + + @param type_uris: The URIs that you wish to check + @type type_uris: iterable of str + + @return: all types that are in both in type_uris and + self.type_uris + """ + return [uri for uri in type_uris if uri in self.type_uris] + + def fromBasicServiceEndpoint(endpoint): + """Trivial transform from a basic endpoint to itself. This + method exists to allow BasicServiceEndpoint to be used as a + filter. + + If you are subclassing this object, re-implement this function. + + @param endpoint: An instance of BasicServiceEndpoint + @return: The object that was passed in, with no processing. + """ + return endpoint + + fromBasicServiceEndpoint = staticmethod(fromBasicServiceEndpoint) + + +class IFilter(object): + """Interface for Yadis filter objects. Other filter-like things + are convertable to this class.""" + + def getServiceEndpoints(self, yadis_url, service_element): + """Returns an iterator of endpoint objects""" + raise NotImplementedError + + +class TransformFilterMaker(object): + """Take a list of basic filters and makes a filter that transforms + the basic filter into a top-level filter. This is mostly useful + for the implementation of mkFilter, which should only be needed + for special cases or internal use by this library. + + This object is useful for creating simple filters for services + that use one URI and are specified by one Type (we expect most + Types will fit this paradigm). + + Creates a BasicServiceEndpoint object and apply the filter + functions to it until one of them returns a value. + """ + + def __init__(self, filter_functions): + """Initialize the filter maker's state + + @param filter_functions: The endpoint transformer functions to + apply to the basic endpoint. These are called in turn + until one of them does not return None, and the result of + that transformer is returned. + """ + self.filter_functions = filter_functions + + def getServiceEndpoints(self, yadis_url, service_element): + """Returns an iterator of endpoint objects produced by the + filter functions.""" + endpoints = [] + + # Do an expansion of the service element by xrd:Type and xrd:URI + for type_uris, uri, _ in expandService(service_element): + + # Create a basic endpoint object to represent this + # yadis_url, Service, Type, URI combination + endpoint = BasicServiceEndpoint(yadis_url, type_uris, uri, + service_element) + + e = self.applyFilters(endpoint) + if e is not None: + endpoints.append(e) + + return endpoints + + def applyFilters(self, endpoint): + """Apply filter functions to an endpoint until one of them + returns non-None.""" + for filter_function in self.filter_functions: + e = filter_function(endpoint) + if e is not None: + # Once one of the filters has returned an + # endpoint, do not apply any more. + return e + + return None + + +class CompoundFilter(object): + """Create a new filter that applies a set of filters to an endpoint + and collects their results. + """ + + def __init__(self, subfilters): + self.subfilters = subfilters + + def getServiceEndpoints(self, yadis_url, service_element): + """Generate all endpoint objects for all of the subfilters of + this filter and return their concatenation.""" + endpoints = [] + for subfilter in self.subfilters: + endpoints.extend( + subfilter.getServiceEndpoints(yadis_url, service_element)) + return endpoints + + +# Exception raised when something is not able to be turned into a filter +filter_type_error = TypeError( + 'Expected a filter, an endpoint, a callable or a list of any of these.') + + +def mkFilter(parts): + """Convert a filter-convertable thing into a filter + + @param parts: a filter, an endpoint, a callable, or a list of any of these. + """ + # Convert the parts into a list, and pass to mkCompoundFilter + if parts is None: + parts = [BasicServiceEndpoint] + + try: + parts = list(parts) + except TypeError: + return mkCompoundFilter([parts]) + else: + return mkCompoundFilter(parts) + + +def mkCompoundFilter(parts): + """Create a filter out of a list of filter-like things + + Used by mkFilter + + @param parts: list of filter, endpoint, callable or list of any of these + """ + # Separate into a list of callables and a list of filter objects + transformers = [] + filters = [] + for subfilter in parts: + try: + subfilter = list(subfilter) + except TypeError: + # If it's not an iterable + if hasattr(subfilter, 'getServiceEndpoints'): + # It's a full filter + filters.append(subfilter) + elif hasattr(subfilter, 'fromBasicServiceEndpoint'): + # It's an endpoint object, so put its endpoint + # conversion attribute into the list of endpoint + # transformers + transformers.append(subfilter.fromBasicServiceEndpoint) + elif isinstance(subfilter, Callable): + # It's a simple callable, so add it to the list of + # endpoint transformers + transformers.append(subfilter) + else: + raise filter_type_error + else: + filters.append(mkCompoundFilter(subfilter)) + + if transformers: + filters.append(TransformFilterMaker(transformers)) + + if len(filters) == 1: + return filters[0] + else: + return CompoundFilter(filters) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/manager.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/manager.py new file mode 100644 index 0000000000000000000000000000000000000000..9c9a042f6dd15c66249ffdc78c2a0406dda011c8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/manager.py @@ -0,0 +1,195 @@ +class YadisServiceManager(object): + """Holds the state of a list of selected Yadis services, managing + storing it in a session and iterating over the services in order.""" + + def __init__(self, starting_url, yadis_url, services, session_key): + # The URL that was used to initiate the Yadis protocol + self.starting_url = starting_url + + # The URL after following redirects (the identifier) + self.yadis_url = yadis_url + + # List of service elements + self.services = list(services) + + self.session_key = session_key + + # Reference to the current service object + self._current = None + + def __len__(self): + """How many untried services remain?""" + return len(self.services) + + def __iter__(self): + return self + + def __next__(self): + """Return the next service + + self.current() will continue to return that service until the + next call to this method.""" + try: + self._current = self.services.pop(0) + except IndexError: + raise StopIteration + else: + return self._current + + def current(self): + """Return the current service. + + Returns None if there are no services left. + """ + return self._current + + def forURL(self, url): + return url in [self.starting_url, self.yadis_url] + + def started(self): + """Has the first service been returned?""" + return self._current is not None + + def store(self, session): + """Store this object in the session, by its session key.""" + session[self.session_key] = self + + +class Discovery(object): + """State management for discovery. + + High-level usage pattern is to call .getNextService(discover) in + order to find the next available service for this user for this + session. Once a request completes, call .finish() to clean up the + session state. + + @ivar session: a dict-like object that stores state unique to the + requesting user-agent. This object must be able to store + serializable objects. + + @ivar url: the URL that is used to make the discovery request + + @ivar session_key_suffix: The suffix that will be used to identify + this object in the session object. + """ + + DEFAULT_SUFFIX = 'auth' + PREFIX = '_yadis_services_' + + def __init__(self, session, url, session_key_suffix=None): + """Initialize a discovery object""" + self.session = session + self.url = url + if session_key_suffix is None: + session_key_suffix = self.DEFAULT_SUFFIX + + self.session_key_suffix = session_key_suffix + + def getNextService(self, discover): + """Return the next authentication service for the pair of + user_input and session. This function handles fallback. + + + @param discover: a callable that takes a URL and returns a + list of services + + @type discover: str -> [service] + + + @return: the next available service + """ + manager = self.getManager() + if manager is not None and not manager: + self.destroyManager() + + if not manager: + yadis_url, services = discover(self.url) + manager = self.createManager(services, yadis_url) + + if manager: + service = next(manager) + manager.store(self.session) + else: + service = None + + return service + + def cleanup(self, force=False): + """Clean up Yadis-related services in the session and return + the most-recently-attempted service from the manager, if one + exists. + + @param force: True if the manager should be deleted regardless + of whether it's a manager for self.url. + + @return: current service endpoint object or None if there is + no current service + """ + manager = self.getManager(force=force) + if manager is not None: + service = manager.current() + self.destroyManager(force=force) + else: + service = None + + return service + + ### Lower-level methods + + def getSessionKey(self): + """Get the session key for this starting URL and suffix + + @return: The session key + @rtype: str + """ + return self.PREFIX + self.session_key_suffix + + def getManager(self, force=False): + """Extract the YadisServiceManager for this object's URL and + suffix from the session. + + @param force: True if the manager should be returned + regardless of whether it's a manager for self.url. + + @return: The current YadisServiceManager, if it's for this + URL, or else None + """ + manager = self.session.get(self.getSessionKey()) + if (manager is not None and (manager.forURL(self.url) or force)): + return manager + else: + return None + + def createManager(self, services, yadis_url=None): + """Create a new YadisService Manager for this starting URL and + suffix, and store it in the session. + + @raises KeyError: When I already have a manager. + + @return: A new YadisServiceManager or None + """ + key = self.getSessionKey() + if self.getManager(): + raise KeyError('There is already a %r manager for %r' % + (key, self.url)) + + if not services: + return None + + manager = YadisServiceManager(self.url, yadis_url, services, key) + manager.store(self.session) + return manager + + def destroyManager(self, force=False): + """Delete any YadisServiceManager with this starting URL and + suffix from the session. + + If there is no service manager or the service manager is for a + different URL, it silently does nothing. + + @param force: True if the manager should be deleted regardless + of whether it's a manager for self.url. + """ + if self.getManager(force=force) is not None: + key = self.getSessionKey() + del self.session[key] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/parsehtml.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/parsehtml.py new file mode 100644 index 0000000000000000000000000000000000000000..c78711196c8ad2d56af07d1f12b1b9d65b078d07 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/parsehtml.py @@ -0,0 +1,207 @@ +__all__ = ['findHTMLMeta', 'MetaNotFound'] + +from html.parser import HTMLParser +import html.entities +import re +import sys + +from openid.yadis.constants import YADIS_HEADER_NAME + +# Size of the chunks to search at a time (also the amount that gets +# read at a time) +CHUNK_SIZE = 1024 * 16 # 16 KB + + +class ParseDone(Exception): + """Exception to hold the URI that was located when the parse is + finished. If the parse finishes without finding the URI, set it to + None.""" + + +class MetaNotFound(Exception): + """Exception to hold the content of the page if we did not find + the appropriate <meta> tag""" + + +re_flags = re.IGNORECASE | re.UNICODE | re.VERBOSE +ent_pat = r''' +& + +(?: \#x (?P<hex> [a-f0-9]+ ) +| \# (?P<dec> \d+ ) +| (?P<word> \w+ ) +) + +;''' + +ent_re = re.compile(ent_pat, re_flags) + + +def substituteMO(mo): + if mo.lastgroup == 'hex': + codepoint = int(mo.group('hex'), 16) + elif mo.lastgroup == 'dec': + codepoint = int(mo.group('dec')) + else: + assert mo.lastgroup == 'word' + codepoint = html.entities.name2codepoint.get(mo.group('word')) + + if codepoint is None: + return mo.group() + else: + return chr(codepoint) + + +def substituteEntities(s): + return ent_re.sub(substituteMO, s) + + +class YadisHTMLParser(HTMLParser): + """Parser that finds a meta http-equiv tag in the head of a html + document. + + When feeding in data, if the tag is matched or it will never be + found, the parser will raise ParseDone with the uri as the first + attribute. + + Parsing state diagram + ===================== + + Any unlisted input does not affect the state:: + + 1, 2, 5 8 + +--------------------------+ +-+ + | | | | + 4 | 3 1, 2, 5, 7 v | v + TOP -> HTML -> HEAD ----------> TERMINATED + | | ^ | ^ ^ + | | 3 | | | | + | +------------+ +-> FOUND ------+ | + | 6 8 | + | 1, 2 | + +------------------------------------+ + + 1. any of </body>, </html>, </head> -> TERMINATE + 2. <body> -> TERMINATE + 3. <head> -> HEAD + 4. <html> -> HTML + 5. <html> -> TERMINATE + 6. <meta http-equiv='X-XRDS-Location'> -> FOUND + 7. <head> -> TERMINATE + 8. Any input -> TERMINATE + """ + TOP = 0 + HTML = 1 + HEAD = 2 + FOUND = 3 + TERMINATED = 4 + + def __init__(self): + if (sys.version_info.minor <= 2): + # Python 3.2 and below actually require the `strict` argument + # to `html.parser.HTMLParser` -- otherwise it's deprecated and + # we don't want to pass it + super(YadisHTMLParser, self).__init__(strict=False) + else: + super(YadisHTMLParser, self).__init__() + self.phase = self.TOP + + def _terminate(self): + self.phase = self.TERMINATED + raise ParseDone(None) + + def handle_endtag(self, tag): + # If we ever see an end of head, body, or html, bail out right away. + # [1] + if tag in ['head', 'body', 'html']: + self._terminate() + + def handle_starttag(self, tag, attrs): + # if we ever see a start body tag, bail out right away, since + # we want to prevent the meta tag from appearing in the body + # [2] + if tag == 'body': + self._terminate() + + if self.phase == self.TOP: + # At the top level, allow a html tag or a head tag to move + # to the head or html phase + if tag == 'head': + # [3] + self.phase = self.HEAD + elif tag == 'html': + # [4] + self.phase = self.HTML + + elif self.phase == self.HTML: + # if we are in the html tag, allow a head tag to move to + # the HEAD phase. If we get another html tag, then bail + # out + if tag == 'head': + # [3] + self.phase = self.HEAD + elif tag == 'html': + # [5] + self._terminate() + + elif self.phase == self.HEAD: + # If we are in the head phase, look for the appropriate + # meta tag. If we get a head or body tag, bail out. + if tag == 'meta': + attrs_d = dict(attrs) + http_equiv = attrs_d.get('http-equiv', '').lower() + if http_equiv == YADIS_HEADER_NAME.lower(): + raw_attr = attrs_d.get('content') + yadis_loc = substituteEntities(raw_attr) + # [6] + self.phase = self.FOUND + raise ParseDone(yadis_loc) + + elif tag in ('head', 'html'): + # [5], [7] + self._terminate() + + def feed(self, chars): + # [8] + if self.phase in (self.TERMINATED, self.FOUND): + self._terminate() + + return super(YadisHTMLParser, self).feed(chars) + + +def findHTMLMeta(stream): + """Look for a meta http-equiv tag with the YADIS header name. + + @param stream: Source of the html text + @type stream: Object that implements a read() method that works + like file.read + + @return: The URI from which to fetch the XRDS document + @rtype: str + + @raises MetaNotFound: raised with the content that was + searched as the first parameter. + """ + parser = YadisHTMLParser() + chunks = [] + + while 1: + chunk = stream.read(CHUNK_SIZE) + if not chunk: + # End of file + break + + chunks.append(chunk) + try: + parser.feed(chunk) + except ParseDone as why: + uri = why.args[0] + if uri is None: + # Parse finished, but we may need the rest of the file + chunks.append(stream.read()) + break + else: + return uri + + content = ''.join(chunks) + raise MetaNotFound(content) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/services.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/services.py new file mode 100644 index 0000000000000000000000000000000000000000..2092a9cae77db1d4d4a21e0fa9b878ba209e605e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/services.py @@ -0,0 +1,56 @@ +# -*- test-case-name: openid.test.test_services -*- + +from openid.yadis.filters import mkFilter +from openid.yadis.discover import discover, DiscoveryFailure +from openid.yadis.etxrd import parseXRDS, iterServices, XRDSError + + +def getServiceEndpoints(input_url, flt=None): + """Perform the Yadis protocol on the input URL and return an + iterable of resulting endpoint objects. + + @param flt: A filter object or something that is convertable to + a filter object (using mkFilter) that will be used to generate + endpoint objects. This defaults to generating BasicEndpoint + objects. + + @param input_url: The URL on which to perform the Yadis protocol + + @return: The normalized identity URL and an iterable of endpoint + objects generated by the filter function. + + @rtype: (str, [endpoint]) + + @raises DiscoveryFailure: when Yadis fails to obtain an XRDS document. + """ + result = discover(input_url) + try: + endpoints = applyFilter(result.normalized_uri, result.response_text, + flt) + except XRDSError as err: + raise DiscoveryFailure(str(err), None) + return (result.normalized_uri, endpoints) + + +def applyFilter(normalized_uri, xrd_data, flt=None): + """Generate an iterable of endpoint objects given this input data, + presumably from the result of performing the Yadis protocol. + + @param normalized_uri: The input URL, after following redirects, + as in the Yadis protocol. + + + @param xrd_data: The XML text the XRDS file fetched from the + normalized URI. + @type xrd_data: str + + """ + flt = mkFilter(flt) + et = parseXRDS(xrd_data) + + endpoints = [] + for service_element in iterServices(et): + endpoints.extend( + flt.getServiceEndpoints(normalized_uri, service_element)) + + return endpoints diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xri.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xri.py new file mode 100644 index 0000000000000000000000000000000000000000..621d30465c22118957c925ca23078ee44e93d599 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xri.py @@ -0,0 +1,122 @@ +# -*- test-case-name: openid.test.test_xri -*- +"""Utility functions for handling XRIs. + +@see: XRI Syntax v2.0 at the U{OASIS XRI Technical Committee<http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xri>} +""" + +import re +from functools import reduce + +from openid import codecutil # registers 'oid_percent_escape' encoding handler + +XRI_AUTHORITIES = ['!', '=', '@', '+', '$', '('] + + +def identifierScheme(identifier): + """Determine if this identifier is an XRI or URI. + + @returns: C{"XRI"} or C{"URI"} + """ + if identifier.startswith('xri://') or (identifier and + identifier[0] in XRI_AUTHORITIES): + return "XRI" + else: + return "URI" + + +def toIRINormal(xri): + """Transform an XRI to IRI-normal form.""" + if not xri.startswith('xri://'): + xri = 'xri://' + xri + return escapeForIRI(xri) + + +_xref_re = re.compile(r'\((.*?)\)') + + +def _escape_xref(xref_match): + """Escape things that need to be escaped if they're in a cross-reference. + """ + xref = xref_match.group() + xref = xref.replace('/', '%2F') + xref = xref.replace('?', '%3F') + xref = xref.replace('#', '%23') + return xref + + +def escapeForIRI(xri): + """Escape things that need to be escaped when transforming to an IRI.""" + xri = xri.replace('%', '%25') + xri = _xref_re.sub(_escape_xref, xri) + return xri + + +def toURINormal(xri): + """Transform an XRI to URI normal form.""" + return iriToURI(toIRINormal(xri)) + + +def iriToURI(iri): + """Transform an IRI to a URI by escaping unicode.""" + # According to RFC 3987, section 3.1, "Mapping of IRIs to URIs" + if isinstance(iri, bytes): + iri = str(iri, encoding="utf-8") + return iri.encode('ascii', errors='oid_percent_escape').decode() + + +def providerIsAuthoritative(providerID, canonicalID): + """Is this provider ID authoritative for this XRI? + + @returntype: bool + """ + # XXX: can't use rsplit until we require python >= 2.4. + lastbang = canonicalID.rindex('!') + parent = canonicalID[:lastbang] + return parent == providerID + + +def rootAuthority(xri): + """Return the root authority for an XRI. + + Example:: + + rootAuthority("xri://@example") == "xri://@" + + @type xri: unicode + @returntype: unicode + """ + if xri.startswith('xri://'): + xri = xri[6:] + authority = xri.split('/', 1)[0] + if authority[0] == '(': + # Cross-reference. + # XXX: This is incorrect if someone nests cross-references so there + # is another close-paren in there. Hopefully nobody does that + # before we have a real xriparse function. Hopefully nobody does + # that *ever*. + root = authority[:authority.index(')') + 1] + elif authority[0] in XRI_AUTHORITIES: + # Other XRI reference. + root = authority[0] + else: + # IRI reference. XXX: Can IRI authorities have segments? + segments = authority.split('!') + segments = reduce(list.__add__, [s.split('*') for s in segments]) + root = segments[0] + + return XRI(root) + + +def XRI(xri): + """An XRI object allowing comparison of XRI. + + Ideally, this would do full normalization and provide comparsion + operators as per XRI Syntax. Right now, it just does a bit of + canonicalization by ensuring the xri scheme is present. + + @param xri: an xri string + @type xri: unicode + """ + if not xri.startswith('xri://'): + xri = 'xri://' + xri + return xri diff --git a/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xrires.py b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xrires.py new file mode 100644 index 0000000000000000000000000000000000000000..a7140294f09b0bbd5d88690c2a8503fa78397447 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/openid/yadis/xrires.py @@ -0,0 +1,123 @@ +# -*- test-case-name: openid.test.test_xrires -*- +"""XRI resolution. +""" + +from urllib.parse import urlencode +from openid import fetchers +from openid.yadis import etxrd +from openid.yadis.xri import toURINormal +from openid.yadis.services import iterServices + +DEFAULT_PROXY = 'http://proxy.xri.net/' + + +class ProxyResolver(object): + """Python interface to a remote XRI proxy resolver. + """ + + def __init__(self, proxy_url=DEFAULT_PROXY): + self.proxy_url = proxy_url + + def queryURL(self, xri, service_type=None): + """Build a URL to query the proxy resolver. + + @param xri: An XRI to resolve. + @type xri: unicode + + @param service_type: The service type to resolve, if you desire + service endpoint selection. A service type is a URI. + @type service_type: str + + @returns: a URL + @returntype: str + """ + # Trim off the xri:// prefix. The proxy resolver didn't accept it + # when this code was written, but that may (or may not) change for + # XRI Resolution 2.0 Working Draft 11. + qxri = toURINormal(xri)[6:] + hxri = self.proxy_url + qxri + args = { + # XXX: If the proxy resolver will ensure that it doesn't return + # bogus CanonicalIDs (as per Steve's message of 15 Aug 2006 + # 11:13:42), then we could ask for application/xrd+xml instead, + # which would give us a bit less to process. + '_xrd_r': 'application/xrds+xml', + } + if service_type: + args['_xrd_t'] = service_type + else: + # Don't perform service endpoint selection. + args['_xrd_r'] += ';sep=false' + query = _appendArgs(hxri, args) + return query + + def query(self, xri, service_types): + """Resolve some services for an XRI. + + Note: I don't implement any service endpoint selection beyond what + the resolver I'm querying does, so the Services I return may well + include Services that were not of the types you asked for. + + May raise fetchers.HTTPFetchingError or L{etxrd.XRDSError} if + the fetching or parsing don't go so well. + + @param xri: An XRI to resolve. + @type xri: unicode + + @param service_types: A list of services types to query for. Service + types are URIs. + @type service_types: list of str + + @returns: tuple of (CanonicalID, Service elements) + @returntype: (unicode, list of C{ElementTree.Element}s) + """ + # FIXME: No test coverage! + services = [] + # Make a seperate request to the proxy resolver for each service + # type, as, if it is following Refs, it could return a different + # XRDS for each. + + canonicalID = None + + for service_type in service_types: + url = self.queryURL(xri, service_type) + response = fetchers.fetch(url) + if response.status not in (200, 206): + # XXX: sucks to fail silently. + # print "response not OK:", response + continue + et = etxrd.parseXRDS(response.body) + canonicalID = etxrd.getCanonicalID(xri, et) + some_services = list(iterServices(et)) + services.extend(some_services) + # TODO: + # * If we do get hits for multiple service_types, we're almost + # certainly going to have duplicated service entries and + # broken priority ordering. + return canonicalID, services + + +def _appendArgs(url, args): + """Append some arguments to an HTTP query. + """ + # to be merged with oidutil.appendArgs when we combine the projects. + if hasattr(args, 'items'): + args = list(args.items()) + args.sort() + + if len(args) == 0: + return url + + # According to XRI Resolution section "QXRI query parameters": + # + # """If the original QXRI had a null query component (only a leading + # question mark), or a query component consisting of only question + # marks, one additional leading question mark MUST be added when + # adding any XRI resolution parameters.""" + + if '?' in url.rstrip('?'): + sep = '&' + else: + sep = '?' + + return '%s%s%s' % (url, sep, urlencode(args)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ea215f2dbb279c7759384cce82de5fd320e75ccb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/LICENSE @@ -0,0 +1,27 @@ +pycparser -- A C parser in Python + +Copyright (c) 2008-2020, Eli Bendersky +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of Eli Bendersky nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..1d0fbd65144ffb486e9df01005c2f2cf1fdf2c63 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/METADATA @@ -0,0 +1,31 @@ +Metadata-Version: 2.1 +Name: pycparser +Version: 2.21 +Summary: C parser in Python +Home-page: https://github.com/eliben/pycparser +Author: Eli Bendersky +Author-email: eliben@gmail.com +Maintainer: Eli Bendersky +License: BSD +Platform: Cross Platform +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: BSD License +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 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* + + +pycparser is a complete parser of the C language, written in +pure Python using the PLY parsing library. +It parses C code into an AST and can serve as a front-end for +C compilers or analysis tools. + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..199f7793fa046ae278707c7b9f9b89eca37596e2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/RECORD @@ -0,0 +1,41 @@ +pycparser-2.21.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pycparser-2.21.dist-info/LICENSE,sha256=Pn3yW437ZYyakVAZMNTZQ7BQh6g0fH4rQyVhavU1BHs,1536 +pycparser-2.21.dist-info/METADATA,sha256=GvTEQA9yKj0nvP4mknfoGpMvjaJXCQjQANcQHrRrAxc,1108 +pycparser-2.21.dist-info/RECORD,, +pycparser-2.21.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +pycparser-2.21.dist-info/top_level.txt,sha256=c-lPcS74L_8KoH7IE6PQF5ofyirRQNV4VhkbSFIPeWM,10 +pycparser/__init__.py,sha256=WUEp5D0fuHBH9Q8c1fYvR2eKWfj-CNghLf2MMlQLI1I,2815 +pycparser/__pycache__/__init__.cpython-310.pyc,, +pycparser/__pycache__/_ast_gen.cpython-310.pyc,, +pycparser/__pycache__/_build_tables.cpython-310.pyc,, +pycparser/__pycache__/ast_transforms.cpython-310.pyc,, +pycparser/__pycache__/c_ast.cpython-310.pyc,, +pycparser/__pycache__/c_generator.cpython-310.pyc,, +pycparser/__pycache__/c_lexer.cpython-310.pyc,, +pycparser/__pycache__/c_parser.cpython-310.pyc,, +pycparser/__pycache__/lextab.cpython-310.pyc,, +pycparser/__pycache__/plyparser.cpython-310.pyc,, +pycparser/__pycache__/yacctab.cpython-310.pyc,, +pycparser/_ast_gen.py,sha256=0JRVnDW-Jw-3IjVlo8je9rbAcp6Ko7toHAnB5zi7h0Q,10555 +pycparser/_build_tables.py,sha256=oZCd3Plhq-vkV-QuEsaahcf-jUI6-HgKsrAL9gvFzuU,1039 +pycparser/_c_ast.cfg,sha256=ld5ezE9yzIJFIVAUfw7ezJSlMi4nXKNCzfmqjOyQTNo,4255 +pycparser/ast_transforms.py,sha256=GTMYlUgWmXd5wJVyovXY1qzzAqjxzCpVVg0664dKGBs,5691 +pycparser/c_ast.py,sha256=HWeOrfYdCY0u5XaYhE1i60uVyE3yMWdcxzECUX-DqJw,31445 +pycparser/c_generator.py,sha256=yi6Mcqxv88J5ue8k5-mVGxh3iJ37iD4QyF-sWcGjC-8,17772 +pycparser/c_lexer.py,sha256=xCpjIb6vOUebBJpdifidb08y7XgAsO3T1gNGXJT93-w,17167 +pycparser/c_parser.py,sha256=_8y3i52bL6SUK21KmEEl0qzHxe-0eZRzjZGkWg8gQ4A,73680 +pycparser/lextab.py,sha256=fIxBAHYRC418oKF52M7xb8_KMj3K-tHx0TzZiKwxjPM,8504 +pycparser/ply/__init__.py,sha256=q4s86QwRsYRa20L9ueSxfh-hPihpftBjDOvYa2_SS2Y,102 +pycparser/ply/__pycache__/__init__.cpython-310.pyc,, +pycparser/ply/__pycache__/cpp.cpython-310.pyc,, +pycparser/ply/__pycache__/ctokens.cpython-310.pyc,, +pycparser/ply/__pycache__/lex.cpython-310.pyc,, +pycparser/ply/__pycache__/yacc.cpython-310.pyc,, +pycparser/ply/__pycache__/ygen.cpython-310.pyc,, +pycparser/ply/cpp.py,sha256=UtC3ylTWp5_1MKA-PLCuwKQR8zSOnlGuGGIdzj8xS98,33282 +pycparser/ply/ctokens.py,sha256=MKksnN40TehPhgVfxCJhjj_BjL943apreABKYz-bl0Y,3177 +pycparser/ply/lex.py,sha256=7Qol57x702HZwjA3ZLp-84CUEWq1EehW-N67Wzghi-M,42918 +pycparser/ply/yacc.py,sha256=eatSDkRLgRr6X3-hoDk_SQQv065R0BdL2K7fQ54CgVM,137323 +pycparser/ply/ygen.py,sha256=2JYNeYtrPz1JzLSLO3d4GsS8zJU8jY_I_CR1VI9gWrA,2251 +pycparser/plyparser.py,sha256=8tLOoEytcapvWrr1JfCf7Dog-wulBtS1YrDs8S7JfMo,4875 +pycparser/yacctab.py,sha256=j_fVNIyDWDRVk7eWMqQtlBw2AwUSV5JTrtT58l7zis0,205652 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..ef99c6cf3283b50a273ac4c6d009a0aa85597070 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc1c9e101ad9ccd943b359338ef42c342ebc84a1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser-2.21.dist-info/top_level.txt @@ -0,0 +1 @@ +pycparser diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d82eb2d6fbafe9828a2281cebc335bd6c20fcbe5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__init__.py @@ -0,0 +1,90 @@ +#----------------------------------------------------------------- +# pycparser: __init__.py +# +# This package file exports some convenience functions for +# interacting with pycparser +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- +__all__ = ['c_lexer', 'c_parser', 'c_ast'] +__version__ = '2.21' + +import io +from subprocess import check_output +from .c_parser import CParser + + +def preprocess_file(filename, cpp_path='cpp', cpp_args=''): + """ Preprocess a file using cpp. + + filename: + Name of the file you want to preprocess. + + cpp_path: + cpp_args: + Refer to the documentation of parse_file for the meaning of these + arguments. + + When successful, returns the preprocessed file's contents. + Errors from cpp will be printed out. + """ + path_list = [cpp_path] + if isinstance(cpp_args, list): + path_list += cpp_args + elif cpp_args != '': + path_list += [cpp_args] + path_list += [filename] + + try: + # Note the use of universal_newlines to treat all newlines + # as \n for Python's purpose + text = check_output(path_list, universal_newlines=True) + except OSError as e: + raise RuntimeError("Unable to invoke 'cpp'. " + + 'Make sure its path was passed correctly\n' + + ('Original error: %s' % e)) + + return text + + +def parse_file(filename, use_cpp=False, cpp_path='cpp', cpp_args='', + parser=None): + """ Parse a C file using pycparser. + + filename: + Name of the file you want to parse. + + use_cpp: + Set to True if you want to execute the C pre-processor + on the file prior to parsing it. + + cpp_path: + If use_cpp is True, this is the path to 'cpp' on your + system. If no path is provided, it attempts to just + execute 'cpp', so it must be in your PATH. + + cpp_args: + If use_cpp is True, set this to the command line arguments strings + to cpp. Be careful with quotes - it's best to pass a raw string + (r'') here. For example: + r'-I../utils/fake_libc_include' + If several arguments are required, pass a list of strings. + + parser: + Optional parser object to be used instead of the default CParser + + When successful, an AST is returned. ParseError can be + thrown if the file doesn't parse successfully. + + Errors from cpp will be printed out. + """ + if use_cpp: + text = preprocess_file(filename, cpp_path, cpp_args) + else: + with io.open(filename) as f: + text = f.read() + + if parser is None: + parser = CParser() + return parser.parse(text, filename) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75f4d26f86a75ee64c435a83af2233f3e71dd532 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..486a6c5d53e831800b598d9c950eac7e627db141 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f12cd1ef3492213705650e74565537219ef705b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f869cc882184487e247ed1f35dfaedd9dda4a9b6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f89c20091e6257237a99b7663a724139d30b64f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2d89011f132c13b2c33307f8fd7bcb41ebef864 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d733e0f7b00fbb3e5859e61ed03875fedb87e095 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..710a9888a3b74ad41d69c388d532e9f5b445a329 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f7dd540ae94b9550a7ea2f72d99c7dd80085e40 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b039d9de1b0e91527b9ee60e99607f636d34274 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..388618d18d1602cfc36f437214b391f904825c31 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_ast_gen.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_ast_gen.py new file mode 100644 index 0000000000000000000000000000000000000000..0f7d330ba694ec21e278264b90bfbe483ca2b7d3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_ast_gen.py @@ -0,0 +1,336 @@ +#----------------------------------------------------------------- +# _ast_gen.py +# +# Generates the AST Node classes from a specification given in +# a configuration file +# +# The design of this module was inspired by astgen.py from the +# Python 2.5 code-base. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- +from string import Template + + +class ASTCodeGenerator(object): + def __init__(self, cfg_filename='_c_ast.cfg'): + """ Initialize the code generator from a configuration + file. + """ + self.cfg_filename = cfg_filename + self.node_cfg = [NodeCfg(name, contents) + for (name, contents) in self.parse_cfgfile(cfg_filename)] + + def generate(self, file=None): + """ Generates the code into file, an open file buffer. + """ + src = Template(_PROLOGUE_COMMENT).substitute( + cfg_filename=self.cfg_filename) + + src += _PROLOGUE_CODE + for node_cfg in self.node_cfg: + src += node_cfg.generate_source() + '\n\n' + + file.write(src) + + def parse_cfgfile(self, filename): + """ Parse the configuration file and yield pairs of + (name, contents) for each node. + """ + with open(filename, "r") as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + colon_i = line.find(':') + lbracket_i = line.find('[') + rbracket_i = line.find(']') + if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i: + raise RuntimeError("Invalid line in %s:\n%s\n" % (filename, line)) + + name = line[:colon_i] + val = line[lbracket_i + 1:rbracket_i] + vallist = [v.strip() for v in val.split(',')] if val else [] + yield name, vallist + + +class NodeCfg(object): + """ Node configuration. + + name: node name + contents: a list of contents - attributes and child nodes + See comment at the top of the configuration file for details. + """ + + def __init__(self, name, contents): + self.name = name + self.all_entries = [] + self.attr = [] + self.child = [] + self.seq_child = [] + + for entry in contents: + clean_entry = entry.rstrip('*') + self.all_entries.append(clean_entry) + + if entry.endswith('**'): + self.seq_child.append(clean_entry) + elif entry.endswith('*'): + self.child.append(clean_entry) + else: + self.attr.append(entry) + + def generate_source(self): + src = self._gen_init() + src += '\n' + self._gen_children() + src += '\n' + self._gen_iter() + src += '\n' + self._gen_attr_names() + return src + + def _gen_init(self): + src = "class %s(Node):\n" % self.name + + if self.all_entries: + args = ', '.join(self.all_entries) + slots = ', '.join("'{0}'".format(e) for e in self.all_entries) + slots += ", 'coord', '__weakref__'" + arglist = '(self, %s, coord=None)' % args + else: + slots = "'coord', '__weakref__'" + arglist = '(self, coord=None)' + + src += " __slots__ = (%s)\n" % slots + src += " def __init__%s:\n" % arglist + + for name in self.all_entries + ['coord']: + src += " self.%s = %s\n" % (name, name) + + return src + + def _gen_children(self): + src = ' def children(self):\n' + + if self.all_entries: + src += ' nodelist = []\n' + + for child in self.child: + src += ( + ' if self.%(child)s is not None:' + + ' nodelist.append(("%(child)s", self.%(child)s))\n') % ( + dict(child=child)) + + for seq_child in self.seq_child: + src += ( + ' for i, child in enumerate(self.%(child)s or []):\n' + ' nodelist.append(("%(child)s[%%d]" %% i, child))\n') % ( + dict(child=seq_child)) + + src += ' return tuple(nodelist)\n' + else: + src += ' return ()\n' + + return src + + def _gen_iter(self): + src = ' def __iter__(self):\n' + + if self.all_entries: + for child in self.child: + src += ( + ' if self.%(child)s is not None:\n' + + ' yield self.%(child)s\n') % (dict(child=child)) + + for seq_child in self.seq_child: + src += ( + ' for child in (self.%(child)s or []):\n' + ' yield child\n') % (dict(child=seq_child)) + + if not (self.child or self.seq_child): + # Empty generator + src += ( + ' return\n' + + ' yield\n') + else: + # Empty generator + src += ( + ' return\n' + + ' yield\n') + + return src + + def _gen_attr_names(self): + src = " attr_names = (" + ''.join("%r, " % nm for nm in self.attr) + ')' + return src + + +_PROLOGUE_COMMENT = \ +r'''#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# $cfg_filename +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +''' + +_PROLOGUE_CODE = r''' +import sys + +def _repr(obj): + """ + Get the representation of an object, with dedicated pprint-like format for lists. + """ + if isinstance(obj, list): + return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]' + else: + return repr(obj) + +class Node(object): + __slots__ = () + """ Abstract base class for AST nodes. + """ + def __repr__(self): + """ Generates a python representation of the current node + """ + result = self.__class__.__name__ + '(' + + indent = '' + separator = '' + for name in self.__slots__[:-2]: + result += separator + result += indent + result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__))))) + + separator = ',' + indent = '\n ' + (' ' * len(self.__class__.__name__)) + + result += indent + ')' + + return result + + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, nodenames=False, showcoord=False, _my_node_name=None): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + buf: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + nodenames: + True if you want to see the actual node names + within their parents. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + lead = ' ' * offset + if nodenames and _my_node_name is not None: + buf.write(lead + self.__class__.__name__+ ' <' + _my_node_name + '>: ') + else: + buf.write(lead + self.__class__.__name__+ ': ') + + if self.attr_names: + if attrnames: + nvlist = [(n, getattr(self,n)) for n in self.attr_names] + attrstr = ', '.join('%s=%s' % nv for nv in nvlist) + else: + vlist = [getattr(self, n) for n in self.attr_names] + attrstr = ', '.join('%s' % v for v in vlist) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for (child_name, child) in self.children(): + child.show( + buf, + offset=offset + 2, + attrnames=attrnames, + nodenames=nodenames, + showcoord=showcoord, + _my_node_name=child_name) + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + + _method_cache = None + + def visit(self, node): + """ Visit a node. + """ + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node: + self.visit(c) + +''' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_build_tables.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_build_tables.py new file mode 100644 index 0000000000000000000000000000000000000000..958381ad0f2927aff0253a8516c3bc76d00760d6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_build_tables.py @@ -0,0 +1,37 @@ +#----------------------------------------------------------------- +# pycparser: _build_tables.py +# +# A dummy for generating the lexing/parsing tables and and +# compiling them into .pyc for faster execution in optimized mode. +# Also generates AST code from the configuration file. +# Should be called from the pycparser directory. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +# Insert '.' and '..' as first entries to the search path for modules. +# Restricted environments like embeddable python do not include the +# current working directory on startup. +import sys +sys.path[0:0] = ['.', '..'] + +# Generate c_ast.py +from _ast_gen import ASTCodeGenerator +ast_gen = ASTCodeGenerator('_c_ast.cfg') +ast_gen.generate(open('c_ast.py', 'w')) + +from pycparser import c_parser + +# Generates the tables +# +c_parser.CParser( + lex_optimize=True, + yacc_debug=False, + yacc_optimize=True) + +# Load to compile into .pyc +# +import lextab +import yacctab +import c_ast diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_c_ast.cfg b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_c_ast.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0626533e8adf517da897ec047c8deb6ad41c38c9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/_c_ast.cfg @@ -0,0 +1,195 @@ +#----------------------------------------------------------------- +# pycparser: _c_ast.cfg +# +# Defines the AST Node classes used in pycparser. +# +# Each entry is a Node sub-class name, listing the attributes +# and child nodes of the class: +# <name>* - a child node +# <name>** - a sequence of child nodes +# <name> - an attribute +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +# ArrayDecl is a nested declaration of an array with the given type. +# dim: the dimension (for example, constant 42) +# dim_quals: list of dimension qualifiers, to support C99's allowing 'const' +# and 'static' within the array dimension in function declarations. +ArrayDecl: [type*, dim*, dim_quals] + +ArrayRef: [name*, subscript*] + +# op: =, +=, /= etc. +# +Assignment: [op, lvalue*, rvalue*] + +Alignas: [alignment*] + +BinaryOp: [op, left*, right*] + +Break: [] + +Case: [expr*, stmts**] + +Cast: [to_type*, expr*] + +# Compound statement in C99 is a list of block items (declarations or +# statements). +# +Compound: [block_items**] + +# Compound literal (anonymous aggregate) for C99. +# (type-name) {initializer_list} +# type: the typename +# init: InitList for the initializer list +# +CompoundLiteral: [type*, init*] + +# type: int, char, float, string, etc. +# +Constant: [type, value] + +Continue: [] + +# name: the variable being declared +# quals: list of qualifiers (const, volatile) +# funcspec: list function specifiers (i.e. inline in C99) +# storage: list of storage specifiers (extern, register, etc.) +# type: declaration type (probably nested with all the modifiers) +# init: initialization value, or None +# bitsize: bit field size, or None +# +Decl: [name, quals, align, storage, funcspec, type*, init*, bitsize*] + +DeclList: [decls**] + +Default: [stmts**] + +DoWhile: [cond*, stmt*] + +# Represents the ellipsis (...) parameter in a function +# declaration +# +EllipsisParam: [] + +# An empty statement (a semicolon ';' on its own) +# +EmptyStatement: [] + +# Enumeration type specifier +# name: an optional ID +# values: an EnumeratorList +# +Enum: [name, values*] + +# A name/value pair for enumeration values +# +Enumerator: [name, value*] + +# A list of enumerators +# +EnumeratorList: [enumerators**] + +# A list of expressions separated by the comma operator. +# +ExprList: [exprs**] + +# This is the top of the AST, representing a single C file (a +# translation unit in K&R jargon). It contains a list of +# "external-declaration"s, which is either declarations (Decl), +# Typedef or function definitions (FuncDef). +# +FileAST: [ext**] + +# for (init; cond; next) stmt +# +For: [init*, cond*, next*, stmt*] + +# name: Id +# args: ExprList +# +FuncCall: [name*, args*] + +# type <decl>(args) +# +FuncDecl: [args*, type*] + +# Function definition: a declarator for the function name and +# a body, which is a compound statement. +# There's an optional list of parameter declarations for old +# K&R-style definitions +# +FuncDef: [decl*, param_decls**, body*] + +Goto: [name] + +ID: [name] + +# Holder for types that are a simple identifier (e.g. the built +# ins void, char etc. and typedef-defined types) +# +IdentifierType: [names] + +If: [cond*, iftrue*, iffalse*] + +# An initialization list used for compound literals. +# +InitList: [exprs**] + +Label: [name, stmt*] + +# A named initializer for C99. +# The name of a NamedInitializer is a sequence of Nodes, because +# names can be hierarchical and contain constant expressions. +# +NamedInitializer: [name**, expr*] + +# a list of comma separated function parameter declarations +# +ParamList: [params**] + +PtrDecl: [quals, type*] + +Return: [expr*] + +StaticAssert: [cond*, message*] + +# name: struct tag name +# decls: declaration of members +# +Struct: [name, decls**] + +# type: . or -> +# name.field or name->field +# +StructRef: [name*, type, field*] + +Switch: [cond*, stmt*] + +# cond ? iftrue : iffalse +# +TernaryOp: [cond*, iftrue*, iffalse*] + +# A base type declaration +# +TypeDecl: [declname, quals, align, type*] + +# A typedef declaration. +# Very similar to Decl, but without some attributes +# +Typedef: [name, quals, storage, type*] + +Typename: [name, quals, align, type*] + +UnaryOp: [op, expr*] + +# name: union tag name +# decls: declaration of members +# +Union: [name, decls**] + +While: [cond*, stmt*] + +Pragma: [string] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ast_transforms.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ast_transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..367dcf54c57db47429fae8a67325237e7c048e17 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ast_transforms.py @@ -0,0 +1,164 @@ +#------------------------------------------------------------------------------ +# pycparser: ast_transforms.py +# +# Some utilities used by the parser to create a friendlier AST. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#------------------------------------------------------------------------------ + +from . import c_ast + + +def fix_switch_cases(switch_node): + """ The 'case' statements in a 'switch' come out of parsing with one + child node, so subsequent statements are just tucked to the parent + Compound. Additionally, consecutive (fall-through) case statements + come out messy. This is a peculiarity of the C grammar. The following: + + switch (myvar) { + case 10: + k = 10; + p = k + 1; + return 10; + case 20: + case 30: + return 20; + default: + break; + } + + Creates this tree (pseudo-dump): + + Switch + ID: myvar + Compound: + Case 10: + k = 10 + p = k + 1 + return 10 + Case 20: + Case 30: + return 20 + Default: + break + + The goal of this transform is to fix this mess, turning it into the + following: + + Switch + ID: myvar + Compound: + Case 10: + k = 10 + p = k + 1 + return 10 + Case 20: + Case 30: + return 20 + Default: + break + + A fixed AST node is returned. The argument may be modified. + """ + assert isinstance(switch_node, c_ast.Switch) + if not isinstance(switch_node.stmt, c_ast.Compound): + return switch_node + + # The new Compound child for the Switch, which will collect children in the + # correct order + new_compound = c_ast.Compound([], switch_node.stmt.coord) + + # The last Case/Default node + last_case = None + + # Goes over the children of the Compound below the Switch, adding them + # either directly below new_compound or below the last Case as appropriate + # (for `switch(cond) {}`, block_items would have been None) + for child in (switch_node.stmt.block_items or []): + if isinstance(child, (c_ast.Case, c_ast.Default)): + # If it's a Case/Default: + # 1. Add it to the Compound and mark as "last case" + # 2. If its immediate child is also a Case or Default, promote it + # to a sibling. + new_compound.block_items.append(child) + _extract_nested_case(child, new_compound.block_items) + last_case = new_compound.block_items[-1] + else: + # Other statements are added as children to the last case, if it + # exists. + if last_case is None: + new_compound.block_items.append(child) + else: + last_case.stmts.append(child) + + switch_node.stmt = new_compound + return switch_node + + +def _extract_nested_case(case_node, stmts_list): + """ Recursively extract consecutive Case statements that are made nested + by the parser and add them to the stmts_list. + """ + if isinstance(case_node.stmts[0], (c_ast.Case, c_ast.Default)): + stmts_list.append(case_node.stmts.pop()) + _extract_nested_case(stmts_list[-1], stmts_list) + + +def fix_atomic_specifiers(decl): + """ Atomic specifiers like _Atomic(type) are unusually structured, + conferring a qualifier upon the contained type. + + This function fixes a decl with atomic specifiers to have a sane AST + structure, by removing spurious Typename->TypeDecl pairs and attaching + the _Atomic qualifier in the right place. + """ + # There can be multiple levels of _Atomic in a decl; fix them until a + # fixed point is reached. + while True: + decl, found = _fix_atomic_specifiers_once(decl) + if not found: + break + + # Make sure to add an _Atomic qual on the topmost decl if needed. Also + # restore the declname on the innermost TypeDecl (it gets placed in the + # wrong place during construction). + typ = decl + while not isinstance(typ, c_ast.TypeDecl): + try: + typ = typ.type + except AttributeError: + return decl + if '_Atomic' in typ.quals and '_Atomic' not in decl.quals: + decl.quals.append('_Atomic') + if typ.declname is None: + typ.declname = decl.name + + return decl + + +def _fix_atomic_specifiers_once(decl): + """ Performs one 'fix' round of atomic specifiers. + Returns (modified_decl, found) where found is True iff a fix was made. + """ + parent = decl + grandparent = None + node = decl.type + while node is not None: + if isinstance(node, c_ast.Typename) and '_Atomic' in node.quals: + break + try: + grandparent = parent + parent = node + node = node.type + except AttributeError: + # If we've reached a node without a `type` field, it means we won't + # find what we're looking for at this point; give up the search + # and return the original decl unmodified. + return decl, False + + assert isinstance(parent, c_ast.TypeDecl) + grandparent.type = node.type + if '_Atomic' not in node.type.quals: + node.type.quals.append('_Atomic') + return decl, True diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_ast.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_ast.py new file mode 100644 index 0000000000000000000000000000000000000000..6575a2ad395a3fd43c44e296b010e6b33c7eefd0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_ast.py @@ -0,0 +1,1125 @@ +#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# _c_ast.cfg +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + + +import sys + +def _repr(obj): + """ + Get the representation of an object, with dedicated pprint-like format for lists. + """ + if isinstance(obj, list): + return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]' + else: + return repr(obj) + +class Node(object): + __slots__ = () + """ Abstract base class for AST nodes. + """ + def __repr__(self): + """ Generates a python representation of the current node + """ + result = self.__class__.__name__ + '(' + + indent = '' + separator = '' + for name in self.__slots__[:-2]: + result += separator + result += indent + result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__))))) + + separator = ',' + indent = '\n ' + (' ' * len(self.__class__.__name__)) + + result += indent + ')' + + return result + + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, nodenames=False, showcoord=False, _my_node_name=None): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + buf: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + nodenames: + True if you want to see the actual node names + within their parents. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + lead = ' ' * offset + if nodenames and _my_node_name is not None: + buf.write(lead + self.__class__.__name__+ ' <' + _my_node_name + '>: ') + else: + buf.write(lead + self.__class__.__name__+ ': ') + + if self.attr_names: + if attrnames: + nvlist = [(n, getattr(self,n)) for n in self.attr_names] + attrstr = ', '.join('%s=%s' % nv for nv in nvlist) + else: + vlist = [getattr(self, n) for n in self.attr_names] + attrstr = ', '.join('%s' % v for v in vlist) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for (child_name, child) in self.children(): + child.show( + buf, + offset=offset + 2, + attrnames=attrnames, + nodenames=nodenames, + showcoord=showcoord, + _my_node_name=child_name) + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + + _method_cache = None + + def visit(self, node): + """ Visit a node. + """ + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node: + self.visit(c) + +class ArrayDecl(Node): + __slots__ = ('type', 'dim', 'dim_quals', 'coord', '__weakref__') + def __init__(self, type, dim, dim_quals, coord=None): + self.type = type + self.dim = dim + self.dim_quals = dim_quals + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + if self.dim is not None: nodelist.append(("dim", self.dim)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.dim is not None: + yield self.dim + + attr_names = ('dim_quals', ) + +class ArrayRef(Node): + __slots__ = ('name', 'subscript', 'coord', '__weakref__') + def __init__(self, name, subscript, coord=None): + self.name = name + self.subscript = subscript + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(("name", self.name)) + if self.subscript is not None: nodelist.append(("subscript", self.subscript)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.subscript is not None: + yield self.subscript + + attr_names = () + +class Assignment(Node): + __slots__ = ('op', 'lvalue', 'rvalue', 'coord', '__weakref__') + def __init__(self, op, lvalue, rvalue, coord=None): + self.op = op + self.lvalue = lvalue + self.rvalue = rvalue + self.coord = coord + + def children(self): + nodelist = [] + if self.lvalue is not None: nodelist.append(("lvalue", self.lvalue)) + if self.rvalue is not None: nodelist.append(("rvalue", self.rvalue)) + return tuple(nodelist) + + def __iter__(self): + if self.lvalue is not None: + yield self.lvalue + if self.rvalue is not None: + yield self.rvalue + + attr_names = ('op', ) + +class Alignas(Node): + __slots__ = ('alignment', 'coord', '__weakref__') + def __init__(self, alignment, coord=None): + self.alignment = alignment + self.coord = coord + + def children(self): + nodelist = [] + if self.alignment is not None: nodelist.append(("alignment", self.alignment)) + return tuple(nodelist) + + def __iter__(self): + if self.alignment is not None: + yield self.alignment + + attr_names = () + +class BinaryOp(Node): + __slots__ = ('op', 'left', 'right', 'coord', '__weakref__') + def __init__(self, op, left, right, coord=None): + self.op = op + self.left = left + self.right = right + self.coord = coord + + def children(self): + nodelist = [] + if self.left is not None: nodelist.append(("left", self.left)) + if self.right is not None: nodelist.append(("right", self.right)) + return tuple(nodelist) + + def __iter__(self): + if self.left is not None: + yield self.left + if self.right is not None: + yield self.right + + attr_names = ('op', ) + +class Break(Node): + __slots__ = ('coord', '__weakref__') + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + +class Case(Node): + __slots__ = ('expr', 'stmts', 'coord', '__weakref__') + def __init__(self, expr, stmts, coord=None): + self.expr = expr + self.stmts = stmts + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(("expr", self.expr)) + for i, child in enumerate(self.stmts or []): + nodelist.append(("stmts[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + for child in (self.stmts or []): + yield child + + attr_names = () + +class Cast(Node): + __slots__ = ('to_type', 'expr', 'coord', '__weakref__') + def __init__(self, to_type, expr, coord=None): + self.to_type = to_type + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.to_type is not None: nodelist.append(("to_type", self.to_type)) + if self.expr is not None: nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.to_type is not None: + yield self.to_type + if self.expr is not None: + yield self.expr + + attr_names = () + +class Compound(Node): + __slots__ = ('block_items', 'coord', '__weakref__') + def __init__(self, block_items, coord=None): + self.block_items = block_items + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.block_items or []): + nodelist.append(("block_items[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.block_items or []): + yield child + + attr_names = () + +class CompoundLiteral(Node): + __slots__ = ('type', 'init', 'coord', '__weakref__') + def __init__(self, type, init, coord=None): + self.type = type + self.init = init + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + if self.init is not None: nodelist.append(("init", self.init)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.init is not None: + yield self.init + + attr_names = () + +class Constant(Node): + __slots__ = ('type', 'value', 'coord', '__weakref__') + def __init__(self, type, value, coord=None): + self.type = type + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ('type', 'value', ) + +class Continue(Node): + __slots__ = ('coord', '__weakref__') + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + +class Decl(Node): + __slots__ = ('name', 'quals', 'align', 'storage', 'funcspec', 'type', 'init', 'bitsize', 'coord', '__weakref__') + def __init__(self, name, quals, align, storage, funcspec, type, init, bitsize, coord=None): + self.name = name + self.quals = quals + self.align = align + self.storage = storage + self.funcspec = funcspec + self.type = type + self.init = init + self.bitsize = bitsize + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + if self.init is not None: nodelist.append(("init", self.init)) + if self.bitsize is not None: nodelist.append(("bitsize", self.bitsize)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.init is not None: + yield self.init + if self.bitsize is not None: + yield self.bitsize + + attr_names = ('name', 'quals', 'align', 'storage', 'funcspec', ) + +class DeclList(Node): + __slots__ = ('decls', 'coord', '__weakref__') + def __init__(self, decls, coord=None): + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append(("decls[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.decls or []): + yield child + + attr_names = () + +class Default(Node): + __slots__ = ('stmts', 'coord', '__weakref__') + def __init__(self, stmts, coord=None): + self.stmts = stmts + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.stmts or []): + nodelist.append(("stmts[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.stmts or []): + yield child + + attr_names = () + +class DoWhile(Node): + __slots__ = ('cond', 'stmt', 'coord', '__weakref__') + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + +class EllipsisParam(Node): + __slots__ = ('coord', '__weakref__') + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + +class EmptyStatement(Node): + __slots__ = ('coord', '__weakref__') + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + +class Enum(Node): + __slots__ = ('name', 'values', 'coord', '__weakref__') + def __init__(self, name, values, coord=None): + self.name = name + self.values = values + self.coord = coord + + def children(self): + nodelist = [] + if self.values is not None: nodelist.append(("values", self.values)) + return tuple(nodelist) + + def __iter__(self): + if self.values is not None: + yield self.values + + attr_names = ('name', ) + +class Enumerator(Node): + __slots__ = ('name', 'value', 'coord', '__weakref__') + def __init__(self, name, value, coord=None): + self.name = name + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + if self.value is not None: nodelist.append(("value", self.value)) + return tuple(nodelist) + + def __iter__(self): + if self.value is not None: + yield self.value + + attr_names = ('name', ) + +class EnumeratorList(Node): + __slots__ = ('enumerators', 'coord', '__weakref__') + def __init__(self, enumerators, coord=None): + self.enumerators = enumerators + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.enumerators or []): + nodelist.append(("enumerators[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.enumerators or []): + yield child + + attr_names = () + +class ExprList(Node): + __slots__ = ('exprs', 'coord', '__weakref__') + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.exprs or []): + nodelist.append(("exprs[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.exprs or []): + yield child + + attr_names = () + +class FileAST(Node): + __slots__ = ('ext', 'coord', '__weakref__') + def __init__(self, ext, coord=None): + self.ext = ext + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.ext or []): + nodelist.append(("ext[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.ext or []): + yield child + + attr_names = () + +class For(Node): + __slots__ = ('init', 'cond', 'next', 'stmt', 'coord', '__weakref__') + def __init__(self, init, cond, next, stmt, coord=None): + self.init = init + self.cond = cond + self.next = next + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.init is not None: nodelist.append(("init", self.init)) + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.next is not None: nodelist.append(("next", self.next)) + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.init is not None: + yield self.init + if self.cond is not None: + yield self.cond + if self.next is not None: + yield self.next + if self.stmt is not None: + yield self.stmt + + attr_names = () + +class FuncCall(Node): + __slots__ = ('name', 'args', 'coord', '__weakref__') + def __init__(self, name, args, coord=None): + self.name = name + self.args = args + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(("name", self.name)) + if self.args is not None: nodelist.append(("args", self.args)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.args is not None: + yield self.args + + attr_names = () + +class FuncDecl(Node): + __slots__ = ('args', 'type', 'coord', '__weakref__') + def __init__(self, args, type, coord=None): + self.args = args + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.args is not None: nodelist.append(("args", self.args)) + if self.type is not None: nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.args is not None: + yield self.args + if self.type is not None: + yield self.type + + attr_names = () + +class FuncDef(Node): + __slots__ = ('decl', 'param_decls', 'body', 'coord', '__weakref__') + def __init__(self, decl, param_decls, body, coord=None): + self.decl = decl + self.param_decls = param_decls + self.body = body + self.coord = coord + + def children(self): + nodelist = [] + if self.decl is not None: nodelist.append(("decl", self.decl)) + if self.body is not None: nodelist.append(("body", self.body)) + for i, child in enumerate(self.param_decls or []): + nodelist.append(("param_decls[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + if self.decl is not None: + yield self.decl + if self.body is not None: + yield self.body + for child in (self.param_decls or []): + yield child + + attr_names = () + +class Goto(Node): + __slots__ = ('name', 'coord', '__weakref__') + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ('name', ) + +class ID(Node): + __slots__ = ('name', 'coord', '__weakref__') + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ('name', ) + +class IdentifierType(Node): + __slots__ = ('names', 'coord', '__weakref__') + def __init__(self, names, coord=None): + self.names = names + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ('names', ) + +class If(Node): + __slots__ = ('cond', 'iftrue', 'iffalse', 'coord', '__weakref__') + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.iftrue is not None: nodelist.append(("iftrue", self.iftrue)) + if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.iftrue is not None: + yield self.iftrue + if self.iffalse is not None: + yield self.iffalse + + attr_names = () + +class InitList(Node): + __slots__ = ('exprs', 'coord', '__weakref__') + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.exprs or []): + nodelist.append(("exprs[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.exprs or []): + yield child + + attr_names = () + +class Label(Node): + __slots__ = ('name', 'stmt', 'coord', '__weakref__') + def __init__(self, name, stmt, coord=None): + self.name = name + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.stmt is not None: + yield self.stmt + + attr_names = ('name', ) + +class NamedInitializer(Node): + __slots__ = ('name', 'expr', 'coord', '__weakref__') + def __init__(self, name, expr, coord=None): + self.name = name + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(("expr", self.expr)) + for i, child in enumerate(self.name or []): + nodelist.append(("name[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + for child in (self.name or []): + yield child + + attr_names = () + +class ParamList(Node): + __slots__ = ('params', 'coord', '__weakref__') + def __init__(self, params, coord=None): + self.params = params + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.params or []): + nodelist.append(("params[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.params or []): + yield child + + attr_names = () + +class PtrDecl(Node): + __slots__ = ('quals', 'type', 'coord', '__weakref__') + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ('quals', ) + +class Return(Node): + __slots__ = ('expr', 'coord', '__weakref__') + def __init__(self, expr, coord=None): + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + + attr_names = () + +class StaticAssert(Node): + __slots__ = ('cond', 'message', 'coord', '__weakref__') + def __init__(self, cond, message, coord=None): + self.cond = cond + self.message = message + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.message is not None: nodelist.append(("message", self.message)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.message is not None: + yield self.message + + attr_names = () + +class Struct(Node): + __slots__ = ('name', 'decls', 'coord', '__weakref__') + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append(("decls[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.decls or []): + yield child + + attr_names = ('name', ) + +class StructRef(Node): + __slots__ = ('name', 'type', 'field', 'coord', '__weakref__') + def __init__(self, name, type, field, coord=None): + self.name = name + self.type = type + self.field = field + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(("name", self.name)) + if self.field is not None: nodelist.append(("field", self.field)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.field is not None: + yield self.field + + attr_names = ('type', ) + +class Switch(Node): + __slots__ = ('cond', 'stmt', 'coord', '__weakref__') + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + +class TernaryOp(Node): + __slots__ = ('cond', 'iftrue', 'iffalse', 'coord', '__weakref__') + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.iftrue is not None: nodelist.append(("iftrue", self.iftrue)) + if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.iftrue is not None: + yield self.iftrue + if self.iffalse is not None: + yield self.iffalse + + attr_names = () + +class TypeDecl(Node): + __slots__ = ('declname', 'quals', 'align', 'type', 'coord', '__weakref__') + def __init__(self, declname, quals, align, type, coord=None): + self.declname = declname + self.quals = quals + self.align = align + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ('declname', 'quals', 'align', ) + +class Typedef(Node): + __slots__ = ('name', 'quals', 'storage', 'type', 'coord', '__weakref__') + def __init__(self, name, quals, storage, type, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ('name', 'quals', 'storage', ) + +class Typename(Node): + __slots__ = ('name', 'quals', 'align', 'type', 'coord', '__weakref__') + def __init__(self, name, quals, align, type, coord=None): + self.name = name + self.quals = quals + self.align = align + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ('name', 'quals', 'align', ) + +class UnaryOp(Node): + __slots__ = ('op', 'expr', 'coord', '__weakref__') + def __init__(self, op, expr, coord=None): + self.op = op + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + + attr_names = ('op', ) + +class Union(Node): + __slots__ = ('name', 'decls', 'coord', '__weakref__') + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append(("decls[%d]" % i, child)) + return tuple(nodelist) + + def __iter__(self): + for child in (self.decls or []): + yield child + + attr_names = ('name', ) + +class While(Node): + __slots__ = ('cond', 'stmt', 'coord', '__weakref__') + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(("cond", self.cond)) + if self.stmt is not None: nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + +class Pragma(Node): + __slots__ = ('string', 'coord', '__weakref__') + def __init__(self, string, coord=None): + self.string = string + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ('string', ) + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_generator.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..1057b2c62e26feb74f2c1d0536de22140579fc8b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_generator.py @@ -0,0 +1,502 @@ +#------------------------------------------------------------------------------ +# pycparser: c_generator.py +# +# C code generator from pycparser AST nodes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#------------------------------------------------------------------------------ +from . import c_ast + + +class CGenerator(object): + """ Uses the same visitor pattern as c_ast.NodeVisitor, but modified to + return a value from each visit method, using string accumulation in + generic_visit. + """ + def __init__(self, reduce_parentheses=False): + """ Constructs C-code generator + + reduce_parentheses: + if True, eliminates needless parentheses on binary operators + """ + # Statements start with indentation of self.indent_level spaces, using + # the _make_indent method. + self.indent_level = 0 + self.reduce_parentheses = reduce_parentheses + + def _make_indent(self): + return ' ' * self.indent_level + + def visit(self, node): + method = 'visit_' + node.__class__.__name__ + return getattr(self, method, self.generic_visit)(node) + + def generic_visit(self, node): + if node is None: + return '' + else: + return ''.join(self.visit(c) for c_name, c in node.children()) + + def visit_Constant(self, n): + return n.value + + def visit_ID(self, n): + return n.name + + def visit_Pragma(self, n): + ret = '#pragma' + if n.string: + ret += ' ' + n.string + return ret + + def visit_ArrayRef(self, n): + arrref = self._parenthesize_unless_simple(n.name) + return arrref + '[' + self.visit(n.subscript) + ']' + + def visit_StructRef(self, n): + sref = self._parenthesize_unless_simple(n.name) + return sref + n.type + self.visit(n.field) + + def visit_FuncCall(self, n): + fref = self._parenthesize_unless_simple(n.name) + return fref + '(' + self.visit(n.args) + ')' + + def visit_UnaryOp(self, n): + if n.op == 'sizeof': + # Always parenthesize the argument of sizeof since it can be + # a name. + return 'sizeof(%s)' % self.visit(n.expr) + else: + operand = self._parenthesize_unless_simple(n.expr) + if n.op == 'p++': + return '%s++' % operand + elif n.op == 'p--': + return '%s--' % operand + else: + return '%s%s' % (n.op, operand) + + # Precedence map of binary operators: + precedence_map = { + # Should be in sync with c_parser.CParser.precedence + # Higher numbers are stronger binding + '||': 0, # weakest binding + '&&': 1, + '|': 2, + '^': 3, + '&': 4, + '==': 5, '!=': 5, + '>': 6, '>=': 6, '<': 6, '<=': 6, + '>>': 7, '<<': 7, + '+': 8, '-': 8, + '*': 9, '/': 9, '%': 9 # strongest binding + } + + def visit_BinaryOp(self, n): + # Note: all binary operators are left-to-right associative + # + # If `n.left.op` has a stronger or equally binding precedence in + # comparison to `n.op`, no parenthesis are needed for the left: + # e.g., `(a*b) + c` is equivalent to `a*b + c`, as well as + # `(a+b) - c` is equivalent to `a+b - c` (same precedence). + # If the left operator is weaker binding than the current, then + # parentheses are necessary: + # e.g., `(a+b) * c` is NOT equivalent to `a+b * c`. + lval_str = self._parenthesize_if( + n.left, + lambda d: not (self._is_simple_node(d) or + self.reduce_parentheses and isinstance(d, c_ast.BinaryOp) and + self.precedence_map[d.op] >= self.precedence_map[n.op])) + # If `n.right.op` has a stronger -but not equal- binding precedence, + # parenthesis can be omitted on the right: + # e.g., `a + (b*c)` is equivalent to `a + b*c`. + # If the right operator is weaker or equally binding, then parentheses + # are necessary: + # e.g., `a * (b+c)` is NOT equivalent to `a * b+c` and + # `a - (b+c)` is NOT equivalent to `a - b+c` (same precedence). + rval_str = self._parenthesize_if( + n.right, + lambda d: not (self._is_simple_node(d) or + self.reduce_parentheses and isinstance(d, c_ast.BinaryOp) and + self.precedence_map[d.op] > self.precedence_map[n.op])) + return '%s %s %s' % (lval_str, n.op, rval_str) + + def visit_Assignment(self, n): + rval_str = self._parenthesize_if( + n.rvalue, + lambda n: isinstance(n, c_ast.Assignment)) + return '%s %s %s' % (self.visit(n.lvalue), n.op, rval_str) + + def visit_IdentifierType(self, n): + return ' '.join(n.names) + + def _visit_expr(self, n): + if isinstance(n, c_ast.InitList): + return '{' + self.visit(n) + '}' + elif isinstance(n, c_ast.ExprList): + return '(' + self.visit(n) + ')' + else: + return self.visit(n) + + def visit_Decl(self, n, no_type=False): + # no_type is used when a Decl is part of a DeclList, where the type is + # explicitly only for the first declaration in a list. + # + s = n.name if no_type else self._generate_decl(n) + if n.bitsize: s += ' : ' + self.visit(n.bitsize) + if n.init: + s += ' = ' + self._visit_expr(n.init) + return s + + def visit_DeclList(self, n): + s = self.visit(n.decls[0]) + if len(n.decls) > 1: + s += ', ' + ', '.join(self.visit_Decl(decl, no_type=True) + for decl in n.decls[1:]) + return s + + def visit_Typedef(self, n): + s = '' + if n.storage: s += ' '.join(n.storage) + ' ' + s += self._generate_type(n.type) + return s + + def visit_Cast(self, n): + s = '(' + self._generate_type(n.to_type, emit_declname=False) + ')' + return s + ' ' + self._parenthesize_unless_simple(n.expr) + + def visit_ExprList(self, n): + visited_subexprs = [] + for expr in n.exprs: + visited_subexprs.append(self._visit_expr(expr)) + return ', '.join(visited_subexprs) + + def visit_InitList(self, n): + visited_subexprs = [] + for expr in n.exprs: + visited_subexprs.append(self._visit_expr(expr)) + return ', '.join(visited_subexprs) + + def visit_Enum(self, n): + return self._generate_struct_union_enum(n, name='enum') + + def visit_Alignas(self, n): + return '_Alignas({})'.format(self.visit(n.alignment)) + + def visit_Enumerator(self, n): + if not n.value: + return '{indent}{name},\n'.format( + indent=self._make_indent(), + name=n.name, + ) + else: + return '{indent}{name} = {value},\n'.format( + indent=self._make_indent(), + name=n.name, + value=self.visit(n.value), + ) + + def visit_FuncDef(self, n): + decl = self.visit(n.decl) + self.indent_level = 0 + body = self.visit(n.body) + if n.param_decls: + knrdecls = ';\n'.join(self.visit(p) for p in n.param_decls) + return decl + '\n' + knrdecls + ';\n' + body + '\n' + else: + return decl + '\n' + body + '\n' + + def visit_FileAST(self, n): + s = '' + for ext in n.ext: + if isinstance(ext, c_ast.FuncDef): + s += self.visit(ext) + elif isinstance(ext, c_ast.Pragma): + s += self.visit(ext) + '\n' + else: + s += self.visit(ext) + ';\n' + return s + + def visit_Compound(self, n): + s = self._make_indent() + '{\n' + self.indent_level += 2 + if n.block_items: + s += ''.join(self._generate_stmt(stmt) for stmt in n.block_items) + self.indent_level -= 2 + s += self._make_indent() + '}\n' + return s + + def visit_CompoundLiteral(self, n): + return '(' + self.visit(n.type) + '){' + self.visit(n.init) + '}' + + + def visit_EmptyStatement(self, n): + return ';' + + def visit_ParamList(self, n): + return ', '.join(self.visit(param) for param in n.params) + + def visit_Return(self, n): + s = 'return' + if n.expr: s += ' ' + self.visit(n.expr) + return s + ';' + + def visit_Break(self, n): + return 'break;' + + def visit_Continue(self, n): + return 'continue;' + + def visit_TernaryOp(self, n): + s = '(' + self._visit_expr(n.cond) + ') ? ' + s += '(' + self._visit_expr(n.iftrue) + ') : ' + s += '(' + self._visit_expr(n.iffalse) + ')' + return s + + def visit_If(self, n): + s = 'if (' + if n.cond: s += self.visit(n.cond) + s += ')\n' + s += self._generate_stmt(n.iftrue, add_indent=True) + if n.iffalse: + s += self._make_indent() + 'else\n' + s += self._generate_stmt(n.iffalse, add_indent=True) + return s + + def visit_For(self, n): + s = 'for (' + if n.init: s += self.visit(n.init) + s += ';' + if n.cond: s += ' ' + self.visit(n.cond) + s += ';' + if n.next: s += ' ' + self.visit(n.next) + s += ')\n' + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_While(self, n): + s = 'while (' + if n.cond: s += self.visit(n.cond) + s += ')\n' + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_DoWhile(self, n): + s = 'do\n' + s += self._generate_stmt(n.stmt, add_indent=True) + s += self._make_indent() + 'while (' + if n.cond: s += self.visit(n.cond) + s += ');' + return s + + def visit_StaticAssert(self, n): + s = '_Static_assert(' + s += self.visit(n.cond) + if n.message: + s += ',' + s += self.visit(n.message) + s += ')' + return s + + def visit_Switch(self, n): + s = 'switch (' + self.visit(n.cond) + ')\n' + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_Case(self, n): + s = 'case ' + self.visit(n.expr) + ':\n' + for stmt in n.stmts: + s += self._generate_stmt(stmt, add_indent=True) + return s + + def visit_Default(self, n): + s = 'default:\n' + for stmt in n.stmts: + s += self._generate_stmt(stmt, add_indent=True) + return s + + def visit_Label(self, n): + return n.name + ':\n' + self._generate_stmt(n.stmt) + + def visit_Goto(self, n): + return 'goto ' + n.name + ';' + + def visit_EllipsisParam(self, n): + return '...' + + def visit_Struct(self, n): + return self._generate_struct_union_enum(n, 'struct') + + def visit_Typename(self, n): + return self._generate_type(n.type) + + def visit_Union(self, n): + return self._generate_struct_union_enum(n, 'union') + + def visit_NamedInitializer(self, n): + s = '' + for name in n.name: + if isinstance(name, c_ast.ID): + s += '.' + name.name + else: + s += '[' + self.visit(name) + ']' + s += ' = ' + self._visit_expr(n.expr) + return s + + def visit_FuncDecl(self, n): + return self._generate_type(n) + + def visit_ArrayDecl(self, n): + return self._generate_type(n, emit_declname=False) + + def visit_TypeDecl(self, n): + return self._generate_type(n, emit_declname=False) + + def visit_PtrDecl(self, n): + return self._generate_type(n, emit_declname=False) + + def _generate_struct_union_enum(self, n, name): + """ Generates code for structs, unions, and enums. name should be + 'struct', 'union', or 'enum'. + """ + if name in ('struct', 'union'): + members = n.decls + body_function = self._generate_struct_union_body + else: + assert name == 'enum' + members = None if n.values is None else n.values.enumerators + body_function = self._generate_enum_body + s = name + ' ' + (n.name or '') + if members is not None: + # None means no members + # Empty sequence means an empty list of members + s += '\n' + s += self._make_indent() + self.indent_level += 2 + s += '{\n' + s += body_function(members) + self.indent_level -= 2 + s += self._make_indent() + '}' + return s + + def _generate_struct_union_body(self, members): + return ''.join(self._generate_stmt(decl) for decl in members) + + def _generate_enum_body(self, members): + # `[:-2] + '\n'` removes the final `,` from the enumerator list + return ''.join(self.visit(value) for value in members)[:-2] + '\n' + + def _generate_stmt(self, n, add_indent=False): + """ Generation from a statement node. This method exists as a wrapper + for individual visit_* methods to handle different treatment of + some statements in this context. + """ + typ = type(n) + if add_indent: self.indent_level += 2 + indent = self._make_indent() + if add_indent: self.indent_level -= 2 + + if typ in ( + c_ast.Decl, c_ast.Assignment, c_ast.Cast, c_ast.UnaryOp, + c_ast.BinaryOp, c_ast.TernaryOp, c_ast.FuncCall, c_ast.ArrayRef, + c_ast.StructRef, c_ast.Constant, c_ast.ID, c_ast.Typedef, + c_ast.ExprList): + # These can also appear in an expression context so no semicolon + # is added to them automatically + # + return indent + self.visit(n) + ';\n' + elif typ in (c_ast.Compound,): + # No extra indentation required before the opening brace of a + # compound - because it consists of multiple lines it has to + # compute its own indentation. + # + return self.visit(n) + elif typ in (c_ast.If,): + return indent + self.visit(n) + else: + return indent + self.visit(n) + '\n' + + def _generate_decl(self, n): + """ Generation from a Decl node. + """ + s = '' + if n.funcspec: s = ' '.join(n.funcspec) + ' ' + if n.storage: s += ' '.join(n.storage) + ' ' + if n.align: s += self.visit(n.align[0]) + ' ' + s += self._generate_type(n.type) + return s + + def _generate_type(self, n, modifiers=[], emit_declname = True): + """ Recursive generation from a type node. n is the type node. + modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers + encountered on the way down to a TypeDecl, to allow proper + generation from it. + """ + typ = type(n) + #~ print(n, modifiers) + + if typ == c_ast.TypeDecl: + s = '' + if n.quals: s += ' '.join(n.quals) + ' ' + s += self.visit(n.type) + + nstr = n.declname if n.declname and emit_declname else '' + # Resolve modifiers. + # Wrap in parens to distinguish pointer to array and pointer to + # function syntax. + # + for i, modifier in enumerate(modifiers): + if isinstance(modifier, c_ast.ArrayDecl): + if (i != 0 and + isinstance(modifiers[i - 1], c_ast.PtrDecl)): + nstr = '(' + nstr + ')' + nstr += '[' + if modifier.dim_quals: + nstr += ' '.join(modifier.dim_quals) + ' ' + nstr += self.visit(modifier.dim) + ']' + elif isinstance(modifier, c_ast.FuncDecl): + if (i != 0 and + isinstance(modifiers[i - 1], c_ast.PtrDecl)): + nstr = '(' + nstr + ')' + nstr += '(' + self.visit(modifier.args) + ')' + elif isinstance(modifier, c_ast.PtrDecl): + if modifier.quals: + nstr = '* %s%s' % (' '.join(modifier.quals), + ' ' + nstr if nstr else '') + else: + nstr = '*' + nstr + if nstr: s += ' ' + nstr + return s + elif typ == c_ast.Decl: + return self._generate_decl(n.type) + elif typ == c_ast.Typename: + return self._generate_type(n.type, emit_declname = emit_declname) + elif typ == c_ast.IdentifierType: + return ' '.join(n.names) + ' ' + elif typ in (c_ast.ArrayDecl, c_ast.PtrDecl, c_ast.FuncDecl): + return self._generate_type(n.type, modifiers + [n], + emit_declname = emit_declname) + else: + return self.visit(n) + + def _parenthesize_if(self, n, condition): + """ Visits 'n' and returns its string representation, parenthesized + if the condition function applied to the node returns True. + """ + s = self._visit_expr(n) + if condition(n): + return '(' + s + ')' + else: + return s + + def _parenthesize_unless_simple(self, n): + """ Common use case for _parenthesize_if + """ + return self._parenthesize_if(n, lambda d: not self._is_simple_node(d)) + + def _is_simple_node(self, n): + """ Returns True for nodes that are "simple" - i.e. nodes that always + have higher precedence than operators. + """ + return isinstance(n, (c_ast.Constant, c_ast.ID, c_ast.ArrayRef, + c_ast.StructRef, c_ast.FuncCall)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_lexer.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_lexer.py new file mode 100644 index 0000000000000000000000000000000000000000..d68d8ebfa3b3a108c7ef515846d1e35c0f6922d8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_lexer.py @@ -0,0 +1,554 @@ +#------------------------------------------------------------------------------ +# pycparser: c_lexer.py +# +# CLexer class: lexer for the C language +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#------------------------------------------------------------------------------ +import re + +from .ply import lex +from .ply.lex import TOKEN + + +class CLexer(object): + """ A lexer for the C language. After building it, set the + input text with input(), and call token() to get new + tokens. + + The public attribute filename can be set to an initial + filename, but the lexer will update it upon #line + directives. + """ + def __init__(self, error_func, on_lbrace_func, on_rbrace_func, + type_lookup_func): + """ Create a new Lexer. + + error_func: + An error function. Will be called with an error + message, line and column as arguments, in case of + an error during lexing. + + on_lbrace_func, on_rbrace_func: + Called when an LBRACE or RBRACE is encountered + (likely to push/pop type_lookup_func's scope) + + type_lookup_func: + A type lookup function. Given a string, it must + return True IFF this string is a name of a type + that was defined with a typedef earlier. + """ + self.error_func = error_func + self.on_lbrace_func = on_lbrace_func + self.on_rbrace_func = on_rbrace_func + self.type_lookup_func = type_lookup_func + self.filename = '' + + # Keeps track of the last token returned from self.token() + self.last_token = None + + # Allow either "# line" or "# <num>" to support GCC's + # cpp output + # + self.line_pattern = re.compile(r'([ \t]*line\W)|([ \t]*\d+)') + self.pragma_pattern = re.compile(r'[ \t]*pragma\W') + + def build(self, **kwargs): + """ Builds the lexer from the specification. Must be + called after the lexer object is created. + + This method exists separately, because the PLY + manual warns against calling lex.lex inside + __init__ + """ + self.lexer = lex.lex(object=self, **kwargs) + + def reset_lineno(self): + """ Resets the internal line number counter of the lexer. + """ + self.lexer.lineno = 1 + + def input(self, text): + self.lexer.input(text) + + def token(self): + self.last_token = self.lexer.token() + return self.last_token + + def find_tok_column(self, token): + """ Find the column of the token in its line. + """ + last_cr = self.lexer.lexdata.rfind('\n', 0, token.lexpos) + return token.lexpos - last_cr + + ######################-- PRIVATE --###################### + + ## + ## Internal auxiliary methods + ## + def _error(self, msg, token): + location = self._make_tok_location(token) + self.error_func(msg, location[0], location[1]) + self.lexer.skip(1) + + def _make_tok_location(self, token): + return (token.lineno, self.find_tok_column(token)) + + ## + ## Reserved keywords + ## + keywords = ( + 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', + 'CONTINUE', 'DEFAULT', 'DO', 'DOUBLE', 'ELSE', 'ENUM', 'EXTERN', + 'FLOAT', 'FOR', 'GOTO', 'IF', 'INLINE', 'INT', 'LONG', + 'REGISTER', 'OFFSETOF', + 'RESTRICT', 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT', + 'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID', + 'VOLATILE', 'WHILE', '__INT128', + ) + + keywords_new = ( + '_BOOL', '_COMPLEX', + '_NORETURN', '_THREAD_LOCAL', '_STATIC_ASSERT', + '_ATOMIC', '_ALIGNOF', '_ALIGNAS', + ) + + keyword_map = {} + + for keyword in keywords: + keyword_map[keyword.lower()] = keyword + + for keyword in keywords_new: + keyword_map[keyword[:2].upper() + keyword[2:].lower()] = keyword + + ## + ## All the tokens recognized by the lexer + ## + tokens = keywords + keywords_new + ( + # Identifiers + 'ID', + + # Type identifiers (identifiers previously defined as + # types with typedef) + 'TYPEID', + + # constants + 'INT_CONST_DEC', 'INT_CONST_OCT', 'INT_CONST_HEX', 'INT_CONST_BIN', 'INT_CONST_CHAR', + 'FLOAT_CONST', 'HEX_FLOAT_CONST', + 'CHAR_CONST', + 'WCHAR_CONST', + 'U8CHAR_CONST', + 'U16CHAR_CONST', + 'U32CHAR_CONST', + + # String literals + 'STRING_LITERAL', + 'WSTRING_LITERAL', + 'U8STRING_LITERAL', + 'U16STRING_LITERAL', + 'U32STRING_LITERAL', + + # Operators + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', + 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', + 'OREQUAL', + + # Increment/decrement + 'PLUSPLUS', 'MINUSMINUS', + + # Structure dereference (->) + 'ARROW', + + # Conditional operator (?) + 'CONDOP', + + # Delimiters + 'LPAREN', 'RPAREN', # ( ) + 'LBRACKET', 'RBRACKET', # [ ] + 'LBRACE', 'RBRACE', # { } + 'COMMA', 'PERIOD', # . , + 'SEMI', 'COLON', # ; : + + # Ellipsis (...) + 'ELLIPSIS', + + # pre-processor + 'PPHASH', # '#' + 'PPPRAGMA', # 'pragma' + 'PPPRAGMASTR', + ) + + ## + ## Regexes for use in tokens + ## + ## + + # valid C identifiers (K&R2: A.2.3), plus '$' (supported by some compilers) + identifier = r'[a-zA-Z_$][0-9a-zA-Z_$]*' + + hex_prefix = '0[xX]' + hex_digits = '[0-9a-fA-F]+' + bin_prefix = '0[bB]' + bin_digits = '[01]+' + + # integer constants (K&R2: A.2.5.1) + integer_suffix_opt = r'(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?' + decimal_constant = '(0'+integer_suffix_opt+')|([1-9][0-9]*'+integer_suffix_opt+')' + octal_constant = '0[0-7]*'+integer_suffix_opt + hex_constant = hex_prefix+hex_digits+integer_suffix_opt + bin_constant = bin_prefix+bin_digits+integer_suffix_opt + + bad_octal_constant = '0[0-7]*[89]' + + # character constants (K&R2: A.2.5.2) + # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line + # directives with Windows paths as filenames (..\..\dir\file) + # For the same reason, decimal_escape allows all digit sequences. We want to + # parse all correct code, even if it means to sometimes parse incorrect + # code. + # + # The original regexes were taken verbatim from the C syntax definition, + # and were later modified to avoid worst-case exponential running time. + # + # simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" + # decimal_escape = r"""(\d+)""" + # hex_escape = r"""(x[0-9a-fA-F]+)""" + # bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" + # + # The following modifications were made to avoid the ambiguity that allowed backtracking: + # (https://github.com/eliben/pycparser/issues/61) + # + # - \x was removed from simple_escape, unless it was not followed by a hex digit, to avoid ambiguity with hex_escape. + # - hex_escape allows one or more hex characters, but requires that the next character(if any) is not hex + # - decimal_escape allows one or more decimal characters, but requires that the next character(if any) is not a decimal + # - bad_escape does not allow any decimals (8-9), to avoid conflicting with the permissive decimal_escape. + # + # Without this change, python's `re` module would recursively try parsing each ambiguous escape sequence in multiple ways. + # e.g. `\123` could be parsed as `\1`+`23`, `\12`+`3`, and `\123`. + + simple_escape = r"""([a-wyzA-Z._~!=&\^\-\\?'"]|x(?![0-9a-fA-F]))""" + decimal_escape = r"""(\d+)(?!\d)""" + hex_escape = r"""(x[0-9a-fA-F]+)(?![0-9a-fA-F])""" + bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-9])""" + + escape_sequence = r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))' + + # This complicated regex with lookahead might be slow for strings, so because all of the valid escapes (including \x) allowed + # 0 or more non-escaped characters after the first character, simple_escape+decimal_escape+hex_escape got simplified to + + escape_sequence_start_in_string = r"""(\\[0-9a-zA-Z._~!=&\^\-\\?'"])""" + + cconst_char = r"""([^'\\\n]|"""+escape_sequence+')' + char_const = "'"+cconst_char+"'" + wchar_const = 'L'+char_const + u8char_const = 'u8'+char_const + u16char_const = 'u'+char_const + u32char_const = 'U'+char_const + multicharacter_constant = "'"+cconst_char+"{2,4}'" + unmatched_quote = "('"+cconst_char+"*\\n)|('"+cconst_char+"*$)" + bad_char_const = r"""('"""+cconst_char+"""[^'\n]+')|('')|('"""+bad_escape+r"""[^'\n]*')""" + + # string literals (K&R2: A.2.6) + string_char = r"""([^"\\\n]|"""+escape_sequence_start_in_string+')' + string_literal = '"'+string_char+'*"' + wstring_literal = 'L'+string_literal + u8string_literal = 'u8'+string_literal + u16string_literal = 'u'+string_literal + u32string_literal = 'U'+string_literal + bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"' + + # floating constants (K&R2: A.2.5.3) + exponent_part = r"""([eE][-+]?[0-9]+)""" + fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)""" + floating_constant = '(((('+fractional_constant+')'+exponent_part+'?)|([0-9]+'+exponent_part+'))[FfLl]?)' + binary_exponent_part = r'''([pP][+-]?[0-9]+)''' + hex_fractional_constant = '((('+hex_digits+r""")?\."""+hex_digits+')|('+hex_digits+r"""\.))""" + hex_floating_constant = '('+hex_prefix+'('+hex_digits+'|'+hex_fractional_constant+')'+binary_exponent_part+'[FfLl]?)' + + ## + ## Lexer states: used for preprocessor \n-terminated directives + ## + states = ( + # ppline: preprocessor line directives + # + ('ppline', 'exclusive'), + + # pppragma: pragma + # + ('pppragma', 'exclusive'), + ) + + def t_PPHASH(self, t): + r'[ \t]*\#' + if self.line_pattern.match(t.lexer.lexdata, pos=t.lexer.lexpos): + t.lexer.begin('ppline') + self.pp_line = self.pp_filename = None + elif self.pragma_pattern.match(t.lexer.lexdata, pos=t.lexer.lexpos): + t.lexer.begin('pppragma') + else: + t.type = 'PPHASH' + return t + + ## + ## Rules for the ppline state + ## + @TOKEN(string_literal) + def t_ppline_FILENAME(self, t): + if self.pp_line is None: + self._error('filename before line number in #line', t) + else: + self.pp_filename = t.value.lstrip('"').rstrip('"') + + @TOKEN(decimal_constant) + def t_ppline_LINE_NUMBER(self, t): + if self.pp_line is None: + self.pp_line = t.value + else: + # Ignore: GCC's cpp sometimes inserts a numeric flag + # after the file name + pass + + def t_ppline_NEWLINE(self, t): + r'\n' + if self.pp_line is None: + self._error('line number missing in #line', t) + else: + self.lexer.lineno = int(self.pp_line) + + if self.pp_filename is not None: + self.filename = self.pp_filename + + t.lexer.begin('INITIAL') + + def t_ppline_PPLINE(self, t): + r'line' + pass + + t_ppline_ignore = ' \t' + + def t_ppline_error(self, t): + self._error('invalid #line directive', t) + + ## + ## Rules for the pppragma state + ## + def t_pppragma_NEWLINE(self, t): + r'\n' + t.lexer.lineno += 1 + t.lexer.begin('INITIAL') + + def t_pppragma_PPPRAGMA(self, t): + r'pragma' + return t + + t_pppragma_ignore = ' \t' + + def t_pppragma_STR(self, t): + '.+' + t.type = 'PPPRAGMASTR' + return t + + def t_pppragma_error(self, t): + self._error('invalid #pragma directive', t) + + ## + ## Rules for the normal state + ## + t_ignore = ' \t' + + # Newlines + def t_NEWLINE(self, t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + + # Operators + t_PLUS = r'\+' + t_MINUS = r'-' + t_TIMES = r'\*' + t_DIVIDE = r'/' + t_MOD = r'%' + t_OR = r'\|' + t_AND = r'&' + t_NOT = r'~' + t_XOR = r'\^' + t_LSHIFT = r'<<' + t_RSHIFT = r'>>' + t_LOR = r'\|\|' + t_LAND = r'&&' + t_LNOT = r'!' + t_LT = r'<' + t_GT = r'>' + t_LE = r'<=' + t_GE = r'>=' + t_EQ = r'==' + t_NE = r'!=' + + # Assignment operators + t_EQUALS = r'=' + t_TIMESEQUAL = r'\*=' + t_DIVEQUAL = r'/=' + t_MODEQUAL = r'%=' + t_PLUSEQUAL = r'\+=' + t_MINUSEQUAL = r'-=' + t_LSHIFTEQUAL = r'<<=' + t_RSHIFTEQUAL = r'>>=' + t_ANDEQUAL = r'&=' + t_OREQUAL = r'\|=' + t_XOREQUAL = r'\^=' + + # Increment/decrement + t_PLUSPLUS = r'\+\+' + t_MINUSMINUS = r'--' + + # -> + t_ARROW = r'->' + + # ? + t_CONDOP = r'\?' + + # Delimiters + t_LPAREN = r'\(' + t_RPAREN = r'\)' + t_LBRACKET = r'\[' + t_RBRACKET = r'\]' + t_COMMA = r',' + t_PERIOD = r'\.' + t_SEMI = r';' + t_COLON = r':' + t_ELLIPSIS = r'\.\.\.' + + # Scope delimiters + # To see why on_lbrace_func is needed, consider: + # typedef char TT; + # void foo(int TT) { TT = 10; } + # TT x = 5; + # Outside the function, TT is a typedef, but inside (starting and ending + # with the braces) it's a parameter. The trouble begins with yacc's + # lookahead token. If we open a new scope in brace_open, then TT has + # already been read and incorrectly interpreted as TYPEID. So, we need + # to open and close scopes from within the lexer. + # Similar for the TT immediately outside the end of the function. + # + @TOKEN(r'\{') + def t_LBRACE(self, t): + self.on_lbrace_func() + return t + @TOKEN(r'\}') + def t_RBRACE(self, t): + self.on_rbrace_func() + return t + + t_STRING_LITERAL = string_literal + + # The following floating and integer constants are defined as + # functions to impose a strict order (otherwise, decimal + # is placed before the others because its regex is longer, + # and this is bad) + # + @TOKEN(floating_constant) + def t_FLOAT_CONST(self, t): + return t + + @TOKEN(hex_floating_constant) + def t_HEX_FLOAT_CONST(self, t): + return t + + @TOKEN(hex_constant) + def t_INT_CONST_HEX(self, t): + return t + + @TOKEN(bin_constant) + def t_INT_CONST_BIN(self, t): + return t + + @TOKEN(bad_octal_constant) + def t_BAD_CONST_OCT(self, t): + msg = "Invalid octal constant" + self._error(msg, t) + + @TOKEN(octal_constant) + def t_INT_CONST_OCT(self, t): + return t + + @TOKEN(decimal_constant) + def t_INT_CONST_DEC(self, t): + return t + + # Must come before bad_char_const, to prevent it from + # catching valid char constants as invalid + # + @TOKEN(multicharacter_constant) + def t_INT_CONST_CHAR(self, t): + return t + + @TOKEN(char_const) + def t_CHAR_CONST(self, t): + return t + + @TOKEN(wchar_const) + def t_WCHAR_CONST(self, t): + return t + + @TOKEN(u8char_const) + def t_U8CHAR_CONST(self, t): + return t + + @TOKEN(u16char_const) + def t_U16CHAR_CONST(self, t): + return t + + @TOKEN(u32char_const) + def t_U32CHAR_CONST(self, t): + return t + + @TOKEN(unmatched_quote) + def t_UNMATCHED_QUOTE(self, t): + msg = "Unmatched '" + self._error(msg, t) + + @TOKEN(bad_char_const) + def t_BAD_CHAR_CONST(self, t): + msg = "Invalid char constant %s" % t.value + self._error(msg, t) + + @TOKEN(wstring_literal) + def t_WSTRING_LITERAL(self, t): + return t + + @TOKEN(u8string_literal) + def t_U8STRING_LITERAL(self, t): + return t + + @TOKEN(u16string_literal) + def t_U16STRING_LITERAL(self, t): + return t + + @TOKEN(u32string_literal) + def t_U32STRING_LITERAL(self, t): + return t + + # unmatched string literals are caught by the preprocessor + + @TOKEN(bad_string_literal) + def t_BAD_STRING_LITERAL(self, t): + msg = "String contains invalid escape code" + self._error(msg, t) + + @TOKEN(identifier) + def t_ID(self, t): + t.type = self.keyword_map.get(t.value, "ID") + if t.type == 'ID' and self.type_lookup_func(t.value): + t.type = "TYPEID" + return t + + def t_error(self, t): + msg = 'Illegal character %s' % repr(t.value[0]) + self._error(msg, t) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_parser.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..640a75940672d12bb06e00960eaf5cca331dacad --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/c_parser.py @@ -0,0 +1,1936 @@ +#------------------------------------------------------------------------------ +# pycparser: c_parser.py +# +# CParser class: Parser and AST builder for the C language +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#------------------------------------------------------------------------------ +from .ply import yacc + +from . import c_ast +from .c_lexer import CLexer +from .plyparser import PLYParser, ParseError, parameterized, template +from .ast_transforms import fix_switch_cases, fix_atomic_specifiers + + +@template +class CParser(PLYParser): + def __init__( + self, + lex_optimize=True, + lexer=CLexer, + lextab='pycparser.lextab', + yacc_optimize=True, + yacctab='pycparser.yacctab', + yacc_debug=False, + taboutputdir=''): + """ Create a new CParser. + + Some arguments for controlling the debug/optimization + level of the parser are provided. The defaults are + tuned for release/performance mode. + The simple rules for using them are: + *) When tweaking CParser/CLexer, set these to False + *) When releasing a stable parser, set to True + + lex_optimize: + Set to False when you're modifying the lexer. + Otherwise, changes in the lexer won't be used, if + some lextab.py file exists. + When releasing with a stable lexer, set to True + to save the re-generation of the lexer table on + each run. + + lexer: + Set this parameter to define the lexer to use if + you're not using the default CLexer. + + lextab: + Points to the lex table that's used for optimized + mode. Only if you're modifying the lexer and want + some tests to avoid re-generating the table, make + this point to a local lex table file (that's been + earlier generated with lex_optimize=True) + + yacc_optimize: + Set to False when you're modifying the parser. + Otherwise, changes in the parser won't be used, if + some parsetab.py file exists. + When releasing with a stable parser, set to True + to save the re-generation of the parser table on + each run. + + yacctab: + Points to the yacc table that's used for optimized + mode. Only if you're modifying the parser, make + this point to a local yacc table file + + yacc_debug: + Generate a parser.out file that explains how yacc + built the parsing table from the grammar. + + taboutputdir: + Set this parameter to control the location of generated + lextab and yacctab files. + """ + self.clex = lexer( + error_func=self._lex_error_func, + on_lbrace_func=self._lex_on_lbrace_func, + on_rbrace_func=self._lex_on_rbrace_func, + type_lookup_func=self._lex_type_lookup_func) + + self.clex.build( + optimize=lex_optimize, + lextab=lextab, + outputdir=taboutputdir) + self.tokens = self.clex.tokens + + rules_with_opt = [ + 'abstract_declarator', + 'assignment_expression', + 'declaration_list', + 'declaration_specifiers_no_type', + 'designation', + 'expression', + 'identifier_list', + 'init_declarator_list', + 'id_init_declarator_list', + 'initializer_list', + 'parameter_type_list', + 'block_item_list', + 'type_qualifier_list', + 'struct_declarator_list' + ] + + for rule in rules_with_opt: + self._create_opt_rule(rule) + + self.cparser = yacc.yacc( + module=self, + start='translation_unit_or_empty', + debug=yacc_debug, + optimize=yacc_optimize, + tabmodule=yacctab, + outputdir=taboutputdir) + + # Stack of scopes for keeping track of symbols. _scope_stack[-1] is + # the current (topmost) scope. Each scope is a dictionary that + # specifies whether a name is a type. If _scope_stack[n][name] is + # True, 'name' is currently a type in the scope. If it's False, + # 'name' is used in the scope but not as a type (for instance, if we + # saw: int name; + # If 'name' is not a key in _scope_stack[n] then 'name' was not defined + # in this scope at all. + self._scope_stack = [dict()] + + # Keeps track of the last token given to yacc (the lookahead token) + self._last_yielded_token = None + + def parse(self, text, filename='', debug=False): + """ Parses C code and returns an AST. + + text: + A string containing the C source code + + filename: + Name of the file being parsed (for meaningful + error messages) + + debug: + Debug flag to YACC + """ + self.clex.filename = filename + self.clex.reset_lineno() + self._scope_stack = [dict()] + self._last_yielded_token = None + return self.cparser.parse( + input=text, + lexer=self.clex, + debug=debug) + + ######################-- PRIVATE --###################### + + def _push_scope(self): + self._scope_stack.append(dict()) + + def _pop_scope(self): + assert len(self._scope_stack) > 1 + self._scope_stack.pop() + + def _add_typedef_name(self, name, coord): + """ Add a new typedef name (ie a TYPEID) to the current scope + """ + if not self._scope_stack[-1].get(name, True): + self._parse_error( + "Typedef %r previously declared as non-typedef " + "in this scope" % name, coord) + self._scope_stack[-1][name] = True + + def _add_identifier(self, name, coord): + """ Add a new object, function, or enum member name (ie an ID) to the + current scope + """ + if self._scope_stack[-1].get(name, False): + self._parse_error( + "Non-typedef %r previously declared as typedef " + "in this scope" % name, coord) + self._scope_stack[-1][name] = False + + def _is_type_in_scope(self, name): + """ Is *name* a typedef-name in the current scope? + """ + for scope in reversed(self._scope_stack): + # If name is an identifier in this scope it shadows typedefs in + # higher scopes. + in_scope = scope.get(name) + if in_scope is not None: return in_scope + return False + + def _lex_error_func(self, msg, line, column): + self._parse_error(msg, self._coord(line, column)) + + def _lex_on_lbrace_func(self): + self._push_scope() + + def _lex_on_rbrace_func(self): + self._pop_scope() + + def _lex_type_lookup_func(self, name): + """ Looks up types that were previously defined with + typedef. + Passed to the lexer for recognizing identifiers that + are types. + """ + is_type = self._is_type_in_scope(name) + return is_type + + def _get_yacc_lookahead_token(self): + """ We need access to yacc's lookahead token in certain cases. + This is the last token yacc requested from the lexer, so we + ask the lexer. + """ + return self.clex.last_token + + # To understand what's going on here, read sections A.8.5 and + # A.8.6 of K&R2 very carefully. + # + # A C type consists of a basic type declaration, with a list + # of modifiers. For example: + # + # int *c[5]; + # + # The basic declaration here is 'int c', and the pointer and + # the array are the modifiers. + # + # Basic declarations are represented by TypeDecl (from module c_ast) and the + # modifiers are FuncDecl, PtrDecl and ArrayDecl. + # + # The standard states that whenever a new modifier is parsed, it should be + # added to the end of the list of modifiers. For example: + # + # K&R2 A.8.6.2: Array Declarators + # + # In a declaration T D where D has the form + # D1 [constant-expression-opt] + # and the type of the identifier in the declaration T D1 is + # "type-modifier T", the type of the + # identifier of D is "type-modifier array of T" + # + # This is what this method does. The declarator it receives + # can be a list of declarators ending with TypeDecl. It + # tacks the modifier to the end of this list, just before + # the TypeDecl. + # + # Additionally, the modifier may be a list itself. This is + # useful for pointers, that can come as a chain from the rule + # p_pointer. In this case, the whole modifier list is spliced + # into the new location. + def _type_modify_decl(self, decl, modifier): + """ Tacks a type modifier on a declarator, and returns + the modified declarator. + + Note: the declarator and modifier may be modified + """ + #~ print '****' + #~ decl.show(offset=3) + #~ modifier.show(offset=3) + #~ print '****' + + modifier_head = modifier + modifier_tail = modifier + + # The modifier may be a nested list. Reach its tail. + while modifier_tail.type: + modifier_tail = modifier_tail.type + + # If the decl is a basic type, just tack the modifier onto it. + if isinstance(decl, c_ast.TypeDecl): + modifier_tail.type = decl + return modifier + else: + # Otherwise, the decl is a list of modifiers. Reach + # its tail and splice the modifier onto the tail, + # pointing to the underlying basic type. + decl_tail = decl + + while not isinstance(decl_tail.type, c_ast.TypeDecl): + decl_tail = decl_tail.type + + modifier_tail.type = decl_tail.type + decl_tail.type = modifier_head + return decl + + # Due to the order in which declarators are constructed, + # they have to be fixed in order to look like a normal AST. + # + # When a declaration arrives from syntax construction, it has + # these problems: + # * The innermost TypeDecl has no type (because the basic + # type is only known at the uppermost declaration level) + # * The declaration has no variable name, since that is saved + # in the innermost TypeDecl + # * The typename of the declaration is a list of type + # specifiers, and not a node. Here, basic identifier types + # should be separated from more complex types like enums + # and structs. + # + # This method fixes these problems. + def _fix_decl_name_type(self, decl, typename): + """ Fixes a declaration. Modifies decl. + """ + # Reach the underlying basic type + # + type = decl + while not isinstance(type, c_ast.TypeDecl): + type = type.type + + decl.name = type.declname + type.quals = decl.quals[:] + + # The typename is a list of types. If any type in this + # list isn't an IdentifierType, it must be the only + # type in the list (it's illegal to declare "int enum ..") + # If all the types are basic, they're collected in the + # IdentifierType holder. + for tn in typename: + if not isinstance(tn, c_ast.IdentifierType): + if len(typename) > 1: + self._parse_error( + "Invalid multiple types specified", tn.coord) + else: + type.type = tn + return decl + + if not typename: + # Functions default to returning int + # + if not isinstance(decl.type, c_ast.FuncDecl): + self._parse_error( + "Missing type in declaration", decl.coord) + type.type = c_ast.IdentifierType( + ['int'], + coord=decl.coord) + else: + # At this point, we know that typename is a list of IdentifierType + # nodes. Concatenate all the names into a single list. + # + type.type = c_ast.IdentifierType( + [name for id in typename for name in id.names], + coord=typename[0].coord) + return decl + + def _add_declaration_specifier(self, declspec, newspec, kind, append=False): + """ Declaration specifiers are represented by a dictionary + with the entries: + * qual: a list of type qualifiers + * storage: a list of storage type qualifiers + * type: a list of type specifiers + * function: a list of function specifiers + * alignment: a list of alignment specifiers + + This method is given a declaration specifier, and a + new specifier of a given kind. + If `append` is True, the new specifier is added to the end of + the specifiers list, otherwise it's added at the beginning. + Returns the declaration specifier, with the new + specifier incorporated. + """ + spec = declspec or dict(qual=[], storage=[], type=[], function=[], alignment=[]) + + if append: + spec[kind].append(newspec) + else: + spec[kind].insert(0, newspec) + + return spec + + def _build_declarations(self, spec, decls, typedef_namespace=False): + """ Builds a list of declarations all sharing the given specifiers. + If typedef_namespace is true, each declared name is added + to the "typedef namespace", which also includes objects, + functions, and enum constants. + """ + is_typedef = 'typedef' in spec['storage'] + declarations = [] + + # Bit-fields are allowed to be unnamed. + if decls[0].get('bitsize') is not None: + pass + + # When redeclaring typedef names as identifiers in inner scopes, a + # problem can occur where the identifier gets grouped into + # spec['type'], leaving decl as None. This can only occur for the + # first declarator. + elif decls[0]['decl'] is None: + if len(spec['type']) < 2 or len(spec['type'][-1].names) != 1 or \ + not self._is_type_in_scope(spec['type'][-1].names[0]): + coord = '?' + for t in spec['type']: + if hasattr(t, 'coord'): + coord = t.coord + break + self._parse_error('Invalid declaration', coord) + + # Make this look as if it came from "direct_declarator:ID" + decls[0]['decl'] = c_ast.TypeDecl( + declname=spec['type'][-1].names[0], + type=None, + quals=None, + align=spec['alignment'], + coord=spec['type'][-1].coord) + # Remove the "new" type's name from the end of spec['type'] + del spec['type'][-1] + + # A similar problem can occur where the declaration ends up looking + # like an abstract declarator. Give it a name if this is the case. + elif not isinstance(decls[0]['decl'], ( + c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType)): + decls_0_tail = decls[0]['decl'] + while not isinstance(decls_0_tail, c_ast.TypeDecl): + decls_0_tail = decls_0_tail.type + if decls_0_tail.declname is None: + decls_0_tail.declname = spec['type'][-1].names[0] + del spec['type'][-1] + + for decl in decls: + assert decl['decl'] is not None + if is_typedef: + declaration = c_ast.Typedef( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl['decl'], + coord=decl['decl'].coord) + else: + declaration = c_ast.Decl( + name=None, + quals=spec['qual'], + align=spec['alignment'], + storage=spec['storage'], + funcspec=spec['function'], + type=decl['decl'], + init=decl.get('init'), + bitsize=decl.get('bitsize'), + coord=decl['decl'].coord) + + if isinstance(declaration.type, ( + c_ast.Enum, c_ast.Struct, c_ast.Union, + c_ast.IdentifierType)): + fixed_decl = declaration + else: + fixed_decl = self._fix_decl_name_type(declaration, spec['type']) + + # Add the type name defined by typedef to a + # symbol table (for usage in the lexer) + if typedef_namespace: + if is_typedef: + self._add_typedef_name(fixed_decl.name, fixed_decl.coord) + else: + self._add_identifier(fixed_decl.name, fixed_decl.coord) + + fixed_decl = fix_atomic_specifiers(fixed_decl) + declarations.append(fixed_decl) + + return declarations + + def _build_function_definition(self, spec, decl, param_decls, body): + """ Builds a function definition. + """ + if 'typedef' in spec['storage']: + self._parse_error("Invalid typedef", decl.coord) + + declaration = self._build_declarations( + spec=spec, + decls=[dict(decl=decl, init=None)], + typedef_namespace=True)[0] + + return c_ast.FuncDef( + decl=declaration, + param_decls=param_decls, + body=body, + coord=decl.coord) + + def _select_struct_union_class(self, token): + """ Given a token (either STRUCT or UNION), selects the + appropriate AST class. + """ + if token == 'struct': + return c_ast.Struct + else: + return c_ast.Union + + ## + ## Precedence and associativity of operators + ## + # If this changes, c_generator.CGenerator.precedence_map needs to change as + # well + precedence = ( + ('left', 'LOR'), + ('left', 'LAND'), + ('left', 'OR'), + ('left', 'XOR'), + ('left', 'AND'), + ('left', 'EQ', 'NE'), + ('left', 'GT', 'GE', 'LT', 'LE'), + ('left', 'RSHIFT', 'LSHIFT'), + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE', 'MOD') + ) + + ## + ## Grammar productions + ## Implementation of the BNF defined in K&R2 A.13 + ## + + # Wrapper around a translation unit, to allow for empty input. + # Not strictly part of the C99 Grammar, but useful in practice. + def p_translation_unit_or_empty(self, p): + """ translation_unit_or_empty : translation_unit + | empty + """ + if p[1] is None: + p[0] = c_ast.FileAST([]) + else: + p[0] = c_ast.FileAST(p[1]) + + def p_translation_unit_1(self, p): + """ translation_unit : external_declaration + """ + # Note: external_declaration is already a list + p[0] = p[1] + + def p_translation_unit_2(self, p): + """ translation_unit : translation_unit external_declaration + """ + p[1].extend(p[2]) + p[0] = p[1] + + # Declarations always come as lists (because they can be + # several in one line), so we wrap the function definition + # into a list as well, to make the return value of + # external_declaration homogeneous. + def p_external_declaration_1(self, p): + """ external_declaration : function_definition + """ + p[0] = [p[1]] + + def p_external_declaration_2(self, p): + """ external_declaration : declaration + """ + p[0] = p[1] + + def p_external_declaration_3(self, p): + """ external_declaration : pp_directive + | pppragma_directive + """ + p[0] = [p[1]] + + def p_external_declaration_4(self, p): + """ external_declaration : SEMI + """ + p[0] = [] + + def p_external_declaration_5(self, p): + """ external_declaration : static_assert + """ + p[0] = p[1] + + def p_static_assert_declaration(self, p): + """ static_assert : _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN + | _STATIC_ASSERT LPAREN constant_expression RPAREN + """ + if len(p) == 5: + p[0] = [c_ast.StaticAssert(p[3], None, self._token_coord(p, 1))] + else: + p[0] = [c_ast.StaticAssert(p[3], p[5], self._token_coord(p, 1))] + + def p_pp_directive(self, p): + """ pp_directive : PPHASH + """ + self._parse_error('Directives not supported yet', + self._token_coord(p, 1)) + + def p_pppragma_directive(self, p): + """ pppragma_directive : PPPRAGMA + | PPPRAGMA PPPRAGMASTR + """ + if len(p) == 3: + p[0] = c_ast.Pragma(p[2], self._token_coord(p, 2)) + else: + p[0] = c_ast.Pragma("", self._token_coord(p, 1)) + + # In function definitions, the declarator can be followed by + # a declaration list, for old "K&R style" function definitios. + def p_function_definition_1(self, p): + """ function_definition : id_declarator declaration_list_opt compound_statement + """ + # no declaration specifiers - 'int' becomes the default type + spec = dict( + qual=[], + alignment=[], + storage=[], + type=[c_ast.IdentifierType(['int'], + coord=self._token_coord(p, 1))], + function=[]) + + p[0] = self._build_function_definition( + spec=spec, + decl=p[1], + param_decls=p[2], + body=p[3]) + + def p_function_definition_2(self, p): + """ function_definition : declaration_specifiers id_declarator declaration_list_opt compound_statement + """ + spec = p[1] + + p[0] = self._build_function_definition( + spec=spec, + decl=p[2], + param_decls=p[3], + body=p[4]) + + # Note, according to C18 A.2.2 6.7.10 static_assert-declaration _Static_assert + # is a declaration, not a statement. We additionally recognise it as a statement + # to fix parsing of _Static_assert inside the functions. + # + def p_statement(self, p): + """ statement : labeled_statement + | expression_statement + | compound_statement + | selection_statement + | iteration_statement + | jump_statement + | pppragma_directive + | static_assert + """ + p[0] = p[1] + + # A pragma is generally considered a decorator rather than an actual + # statement. Still, for the purposes of analyzing an abstract syntax tree of + # C code, pragma's should not be ignored and were previously treated as a + # statement. This presents a problem for constructs that take a statement + # such as labeled_statements, selection_statements, and + # iteration_statements, causing a misleading structure in the AST. For + # example, consider the following C code. + # + # for (int i = 0; i < 3; i++) + # #pragma omp critical + # sum += 1; + # + # This code will compile and execute "sum += 1;" as the body of the for + # loop. Previous implementations of PyCParser would render the AST for this + # block of code as follows: + # + # For: + # DeclList: + # Decl: i, [], [], [] + # TypeDecl: i, [] + # IdentifierType: ['int'] + # Constant: int, 0 + # BinaryOp: < + # ID: i + # Constant: int, 3 + # UnaryOp: p++ + # ID: i + # Pragma: omp critical + # Assignment: += + # ID: sum + # Constant: int, 1 + # + # This AST misleadingly takes the Pragma as the body of the loop and the + # assignment then becomes a sibling of the loop. + # + # To solve edge cases like these, the pragmacomp_or_statement rule groups + # a pragma and its following statement (which would otherwise be orphaned) + # using a compound block, effectively turning the above code into: + # + # for (int i = 0; i < 3; i++) { + # #pragma omp critical + # sum += 1; + # } + def p_pragmacomp_or_statement(self, p): + """ pragmacomp_or_statement : pppragma_directive statement + | statement + """ + if isinstance(p[1], c_ast.Pragma) and len(p) == 3: + p[0] = c_ast.Compound( + block_items=[p[1], p[2]], + coord=self._token_coord(p, 1)) + else: + p[0] = p[1] + + # In C, declarations can come several in a line: + # int x, *px, romulo = 5; + # + # However, for the AST, we will split them to separate Decl + # nodes. + # + # This rule splits its declarations and always returns a list + # of Decl nodes, even if it's one element long. + # + def p_decl_body(self, p): + """ decl_body : declaration_specifiers init_declarator_list_opt + | declaration_specifiers_no_type id_init_declarator_list_opt + """ + spec = p[1] + + # p[2] (init_declarator_list_opt) is either a list or None + # + if p[2] is None: + # By the standard, you must have at least one declarator unless + # declaring a structure tag, a union tag, or the members of an + # enumeration. + # + ty = spec['type'] + s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum) + if len(ty) == 1 and isinstance(ty[0], s_u_or_e): + decls = [c_ast.Decl( + name=None, + quals=spec['qual'], + align=spec['alignment'], + storage=spec['storage'], + funcspec=spec['function'], + type=ty[0], + init=None, + bitsize=None, + coord=ty[0].coord)] + + # However, this case can also occur on redeclared identifiers in + # an inner scope. The trouble is that the redeclared type's name + # gets grouped into declaration_specifiers; _build_declarations + # compensates for this. + # + else: + decls = self._build_declarations( + spec=spec, + decls=[dict(decl=None, init=None)], + typedef_namespace=True) + + else: + decls = self._build_declarations( + spec=spec, + decls=p[2], + typedef_namespace=True) + + p[0] = decls + + # The declaration has been split to a decl_body sub-rule and + # SEMI, because having them in a single rule created a problem + # for defining typedefs. + # + # If a typedef line was directly followed by a line using the + # type defined with the typedef, the type would not be + # recognized. This is because to reduce the declaration rule, + # the parser's lookahead asked for the token after SEMI, which + # was the type from the next line, and the lexer had no chance + # to see the updated type symbol table. + # + # Splitting solves this problem, because after seeing SEMI, + # the parser reduces decl_body, which actually adds the new + # type into the table to be seen by the lexer before the next + # line is reached. + def p_declaration(self, p): + """ declaration : decl_body SEMI + """ + p[0] = p[1] + + # Since each declaration is a list of declarations, this + # rule will combine all the declarations and return a single + # list + # + def p_declaration_list(self, p): + """ declaration_list : declaration + | declaration_list declaration + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + # To know when declaration-specifiers end and declarators begin, + # we require declaration-specifiers to have at least one + # type-specifier, and disallow typedef-names after we've seen any + # type-specifier. These are both required by the spec. + # + def p_declaration_specifiers_no_type_1(self, p): + """ declaration_specifiers_no_type : type_qualifier declaration_specifiers_no_type_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'qual') + + def p_declaration_specifiers_no_type_2(self, p): + """ declaration_specifiers_no_type : storage_class_specifier declaration_specifiers_no_type_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'storage') + + def p_declaration_specifiers_no_type_3(self, p): + """ declaration_specifiers_no_type : function_specifier declaration_specifiers_no_type_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'function') + + # Without this, `typedef _Atomic(T) U` will parse incorrectly because the + # _Atomic qualifier will match, instead of the specifier. + def p_declaration_specifiers_no_type_4(self, p): + """ declaration_specifiers_no_type : atomic_specifier declaration_specifiers_no_type_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'type') + + def p_declaration_specifiers_no_type_5(self, p): + """ declaration_specifiers_no_type : alignment_specifier declaration_specifiers_no_type_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'alignment') + + def p_declaration_specifiers_1(self, p): + """ declaration_specifiers : declaration_specifiers type_qualifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'qual', append=True) + + def p_declaration_specifiers_2(self, p): + """ declaration_specifiers : declaration_specifiers storage_class_specifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'storage', append=True) + + def p_declaration_specifiers_3(self, p): + """ declaration_specifiers : declaration_specifiers function_specifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'function', append=True) + + def p_declaration_specifiers_4(self, p): + """ declaration_specifiers : declaration_specifiers type_specifier_no_typeid + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True) + + def p_declaration_specifiers_5(self, p): + """ declaration_specifiers : type_specifier + """ + p[0] = self._add_declaration_specifier(None, p[1], 'type') + + def p_declaration_specifiers_6(self, p): + """ declaration_specifiers : declaration_specifiers_no_type type_specifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True) + + def p_declaration_specifiers_7(self, p): + """ declaration_specifiers : declaration_specifiers alignment_specifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'alignment', append=True) + + def p_storage_class_specifier(self, p): + """ storage_class_specifier : AUTO + | REGISTER + | STATIC + | EXTERN + | TYPEDEF + | _THREAD_LOCAL + """ + p[0] = p[1] + + def p_function_specifier(self, p): + """ function_specifier : INLINE + | _NORETURN + """ + p[0] = p[1] + + def p_type_specifier_no_typeid(self, p): + """ type_specifier_no_typeid : VOID + | _BOOL + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | _COMPLEX + | SIGNED + | UNSIGNED + | __INT128 + """ + p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1)) + + def p_type_specifier(self, p): + """ type_specifier : typedef_name + | enum_specifier + | struct_or_union_specifier + | type_specifier_no_typeid + | atomic_specifier + """ + p[0] = p[1] + + # See section 6.7.2.4 of the C11 standard. + def p_atomic_specifier(self, p): + """ atomic_specifier : _ATOMIC LPAREN type_name RPAREN + """ + typ = p[3] + typ.quals.append('_Atomic') + p[0] = typ + + def p_type_qualifier(self, p): + """ type_qualifier : CONST + | RESTRICT + | VOLATILE + | _ATOMIC + """ + p[0] = p[1] + + def p_init_declarator_list(self, p): + """ init_declarator_list : init_declarator + | init_declarator_list COMMA init_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # Returns a {decl=<declarator> : init=<initializer>} dictionary + # If there's no initializer, uses None + # + def p_init_declarator(self, p): + """ init_declarator : declarator + | declarator EQUALS initializer + """ + p[0] = dict(decl=p[1], init=(p[3] if len(p) > 2 else None)) + + def p_id_init_declarator_list(self, p): + """ id_init_declarator_list : id_init_declarator + | id_init_declarator_list COMMA init_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + def p_id_init_declarator(self, p): + """ id_init_declarator : id_declarator + | id_declarator EQUALS initializer + """ + p[0] = dict(decl=p[1], init=(p[3] if len(p) > 2 else None)) + + # Require at least one type specifier in a specifier-qualifier-list + # + def p_specifier_qualifier_list_1(self, p): + """ specifier_qualifier_list : specifier_qualifier_list type_specifier_no_typeid + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True) + + def p_specifier_qualifier_list_2(self, p): + """ specifier_qualifier_list : specifier_qualifier_list type_qualifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'qual', append=True) + + def p_specifier_qualifier_list_3(self, p): + """ specifier_qualifier_list : type_specifier + """ + p[0] = self._add_declaration_specifier(None, p[1], 'type') + + def p_specifier_qualifier_list_4(self, p): + """ specifier_qualifier_list : type_qualifier_list type_specifier + """ + p[0] = dict(qual=p[1], alignment=[], storage=[], type=[p[2]], function=[]) + + def p_specifier_qualifier_list_5(self, p): + """ specifier_qualifier_list : alignment_specifier + """ + p[0] = dict(qual=[], alignment=[p[1]], storage=[], type=[], function=[]) + + def p_specifier_qualifier_list_6(self, p): + """ specifier_qualifier_list : specifier_qualifier_list alignment_specifier + """ + p[0] = self._add_declaration_specifier(p[1], p[2], 'alignment') + + # TYPEID is allowed here (and in other struct/enum related tag names), because + # struct/enum tags reside in their own namespace and can be named the same as types + # + def p_struct_or_union_specifier_1(self, p): + """ struct_or_union_specifier : struct_or_union ID + | struct_or_union TYPEID + """ + klass = self._select_struct_union_class(p[1]) + # None means no list of members + p[0] = klass( + name=p[2], + decls=None, + coord=self._token_coord(p, 2)) + + def p_struct_or_union_specifier_2(self, p): + """ struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close + | struct_or_union brace_open brace_close + """ + klass = self._select_struct_union_class(p[1]) + if len(p) == 4: + # Empty sequence means an empty list of members + p[0] = klass( + name=None, + decls=[], + coord=self._token_coord(p, 2)) + else: + p[0] = klass( + name=None, + decls=p[3], + coord=self._token_coord(p, 2)) + + + def p_struct_or_union_specifier_3(self, p): + """ struct_or_union_specifier : struct_or_union ID brace_open struct_declaration_list brace_close + | struct_or_union ID brace_open brace_close + | struct_or_union TYPEID brace_open struct_declaration_list brace_close + | struct_or_union TYPEID brace_open brace_close + """ + klass = self._select_struct_union_class(p[1]) + if len(p) == 5: + # Empty sequence means an empty list of members + p[0] = klass( + name=p[2], + decls=[], + coord=self._token_coord(p, 2)) + else: + p[0] = klass( + name=p[2], + decls=p[4], + coord=self._token_coord(p, 2)) + + def p_struct_or_union(self, p): + """ struct_or_union : STRUCT + | UNION + """ + p[0] = p[1] + + # Combine all declarations into a single list + # + def p_struct_declaration_list(self, p): + """ struct_declaration_list : struct_declaration + | struct_declaration_list struct_declaration + """ + if len(p) == 2: + p[0] = p[1] or [] + else: + p[0] = p[1] + (p[2] or []) + + def p_struct_declaration_1(self, p): + """ struct_declaration : specifier_qualifier_list struct_declarator_list_opt SEMI + """ + spec = p[1] + assert 'typedef' not in spec['storage'] + + if p[2] is not None: + decls = self._build_declarations( + spec=spec, + decls=p[2]) + + elif len(spec['type']) == 1: + # Anonymous struct/union, gcc extension, C1x feature. + # Although the standard only allows structs/unions here, I see no + # reason to disallow other types since some compilers have typedefs + # here, and pycparser isn't about rejecting all invalid code. + # + node = spec['type'][0] + if isinstance(node, c_ast.Node): + decl_type = node + else: + decl_type = c_ast.IdentifierType(node) + + decls = self._build_declarations( + spec=spec, + decls=[dict(decl=decl_type)]) + + else: + # Structure/union members can have the same names as typedefs. + # The trouble is that the member's name gets grouped into + # specifier_qualifier_list; _build_declarations compensates. + # + decls = self._build_declarations( + spec=spec, + decls=[dict(decl=None, init=None)]) + + p[0] = decls + + def p_struct_declaration_2(self, p): + """ struct_declaration : SEMI + """ + p[0] = None + + def p_struct_declaration_3(self, p): + """ struct_declaration : pppragma_directive + """ + p[0] = [p[1]] + + def p_struct_declarator_list(self, p): + """ struct_declarator_list : struct_declarator + | struct_declarator_list COMMA struct_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # struct_declarator passes up a dict with the keys: decl (for + # the underlying declarator) and bitsize (for the bitsize) + # + def p_struct_declarator_1(self, p): + """ struct_declarator : declarator + """ + p[0] = {'decl': p[1], 'bitsize': None} + + def p_struct_declarator_2(self, p): + """ struct_declarator : declarator COLON constant_expression + | COLON constant_expression + """ + if len(p) > 3: + p[0] = {'decl': p[1], 'bitsize': p[3]} + else: + p[0] = {'decl': c_ast.TypeDecl(None, None, None, None), 'bitsize': p[2]} + + def p_enum_specifier_1(self, p): + """ enum_specifier : ENUM ID + | ENUM TYPEID + """ + p[0] = c_ast.Enum(p[2], None, self._token_coord(p, 1)) + + def p_enum_specifier_2(self, p): + """ enum_specifier : ENUM brace_open enumerator_list brace_close + """ + p[0] = c_ast.Enum(None, p[3], self._token_coord(p, 1)) + + def p_enum_specifier_3(self, p): + """ enum_specifier : ENUM ID brace_open enumerator_list brace_close + | ENUM TYPEID brace_open enumerator_list brace_close + """ + p[0] = c_ast.Enum(p[2], p[4], self._token_coord(p, 1)) + + def p_enumerator_list(self, p): + """ enumerator_list : enumerator + | enumerator_list COMMA + | enumerator_list COMMA enumerator + """ + if len(p) == 2: + p[0] = c_ast.EnumeratorList([p[1]], p[1].coord) + elif len(p) == 3: + p[0] = p[1] + else: + p[1].enumerators.append(p[3]) + p[0] = p[1] + + def p_alignment_specifier(self, p): + """ alignment_specifier : _ALIGNAS LPAREN type_name RPAREN + | _ALIGNAS LPAREN constant_expression RPAREN + """ + p[0] = c_ast.Alignas(p[3], self._token_coord(p, 1)) + + def p_enumerator(self, p): + """ enumerator : ID + | ID EQUALS constant_expression + """ + if len(p) == 2: + enumerator = c_ast.Enumerator( + p[1], None, + self._token_coord(p, 1)) + else: + enumerator = c_ast.Enumerator( + p[1], p[3], + self._token_coord(p, 1)) + self._add_identifier(enumerator.name, enumerator.coord) + + p[0] = enumerator + + def p_declarator(self, p): + """ declarator : id_declarator + | typeid_declarator + """ + p[0] = p[1] + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_xxx_declarator_1(self, p): + """ xxx_declarator : direct_xxx_declarator + """ + p[0] = p[1] + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_xxx_declarator_2(self, p): + """ xxx_declarator : pointer direct_xxx_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_direct_xxx_declarator_1(self, p): + """ direct_xxx_declarator : yyy + """ + p[0] = c_ast.TypeDecl( + declname=p[1], + type=None, + quals=None, + align=None, + coord=self._token_coord(p, 1)) + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID')) + def p_direct_xxx_declarator_2(self, p): + """ direct_xxx_declarator : LPAREN xxx_declarator RPAREN + """ + p[0] = p[2] + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_direct_xxx_declarator_3(self, p): + """ direct_xxx_declarator : direct_xxx_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET + """ + quals = (p[3] if len(p) > 5 else []) or [] + # Accept dimension qualifiers + # Per C99 6.7.5.3 p7 + arr = c_ast.ArrayDecl( + type=None, + dim=p[4] if len(p) > 5 else p[3], + dim_quals=quals, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_direct_xxx_declarator_4(self, p): + """ direct_xxx_declarator : direct_xxx_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET + | direct_xxx_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET + """ + # Using slice notation for PLY objects doesn't work in Python 3 for the + # version of PLY embedded with pycparser; see PLY Google Code issue 30. + # Work around that here by listing the two elements separately. + listed_quals = [item if isinstance(item, list) else [item] + for item in [p[3],p[4]]] + dim_quals = [qual for sublist in listed_quals for qual in sublist + if qual is not None] + arr = c_ast.ArrayDecl( + type=None, + dim=p[5], + dim_quals=dim_quals, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + # Special for VLAs + # + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_direct_xxx_declarator_5(self, p): + """ direct_xxx_declarator : direct_xxx_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=c_ast.ID(p[4], self._token_coord(p, 4)), + dim_quals=p[3] if p[3] is not None else [], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID')) + def p_direct_xxx_declarator_6(self, p): + """ direct_xxx_declarator : direct_xxx_declarator LPAREN parameter_type_list RPAREN + | direct_xxx_declarator LPAREN identifier_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + # To see why _get_yacc_lookahead_token is needed, consider: + # typedef char TT; + # void foo(int TT) { TT = 10; } + # Outside the function, TT is a typedef, but inside (starting and + # ending with the braces) it's a parameter. The trouble begins with + # yacc's lookahead token. We don't know if we're declaring or + # defining a function until we see LBRACE, but if we wait for yacc to + # trigger a rule on that token, then TT will have already been read + # and incorrectly interpreted as TYPEID. We need to add the + # parameters to the scope the moment the lexer sees LBRACE. + # + if self._get_yacc_lookahead_token().type == "LBRACE": + if func.args is not None: + for param in func.args.params: + if isinstance(param, c_ast.EllipsisParam): break + self._add_identifier(param.name, param.coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_pointer(self, p): + """ pointer : TIMES type_qualifier_list_opt + | TIMES type_qualifier_list_opt pointer + """ + coord = self._token_coord(p, 1) + # Pointer decls nest from inside out. This is important when different + # levels have different qualifiers. For example: + # + # char * const * p; + # + # Means "pointer to const pointer to char" + # + # While: + # + # char ** const p; + # + # Means "const pointer to pointer to char" + # + # So when we construct PtrDecl nestings, the leftmost pointer goes in + # as the most nested type. + nested_type = c_ast.PtrDecl(quals=p[2] or [], type=None, coord=coord) + if len(p) > 3: + tail_type = p[3] + while tail_type.type is not None: + tail_type = tail_type.type + tail_type.type = nested_type + p[0] = p[3] + else: + p[0] = nested_type + + def p_type_qualifier_list(self, p): + """ type_qualifier_list : type_qualifier + | type_qualifier_list type_qualifier + """ + p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]] + + def p_parameter_type_list(self, p): + """ parameter_type_list : parameter_list + | parameter_list COMMA ELLIPSIS + """ + if len(p) > 2: + p[1].params.append(c_ast.EllipsisParam(self._token_coord(p, 3))) + + p[0] = p[1] + + def p_parameter_list(self, p): + """ parameter_list : parameter_declaration + | parameter_list COMMA parameter_declaration + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + # From ISO/IEC 9899:TC2, 6.7.5.3.11: + # "If, in a parameter declaration, an identifier can be treated either + # as a typedef name or as a parameter name, it shall be taken as a + # typedef name." + # + # Inside a parameter declaration, once we've reduced declaration specifiers, + # if we shift in an LPAREN and see a TYPEID, it could be either an abstract + # declarator or a declarator nested inside parens. This rule tells us to + # always treat it as an abstract declarator. Therefore, we only accept + # `id_declarator`s and `typeid_noparen_declarator`s. + def p_parameter_declaration_1(self, p): + """ parameter_declaration : declaration_specifiers id_declarator + | declaration_specifiers typeid_noparen_declarator + """ + spec = p[1] + if not spec['type']: + spec['type'] = [c_ast.IdentifierType(['int'], + coord=self._token_coord(p, 1))] + p[0] = self._build_declarations( + spec=spec, + decls=[dict(decl=p[2])])[0] + + def p_parameter_declaration_2(self, p): + """ parameter_declaration : declaration_specifiers abstract_declarator_opt + """ + spec = p[1] + if not spec['type']: + spec['type'] = [c_ast.IdentifierType(['int'], + coord=self._token_coord(p, 1))] + + # Parameters can have the same names as typedefs. The trouble is that + # the parameter's name gets grouped into declaration_specifiers, making + # it look like an old-style declaration; compensate. + # + if len(spec['type']) > 1 and len(spec['type'][-1].names) == 1 and \ + self._is_type_in_scope(spec['type'][-1].names[0]): + decl = self._build_declarations( + spec=spec, + decls=[dict(decl=p[2], init=None)])[0] + + # This truly is an old-style parameter declaration + # + else: + decl = c_ast.Typename( + name='', + quals=spec['qual'], + align=None, + type=p[2] or c_ast.TypeDecl(None, None, None, None), + coord=self._token_coord(p, 2)) + typename = spec['type'] + decl = self._fix_decl_name_type(decl, typename) + + p[0] = decl + + def p_identifier_list(self, p): + """ identifier_list : identifier + | identifier_list COMMA identifier + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + def p_initializer_1(self, p): + """ initializer : assignment_expression + """ + p[0] = p[1] + + def p_initializer_2(self, p): + """ initializer : brace_open initializer_list_opt brace_close + | brace_open initializer_list COMMA brace_close + """ + if p[2] is None: + p[0] = c_ast.InitList([], self._token_coord(p, 1)) + else: + p[0] = p[2] + + def p_initializer_list(self, p): + """ initializer_list : designation_opt initializer + | initializer_list COMMA designation_opt initializer + """ + if len(p) == 3: # single initializer + init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2]) + p[0] = c_ast.InitList([init], p[2].coord) + else: + init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4]) + p[1].exprs.append(init) + p[0] = p[1] + + def p_designation(self, p): + """ designation : designator_list EQUALS + """ + p[0] = p[1] + + # Designators are represented as a list of nodes, in the order in which + # they're written in the code. + # + def p_designator_list(self, p): + """ designator_list : designator + | designator_list designator + """ + p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]] + + def p_designator(self, p): + """ designator : LBRACKET constant_expression RBRACKET + | PERIOD identifier + """ + p[0] = p[2] + + def p_type_name(self, p): + """ type_name : specifier_qualifier_list abstract_declarator_opt + """ + typename = c_ast.Typename( + name='', + quals=p[1]['qual'][:], + align=None, + type=p[2] or c_ast.TypeDecl(None, None, None, None), + coord=self._token_coord(p, 2)) + + p[0] = self._fix_decl_name_type(typename, p[1]['type']) + + def p_abstract_declarator_1(self, p): + """ abstract_declarator : pointer + """ + dummytype = c_ast.TypeDecl(None, None, None, None) + p[0] = self._type_modify_decl( + decl=dummytype, + modifier=p[1]) + + def p_abstract_declarator_2(self, p): + """ abstract_declarator : pointer direct_abstract_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + def p_abstract_declarator_3(self, p): + """ abstract_declarator : direct_abstract_declarator + """ + p[0] = p[1] + + # Creating and using direct_abstract_declarator_opt here + # instead of listing both direct_abstract_declarator and the + # lack of it in the beginning of _1 and _2 caused two + # shift/reduce errors. + # + def p_direct_abstract_declarator_1(self, p): + """ direct_abstract_declarator : LPAREN abstract_declarator RPAREN """ + p[0] = p[2] + + def p_direct_abstract_declarator_2(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=p[3], + dim_quals=[], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_abstract_declarator_3(self, p): + """ direct_abstract_declarator : LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET + """ + quals = (p[2] if len(p) > 4 else []) or [] + p[0] = c_ast.ArrayDecl( + type=c_ast.TypeDecl(None, None, None, None), + dim=p[3] if len(p) > 4 else p[2], + dim_quals=quals, + coord=self._token_coord(p, 1)) + + def p_direct_abstract_declarator_4(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LBRACKET TIMES RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=c_ast.ID(p[3], self._token_coord(p, 3)), + dim_quals=[], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_abstract_declarator_5(self, p): + """ direct_abstract_declarator : LBRACKET TIMES RBRACKET + """ + p[0] = c_ast.ArrayDecl( + type=c_ast.TypeDecl(None, None, None, None), + dim=c_ast.ID(p[3], self._token_coord(p, 3)), + dim_quals=[], + coord=self._token_coord(p, 1)) + + def p_direct_abstract_declarator_6(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_direct_abstract_declarator_7(self, p): + """ direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN + """ + p[0] = c_ast.FuncDecl( + args=p[2], + type=c_ast.TypeDecl(None, None, None, None), + coord=self._token_coord(p, 1)) + + # declaration is a list, statement isn't. To make it consistent, block_item + # will always be a list + # + def p_block_item(self, p): + """ block_item : declaration + | statement + """ + p[0] = p[1] if isinstance(p[1], list) else [p[1]] + + # Since we made block_item a list, this just combines lists + # + def p_block_item_list(self, p): + """ block_item_list : block_item + | block_item_list block_item + """ + # Empty block items (plain ';') produce [None], so ignore them + p[0] = p[1] if (len(p) == 2 or p[2] == [None]) else p[1] + p[2] + + def p_compound_statement_1(self, p): + """ compound_statement : brace_open block_item_list_opt brace_close """ + p[0] = c_ast.Compound( + block_items=p[2], + coord=self._token_coord(p, 1)) + + def p_labeled_statement_1(self, p): + """ labeled_statement : ID COLON pragmacomp_or_statement """ + p[0] = c_ast.Label(p[1], p[3], self._token_coord(p, 1)) + + def p_labeled_statement_2(self, p): + """ labeled_statement : CASE constant_expression COLON pragmacomp_or_statement """ + p[0] = c_ast.Case(p[2], [p[4]], self._token_coord(p, 1)) + + def p_labeled_statement_3(self, p): + """ labeled_statement : DEFAULT COLON pragmacomp_or_statement """ + p[0] = c_ast.Default([p[3]], self._token_coord(p, 1)) + + def p_selection_statement_1(self, p): + """ selection_statement : IF LPAREN expression RPAREN pragmacomp_or_statement """ + p[0] = c_ast.If(p[3], p[5], None, self._token_coord(p, 1)) + + def p_selection_statement_2(self, p): + """ selection_statement : IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement """ + p[0] = c_ast.If(p[3], p[5], p[7], self._token_coord(p, 1)) + + def p_selection_statement_3(self, p): + """ selection_statement : SWITCH LPAREN expression RPAREN pragmacomp_or_statement """ + p[0] = fix_switch_cases( + c_ast.Switch(p[3], p[5], self._token_coord(p, 1))) + + def p_iteration_statement_1(self, p): + """ iteration_statement : WHILE LPAREN expression RPAREN pragmacomp_or_statement """ + p[0] = c_ast.While(p[3], p[5], self._token_coord(p, 1)) + + def p_iteration_statement_2(self, p): + """ iteration_statement : DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI """ + p[0] = c_ast.DoWhile(p[5], p[2], self._token_coord(p, 1)) + + def p_iteration_statement_3(self, p): + """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement """ + p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._token_coord(p, 1)) + + def p_iteration_statement_4(self, p): + """ iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement """ + p[0] = c_ast.For(c_ast.DeclList(p[3], self._token_coord(p, 1)), + p[4], p[6], p[8], self._token_coord(p, 1)) + + def p_jump_statement_1(self, p): + """ jump_statement : GOTO ID SEMI """ + p[0] = c_ast.Goto(p[2], self._token_coord(p, 1)) + + def p_jump_statement_2(self, p): + """ jump_statement : BREAK SEMI """ + p[0] = c_ast.Break(self._token_coord(p, 1)) + + def p_jump_statement_3(self, p): + """ jump_statement : CONTINUE SEMI """ + p[0] = c_ast.Continue(self._token_coord(p, 1)) + + def p_jump_statement_4(self, p): + """ jump_statement : RETURN expression SEMI + | RETURN SEMI + """ + p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._token_coord(p, 1)) + + def p_expression_statement(self, p): + """ expression_statement : expression_opt SEMI """ + if p[1] is None: + p[0] = c_ast.EmptyStatement(self._token_coord(p, 2)) + else: + p[0] = p[1] + + def p_expression(self, p): + """ expression : assignment_expression + | expression COMMA assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + if not isinstance(p[1], c_ast.ExprList): + p[1] = c_ast.ExprList([p[1]], p[1].coord) + + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_parenthesized_compound_expression(self, p): + """ assignment_expression : LPAREN compound_statement RPAREN """ + p[0] = p[2] + + def p_typedef_name(self, p): + """ typedef_name : TYPEID """ + p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1)) + + def p_assignment_expression(self, p): + """ assignment_expression : conditional_expression + | unary_expression assignment_operator assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord) + + # K&R2 defines these as many separate rules, to encode + # precedence and associativity. Why work hard ? I'll just use + # the built in precedence/associativity specification feature + # of PLY. (see precedence declaration above) + # + def p_assignment_operator(self, p): + """ assignment_operator : EQUALS + | XOREQUAL + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + """ + p[0] = p[1] + + def p_constant_expression(self, p): + """ constant_expression : conditional_expression """ + p[0] = p[1] + + def p_conditional_expression(self, p): + """ conditional_expression : binary_expression + | binary_expression CONDOP expression COLON conditional_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord) + + def p_binary_expression(self, p): + """ binary_expression : cast_expression + | binary_expression TIMES binary_expression + | binary_expression DIVIDE binary_expression + | binary_expression MOD binary_expression + | binary_expression PLUS binary_expression + | binary_expression MINUS binary_expression + | binary_expression RSHIFT binary_expression + | binary_expression LSHIFT binary_expression + | binary_expression LT binary_expression + | binary_expression LE binary_expression + | binary_expression GE binary_expression + | binary_expression GT binary_expression + | binary_expression EQ binary_expression + | binary_expression NE binary_expression + | binary_expression AND binary_expression + | binary_expression OR binary_expression + | binary_expression XOR binary_expression + | binary_expression LAND binary_expression + | binary_expression LOR binary_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord) + + def p_cast_expression_1(self, p): + """ cast_expression : unary_expression """ + p[0] = p[1] + + def p_cast_expression_2(self, p): + """ cast_expression : LPAREN type_name RPAREN cast_expression """ + p[0] = c_ast.Cast(p[2], p[4], self._token_coord(p, 1)) + + def p_unary_expression_1(self, p): + """ unary_expression : postfix_expression """ + p[0] = p[1] + + def p_unary_expression_2(self, p): + """ unary_expression : PLUSPLUS unary_expression + | MINUSMINUS unary_expression + | unary_operator cast_expression + """ + p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord) + + def p_unary_expression_3(self, p): + """ unary_expression : SIZEOF unary_expression + | SIZEOF LPAREN type_name RPAREN + | _ALIGNOF LPAREN type_name RPAREN + """ + p[0] = c_ast.UnaryOp( + p[1], + p[2] if len(p) == 3 else p[3], + self._token_coord(p, 1)) + + def p_unary_operator(self, p): + """ unary_operator : AND + | TIMES + | PLUS + | MINUS + | NOT + | LNOT + """ + p[0] = p[1] + + def p_postfix_expression_1(self, p): + """ postfix_expression : primary_expression """ + p[0] = p[1] + + def p_postfix_expression_2(self, p): + """ postfix_expression : postfix_expression LBRACKET expression RBRACKET """ + p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord) + + def p_postfix_expression_3(self, p): + """ postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN + | postfix_expression LPAREN RPAREN + """ + p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None, p[1].coord) + + def p_postfix_expression_4(self, p): + """ postfix_expression : postfix_expression PERIOD ID + | postfix_expression PERIOD TYPEID + | postfix_expression ARROW ID + | postfix_expression ARROW TYPEID + """ + field = c_ast.ID(p[3], self._token_coord(p, 3)) + p[0] = c_ast.StructRef(p[1], p[2], field, p[1].coord) + + def p_postfix_expression_5(self, p): + """ postfix_expression : postfix_expression PLUSPLUS + | postfix_expression MINUSMINUS + """ + p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord) + + def p_postfix_expression_6(self, p): + """ postfix_expression : LPAREN type_name RPAREN brace_open initializer_list brace_close + | LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close + """ + p[0] = c_ast.CompoundLiteral(p[2], p[5]) + + def p_primary_expression_1(self, p): + """ primary_expression : identifier """ + p[0] = p[1] + + def p_primary_expression_2(self, p): + """ primary_expression : constant """ + p[0] = p[1] + + def p_primary_expression_3(self, p): + """ primary_expression : unified_string_literal + | unified_wstring_literal + """ + p[0] = p[1] + + def p_primary_expression_4(self, p): + """ primary_expression : LPAREN expression RPAREN """ + p[0] = p[2] + + def p_primary_expression_5(self, p): + """ primary_expression : OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN + """ + coord = self._token_coord(p, 1) + p[0] = c_ast.FuncCall(c_ast.ID(p[1], coord), + c_ast.ExprList([p[3], p[5]], coord), + coord) + + def p_offsetof_member_designator(self, p): + """ offsetof_member_designator : identifier + | offsetof_member_designator PERIOD identifier + | offsetof_member_designator LBRACKET expression RBRACKET + """ + if len(p) == 2: + p[0] = p[1] + elif len(p) == 4: + p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord) + elif len(p) == 5: + p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord) + else: + raise NotImplementedError("Unexpected parsing state. len(p): %u" % len(p)) + + def p_argument_expression_list(self, p): + """ argument_expression_list : assignment_expression + | argument_expression_list COMMA assignment_expression + """ + if len(p) == 2: # single expr + p[0] = c_ast.ExprList([p[1]], p[1].coord) + else: + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_identifier(self, p): + """ identifier : ID """ + p[0] = c_ast.ID(p[1], self._token_coord(p, 1)) + + def p_constant_1(self, p): + """ constant : INT_CONST_DEC + | INT_CONST_OCT + | INT_CONST_HEX + | INT_CONST_BIN + | INT_CONST_CHAR + """ + uCount = 0 + lCount = 0 + for x in p[1][-3:]: + if x in ('l', 'L'): + lCount += 1 + elif x in ('u', 'U'): + uCount += 1 + t = '' + if uCount > 1: + raise ValueError('Constant cannot have more than one u/U suffix.') + elif lCount > 2: + raise ValueError('Constant cannot have more than two l/L suffix.') + prefix = 'unsigned ' * uCount + 'long ' * lCount + p[0] = c_ast.Constant( + prefix + 'int', p[1], self._token_coord(p, 1)) + + def p_constant_2(self, p): + """ constant : FLOAT_CONST + | HEX_FLOAT_CONST + """ + if 'x' in p[1].lower(): + t = 'float' + else: + if p[1][-1] in ('f', 'F'): + t = 'float' + elif p[1][-1] in ('l', 'L'): + t = 'long double' + else: + t = 'double' + + p[0] = c_ast.Constant( + t, p[1], self._token_coord(p, 1)) + + def p_constant_3(self, p): + """ constant : CHAR_CONST + | WCHAR_CONST + | U8CHAR_CONST + | U16CHAR_CONST + | U32CHAR_CONST + """ + p[0] = c_ast.Constant( + 'char', p[1], self._token_coord(p, 1)) + + # The "unified" string and wstring literal rules are for supporting + # concatenation of adjacent string literals. + # I.e. "hello " "world" is seen by the C compiler as a single string literal + # with the value "hello world" + # + def p_unified_string_literal(self, p): + """ unified_string_literal : STRING_LITERAL + | unified_string_literal STRING_LITERAL + """ + if len(p) == 2: # single literal + p[0] = c_ast.Constant( + 'string', p[1], self._token_coord(p, 1)) + else: + p[1].value = p[1].value[:-1] + p[2][1:] + p[0] = p[1] + + def p_unified_wstring_literal(self, p): + """ unified_wstring_literal : WSTRING_LITERAL + | U8STRING_LITERAL + | U16STRING_LITERAL + | U32STRING_LITERAL + | unified_wstring_literal WSTRING_LITERAL + | unified_wstring_literal U8STRING_LITERAL + | unified_wstring_literal U16STRING_LITERAL + | unified_wstring_literal U32STRING_LITERAL + """ + if len(p) == 2: # single literal + p[0] = c_ast.Constant( + 'string', p[1], self._token_coord(p, 1)) + else: + p[1].value = p[1].value.rstrip()[:-1] + p[2][2:] + p[0] = p[1] + + def p_brace_open(self, p): + """ brace_open : LBRACE + """ + p[0] = p[1] + p.set_lineno(0, p.lineno(1)) + + def p_brace_close(self, p): + """ brace_close : RBRACE + """ + p[0] = p[1] + p.set_lineno(0, p.lineno(1)) + + def p_empty(self, p): + 'empty : ' + p[0] = None + + def p_error(self, p): + # If error recovery is added here in the future, make sure + # _get_yacc_lookahead_token still works! + # + if p: + self._parse_error( + 'before: %s' % p.value, + self._coord(lineno=p.lineno, + column=self.clex.find_tok_column(p))) + else: + self._parse_error('At end of input', self.clex.filename) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/lextab.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/lextab.py new file mode 100644 index 0000000000000000000000000000000000000000..444b4656d5cec7bcbcf52a05823ec3d2fd6f29af --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/lextab.py @@ -0,0 +1,10 @@ +# lextab.py. This file automatically created by PLY (version 3.10). Don't edit! +_tabversion = '3.10' +_lextokens = set(('INT_CONST_CHAR', 'VOID', 'LBRACKET', 'WCHAR_CONST', 'FLOAT_CONST', 'MINUS', 'RPAREN', 'STRUCT', 'LONG', 'PLUS', 'ELLIPSIS', 'U32STRING_LITERAL', 'GT', 'GOTO', 'ENUM', 'PERIOD', 'GE', 'INT_CONST_DEC', 'ARROW', '_STATIC_ASSERT', '__INT128', 'HEX_FLOAT_CONST', 'DOUBLE', 'MINUSEQUAL', 'INT_CONST_OCT', 'TIMESEQUAL', 'OR', 'SHORT', 'RETURN', 'RSHIFTEQUAL', '_ALIGNAS', 'RESTRICT', 'STATIC', 'SIZEOF', 'UNSIGNED', 'PLUSPLUS', 'COLON', 'WSTRING_LITERAL', 'DIVIDE', 'FOR', 'UNION', 'EQUALS', 'ELSE', 'ANDEQUAL', 'EQ', 'AND', 'TYPEID', 'LBRACE', 'PPHASH', 'INT', 'SIGNED', 'CONTINUE', 'NOT', 'OREQUAL', 'MOD', 'RSHIFT', 'DEFAULT', '_NORETURN', 'CHAR', 'WHILE', 'DIVEQUAL', '_ALIGNOF', 'EXTERN', 'LNOT', 'CASE', 'LAND', 'REGISTER', 'MODEQUAL', 'NE', 'SWITCH', 'INT_CONST_HEX', '_COMPLEX', 'PPPRAGMASTR', 'PLUSEQUAL', 'U32CHAR_CONST', 'CONDOP', 'U8STRING_LITERAL', 'BREAK', 'VOLATILE', 'PPPRAGMA', 'INLINE', 'INT_CONST_BIN', 'DO', 'U8CHAR_CONST', 'CONST', 'U16STRING_LITERAL', 'LOR', 'CHAR_CONST', 'LSHIFT', 'RBRACE', '_BOOL', 'LE', 'SEMI', '_THREAD_LOCAL', 'LT', 'COMMA', 'U16CHAR_CONST', 'OFFSETOF', '_ATOMIC', 'TYPEDEF', 'XOR', 'AUTO', 'TIMES', 'LPAREN', 'MINUSMINUS', 'ID', 'IF', 'STRING_LITERAL', 'FLOAT', 'XOREQUAL', 'LSHIFTEQUAL', 'RBRACKET')) +_lexreflags = 64 +_lexliterals = '' +_lexstateinfo = {'ppline': 'exclusive', 'pppragma': 'exclusive', 'INITIAL': 'inclusive'} +_lexstatere = {'ppline': [('(?P<t_ppline_FILENAME>"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_ppline_LINE_NUMBER>(0(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|([1-9][0-9]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?))|(?P<t_ppline_NEWLINE>\\n)|(?P<t_ppline_PPLINE>line)', [None, ('t_ppline_FILENAME', 'FILENAME'), None, None, ('t_ppline_LINE_NUMBER', 'LINE_NUMBER'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_ppline_NEWLINE', 'NEWLINE'), ('t_ppline_PPLINE', 'PPLINE')])], 'pppragma': [('(?P<t_pppragma_NEWLINE>\\n)|(?P<t_pppragma_PPPRAGMA>pragma)|(?P<t_pppragma_STR>.+)', [None, ('t_pppragma_NEWLINE', 'NEWLINE'), ('t_pppragma_PPPRAGMA', 'PPPRAGMA'), ('t_pppragma_STR', 'STR')])], 'INITIAL': [('(?P<t_PPHASH>[ \\t]*\\#)|(?P<t_NEWLINE>\\n+)|(?P<t_LBRACE>\\{)|(?P<t_RBRACE>\\})|(?P<t_FLOAT_CONST>((((([0-9]*\\.[0-9]+)|([0-9]+\\.))([eE][-+]?[0-9]+)?)|([0-9]+([eE][-+]?[0-9]+)))[FfLl]?))|(?P<t_HEX_FLOAT_CONST>(0[xX]([0-9a-fA-F]+|((([0-9a-fA-F]+)?\\.[0-9a-fA-F]+)|([0-9a-fA-F]+\\.)))([pP][+-]?[0-9]+)[FfLl]?))|(?P<t_INT_CONST_HEX>0[xX][0-9a-fA-F]+(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|(?P<t_INT_CONST_BIN>0[bB][01]+(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)', [None, ('t_PPHASH', 'PPHASH'), ('t_NEWLINE', 'NEWLINE'), ('t_LBRACE', 'LBRACE'), ('t_RBRACE', 'RBRACE'), ('t_FLOAT_CONST', 'FLOAT_CONST'), None, None, None, None, None, None, None, None, None, ('t_HEX_FLOAT_CONST', 'HEX_FLOAT_CONST'), None, None, None, None, None, None, None, ('t_INT_CONST_HEX', 'INT_CONST_HEX'), None, None, None, None, None, None, None, ('t_INT_CONST_BIN', 'INT_CONST_BIN')]), ('(?P<t_BAD_CONST_OCT>0[0-7]*[89])|(?P<t_INT_CONST_OCT>0[0-7]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|(?P<t_INT_CONST_DEC>(0(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|([1-9][0-9]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?))|(?P<t_INT_CONST_CHAR>\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F])))){2,4}\')|(?P<t_CHAR_CONST>\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?P<t_WCHAR_CONST>L\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?P<t_U8CHAR_CONST>u8\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?P<t_U16CHAR_CONST>u\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?P<t_U32CHAR_CONST>U\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')', [None, ('t_BAD_CONST_OCT', 'BAD_CONST_OCT'), ('t_INT_CONST_OCT', 'INT_CONST_OCT'), None, None, None, None, None, None, None, ('t_INT_CONST_DEC', 'INT_CONST_DEC'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_INT_CONST_CHAR', 'INT_CONST_CHAR'), None, None, None, None, None, None, ('t_CHAR_CONST', 'CHAR_CONST'), None, None, None, None, None, None, ('t_WCHAR_CONST', 'WCHAR_CONST'), None, None, None, None, None, None, ('t_U8CHAR_CONST', 'U8CHAR_CONST'), None, None, None, None, None, None, ('t_U16CHAR_CONST', 'U16CHAR_CONST'), None, None, None, None, None, None, ('t_U32CHAR_CONST', 'U32CHAR_CONST')]), ('(?P<t_UNMATCHED_QUOTE>(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))*\\n)|(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))*$))|(?P<t_BAD_CHAR_CONST>(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))[^\'\n]+\')|(\'\')|(\'([\\\\][^a-zA-Z._~^!=&\\^\\-\\\\?\'"x0-9])[^\'\\n]*\'))|(?P<t_WSTRING_LITERAL>L"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_U8STRING_LITERAL>u8"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_U16STRING_LITERAL>u"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_U32STRING_LITERAL>U"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_BAD_STRING_LITERAL>"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*([\\\\][^a-zA-Z._~^!=&\\^\\-\\\\?\'"x0-9])([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_ID>[a-zA-Z_$][0-9a-zA-Z_$]*)|(?P<t_STRING_LITERAL>"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P<t_ELLIPSIS>\\.\\.\\.)|(?P<t_PLUSPLUS>\\+\\+)|(?P<t_LOR>\\|\\|)|(?P<t_XOREQUAL>\\^=)|(?P<t_OREQUAL>\\|=)|(?P<t_LSHIFTEQUAL><<=)|(?P<t_RSHIFTEQUAL>>>=)|(?P<t_PLUSEQUAL>\\+=)|(?P<t_TIMESEQUAL>\\*=)', [None, ('t_UNMATCHED_QUOTE', 'UNMATCHED_QUOTE'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_BAD_CHAR_CONST', 'BAD_CHAR_CONST'), None, None, None, None, None, None, None, None, None, None, ('t_WSTRING_LITERAL', 'WSTRING_LITERAL'), None, None, ('t_U8STRING_LITERAL', 'U8STRING_LITERAL'), None, None, ('t_U16STRING_LITERAL', 'U16STRING_LITERAL'), None, None, ('t_U32STRING_LITERAL', 'U32STRING_LITERAL'), None, None, ('t_BAD_STRING_LITERAL', 'BAD_STRING_LITERAL'), None, None, None, None, None, ('t_ID', 'ID'), (None, 'STRING_LITERAL'), None, None, (None, 'ELLIPSIS'), (None, 'PLUSPLUS'), (None, 'LOR'), (None, 'XOREQUAL'), (None, 'OREQUAL'), (None, 'LSHIFTEQUAL'), (None, 'RSHIFTEQUAL'), (None, 'PLUSEQUAL'), (None, 'TIMESEQUAL')]), ('(?P<t_PLUS>\\+)|(?P<t_MODEQUAL>%=)|(?P<t_DIVEQUAL>/=)|(?P<t_RBRACKET>\\])|(?P<t_CONDOP>\\?)|(?P<t_XOR>\\^)|(?P<t_LSHIFT><<)|(?P<t_LE><=)|(?P<t_LPAREN>\\()|(?P<t_ARROW>->)|(?P<t_EQ>==)|(?P<t_NE>!=)|(?P<t_MINUSMINUS>--)|(?P<t_OR>\\|)|(?P<t_TIMES>\\*)|(?P<t_LBRACKET>\\[)|(?P<t_GE>>=)|(?P<t_RPAREN>\\))|(?P<t_LAND>&&)|(?P<t_RSHIFT>>>)|(?P<t_MINUSEQUAL>-=)|(?P<t_PERIOD>\\.)|(?P<t_ANDEQUAL>&=)|(?P<t_EQUALS>=)|(?P<t_LT><)|(?P<t_COMMA>,)|(?P<t_DIVIDE>/)|(?P<t_AND>&)|(?P<t_MOD>%)|(?P<t_SEMI>;)|(?P<t_MINUS>-)|(?P<t_GT>>)|(?P<t_COLON>:)|(?P<t_NOT>~)|(?P<t_LNOT>!)', [None, (None, 'PLUS'), (None, 'MODEQUAL'), (None, 'DIVEQUAL'), (None, 'RBRACKET'), (None, 'CONDOP'), (None, 'XOR'), (None, 'LSHIFT'), (None, 'LE'), (None, 'LPAREN'), (None, 'ARROW'), (None, 'EQ'), (None, 'NE'), (None, 'MINUSMINUS'), (None, 'OR'), (None, 'TIMES'), (None, 'LBRACKET'), (None, 'GE'), (None, 'RPAREN'), (None, 'LAND'), (None, 'RSHIFT'), (None, 'MINUSEQUAL'), (None, 'PERIOD'), (None, 'ANDEQUAL'), (None, 'EQUALS'), (None, 'LT'), (None, 'COMMA'), (None, 'DIVIDE'), (None, 'AND'), (None, 'MOD'), (None, 'SEMI'), (None, 'MINUS'), (None, 'GT'), (None, 'COLON'), (None, 'NOT'), (None, 'LNOT')])]} +_lexstateignore = {'ppline': ' \t', 'pppragma': ' \t', 'INITIAL': ' \t'} +_lexstateerrorf = {'ppline': 't_ppline_error', 'pppragma': 't_pppragma_error', 'INITIAL': 't_error'} +_lexstateeoff = {} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6e53cddcf6740cfb5317ce75efd7930c19e66f17 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__init__.py @@ -0,0 +1,5 @@ +# PLY package +# Author: David Beazley (dave@dabeaz.com) + +__version__ = '3.9' +__all__ = ['lex','yacc'] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e712469a88f4ed0e9ec2f0cdc57bd830faf4f4b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9b72d31d83170bb92260e59bcf781fdbe721fb6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6ed50e3b6b5068fdb59afb09d8905002d945580 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcd4f6ff2478a3ec1f1e0414793622093a7919af Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd1524e4582478f3b393c3ee7bc2525185a345bc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31c2ef2055277644035cb46e4974636ffa3e3705 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/cpp.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/cpp.py new file mode 100644 index 0000000000000000000000000000000000000000..86273eac77a5b404cb41cf4d2650d8a37415fb67 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/cpp.py @@ -0,0 +1,905 @@ +# ----------------------------------------------------------------------------- +# cpp.py +# +# Author: David Beazley (http://www.dabeaz.com) +# Copyright (C) 2017 +# All rights reserved +# +# This module implements an ANSI-C style lexical preprocessor for PLY. +# ----------------------------------------------------------------------------- +import sys + +# Some Python 3 compatibility shims +if sys.version_info.major < 3: + STRING_TYPES = (str, unicode) +else: + STRING_TYPES = str + xrange = range + +# ----------------------------------------------------------------------------- +# Default preprocessor lexer definitions. These tokens are enough to get +# a basic preprocessor working. Other modules may import these if they want +# ----------------------------------------------------------------------------- + +tokens = ( + 'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT1', 'CPP_COMMENT2', 'CPP_POUND','CPP_DPOUND' +) + +literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\"" + +# Whitespace +def t_CPP_WS(t): + r'\s+' + t.lexer.lineno += t.value.count("\n") + return t + +t_CPP_POUND = r'\#' +t_CPP_DPOUND = r'\#\#' + +# Identifier +t_CPP_ID = r'[A-Za-z_][\w_]*' + +# Integer literal +def CPP_INTEGER(t): + r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU][lL]|[lL][uU]|[uU]|[lL])?)' + return t + +t_CPP_INTEGER = CPP_INTEGER + +# Floating literal +t_CPP_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +def t_CPP_STRING(t): + r'\"([^\\\n]|(\\(.|\n)))*?\"' + t.lexer.lineno += t.value.count("\n") + return t + +# Character constant 'c' or L'c' +def t_CPP_CHAR(t): + r'(L)?\'([^\\\n]|(\\(.|\n)))*?\'' + t.lexer.lineno += t.value.count("\n") + return t + +# Comment +def t_CPP_COMMENT1(t): + r'(/\*(.|\n)*?\*/)' + ncr = t.value.count("\n") + t.lexer.lineno += ncr + # replace with one space or a number of '\n' + t.type = 'CPP_WS'; t.value = '\n' * ncr if ncr else ' ' + return t + +# Line comment +def t_CPP_COMMENT2(t): + r'(//.*?(\n|$))' + # replace with '/n' + t.type = 'CPP_WS'; t.value = '\n' + return t + +def t_error(t): + t.type = t.value[0] + t.value = t.value[0] + t.lexer.skip(1) + return t + +import re +import copy +import time +import os.path + +# ----------------------------------------------------------------------------- +# trigraph() +# +# Given an input string, this function replaces all trigraph sequences. +# The following mapping is used: +# +# ??= # +# ??/ \ +# ??' ^ +# ??( [ +# ??) ] +# ??! | +# ??< { +# ??> } +# ??- ~ +# ----------------------------------------------------------------------------- + +_trigraph_pat = re.compile(r'''\?\?[=/\'\(\)\!<>\-]''') +_trigraph_rep = { + '=':'#', + '/':'\\', + "'":'^', + '(':'[', + ')':']', + '!':'|', + '<':'{', + '>':'}', + '-':'~' +} + +def trigraph(input): + return _trigraph_pat.sub(lambda g: _trigraph_rep[g.group()[-1]],input) + +# ------------------------------------------------------------------ +# Macro object +# +# This object holds information about preprocessor macros +# +# .name - Macro name (string) +# .value - Macro value (a list of tokens) +# .arglist - List of argument names +# .variadic - Boolean indicating whether or not variadic macro +# .vararg - Name of the variadic parameter +# +# When a macro is created, the macro replacement token sequence is +# pre-scanned and used to create patch lists that are later used +# during macro expansion +# ------------------------------------------------------------------ + +class Macro(object): + def __init__(self,name,value,arglist=None,variadic=False): + self.name = name + self.value = value + self.arglist = arglist + self.variadic = variadic + if variadic: + self.vararg = arglist[-1] + self.source = None + +# ------------------------------------------------------------------ +# Preprocessor object +# +# Object representing a preprocessor. Contains macro definitions, +# include directories, and other information +# ------------------------------------------------------------------ + +class Preprocessor(object): + def __init__(self,lexer=None): + if lexer is None: + lexer = lex.lexer + self.lexer = lexer + self.macros = { } + self.path = [] + self.temp_path = [] + + # Probe the lexer for selected tokens + self.lexprobe() + + tm = time.localtime() + self.define("__DATE__ \"%s\"" % time.strftime("%b %d %Y",tm)) + self.define("__TIME__ \"%s\"" % time.strftime("%H:%M:%S",tm)) + self.parser = None + + # ----------------------------------------------------------------------------- + # tokenize() + # + # Utility function. Given a string of text, tokenize into a list of tokens + # ----------------------------------------------------------------------------- + + def tokenize(self,text): + tokens = [] + self.lexer.input(text) + while True: + tok = self.lexer.token() + if not tok: break + tokens.append(tok) + return tokens + + # --------------------------------------------------------------------- + # error() + # + # Report a preprocessor error/warning of some kind + # ---------------------------------------------------------------------- + + def error(self,file,line,msg): + print("%s:%d %s" % (file,line,msg)) + + # ---------------------------------------------------------------------- + # lexprobe() + # + # This method probes the preprocessor lexer object to discover + # the token types of symbols that are important to the preprocessor. + # If this works right, the preprocessor will simply "work" + # with any suitable lexer regardless of how tokens have been named. + # ---------------------------------------------------------------------- + + def lexprobe(self): + + # Determine the token type for identifiers + self.lexer.input("identifier") + tok = self.lexer.token() + if not tok or tok.value != "identifier": + print("Couldn't determine identifier type") + else: + self.t_ID = tok.type + + # Determine the token type for integers + self.lexer.input("12345") + tok = self.lexer.token() + if not tok or int(tok.value) != 12345: + print("Couldn't determine integer type") + else: + self.t_INTEGER = tok.type + self.t_INTEGER_TYPE = type(tok.value) + + # Determine the token type for strings enclosed in double quotes + self.lexer.input("\"filename\"") + tok = self.lexer.token() + if not tok or tok.value != "\"filename\"": + print("Couldn't determine string type") + else: + self.t_STRING = tok.type + + # Determine the token type for whitespace--if any + self.lexer.input(" ") + tok = self.lexer.token() + if not tok or tok.value != " ": + self.t_SPACE = None + else: + self.t_SPACE = tok.type + + # Determine the token type for newlines + self.lexer.input("\n") + tok = self.lexer.token() + if not tok or tok.value != "\n": + self.t_NEWLINE = None + print("Couldn't determine token for newlines") + else: + self.t_NEWLINE = tok.type + + self.t_WS = (self.t_SPACE, self.t_NEWLINE) + + # Check for other characters used by the preprocessor + chars = [ '<','>','#','##','\\','(',')',',','.'] + for c in chars: + self.lexer.input(c) + tok = self.lexer.token() + if not tok or tok.value != c: + print("Unable to lex '%s' required for preprocessor" % c) + + # ---------------------------------------------------------------------- + # add_path() + # + # Adds a search path to the preprocessor. + # ---------------------------------------------------------------------- + + def add_path(self,path): + self.path.append(path) + + # ---------------------------------------------------------------------- + # group_lines() + # + # Given an input string, this function splits it into lines. Trailing whitespace + # is removed. Any line ending with \ is grouped with the next line. This + # function forms the lowest level of the preprocessor---grouping into text into + # a line-by-line format. + # ---------------------------------------------------------------------- + + def group_lines(self,input): + lex = self.lexer.clone() + lines = [x.rstrip() for x in input.splitlines()] + for i in xrange(len(lines)): + j = i+1 + while lines[i].endswith('\\') and (j < len(lines)): + lines[i] = lines[i][:-1]+lines[j] + lines[j] = "" + j += 1 + + input = "\n".join(lines) + lex.input(input) + lex.lineno = 1 + + current_line = [] + while True: + tok = lex.token() + if not tok: + break + current_line.append(tok) + if tok.type in self.t_WS and '\n' in tok.value: + yield current_line + current_line = [] + + if current_line: + yield current_line + + # ---------------------------------------------------------------------- + # tokenstrip() + # + # Remove leading/trailing whitespace tokens from a token list + # ---------------------------------------------------------------------- + + def tokenstrip(self,tokens): + i = 0 + while i < len(tokens) and tokens[i].type in self.t_WS: + i += 1 + del tokens[:i] + i = len(tokens)-1 + while i >= 0 and tokens[i].type in self.t_WS: + i -= 1 + del tokens[i+1:] + return tokens + + + # ---------------------------------------------------------------------- + # collect_args() + # + # Collects comma separated arguments from a list of tokens. The arguments + # must be enclosed in parenthesis. Returns a tuple (tokencount,args,positions) + # where tokencount is the number of tokens consumed, args is a list of arguments, + # and positions is a list of integers containing the starting index of each + # argument. Each argument is represented by a list of tokens. + # + # When collecting arguments, leading and trailing whitespace is removed + # from each argument. + # + # This function properly handles nested parenthesis and commas---these do not + # define new arguments. + # ---------------------------------------------------------------------- + + def collect_args(self,tokenlist): + args = [] + positions = [] + current_arg = [] + nesting = 1 + tokenlen = len(tokenlist) + + # Search for the opening '('. + i = 0 + while (i < tokenlen) and (tokenlist[i].type in self.t_WS): + i += 1 + + if (i < tokenlen) and (tokenlist[i].value == '('): + positions.append(i+1) + else: + self.error(self.source,tokenlist[0].lineno,"Missing '(' in macro arguments") + return 0, [], [] + + i += 1 + + while i < tokenlen: + t = tokenlist[i] + if t.value == '(': + current_arg.append(t) + nesting += 1 + elif t.value == ')': + nesting -= 1 + if nesting == 0: + if current_arg: + args.append(self.tokenstrip(current_arg)) + positions.append(i) + return i+1,args,positions + current_arg.append(t) + elif t.value == ',' and nesting == 1: + args.append(self.tokenstrip(current_arg)) + positions.append(i+1) + current_arg = [] + else: + current_arg.append(t) + i += 1 + + # Missing end argument + self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments") + return 0, [],[] + + # ---------------------------------------------------------------------- + # macro_prescan() + # + # Examine the macro value (token sequence) and identify patch points + # This is used to speed up macro expansion later on---we'll know + # right away where to apply patches to the value to form the expansion + # ---------------------------------------------------------------------- + + def macro_prescan(self,macro): + macro.patch = [] # Standard macro arguments + macro.str_patch = [] # String conversion expansion + macro.var_comma_patch = [] # Variadic macro comma patch + i = 0 + while i < len(macro.value): + if macro.value[i].type == self.t_ID and macro.value[i].value in macro.arglist: + argnum = macro.arglist.index(macro.value[i].value) + # Conversion of argument to a string + if i > 0 and macro.value[i-1].value == '#': + macro.value[i] = copy.copy(macro.value[i]) + macro.value[i].type = self.t_STRING + del macro.value[i-1] + macro.str_patch.append((argnum,i-1)) + continue + # Concatenation + elif (i > 0 and macro.value[i-1].value == '##'): + macro.patch.append(('c',argnum,i-1)) + del macro.value[i-1] + continue + elif ((i+1) < len(macro.value) and macro.value[i+1].value == '##'): + macro.patch.append(('c',argnum,i)) + i += 1 + continue + # Standard expansion + else: + macro.patch.append(('e',argnum,i)) + elif macro.value[i].value == '##': + if macro.variadic and (i > 0) and (macro.value[i-1].value == ',') and \ + ((i+1) < len(macro.value)) and (macro.value[i+1].type == self.t_ID) and \ + (macro.value[i+1].value == macro.vararg): + macro.var_comma_patch.append(i-1) + i += 1 + macro.patch.sort(key=lambda x: x[2],reverse=True) + + # ---------------------------------------------------------------------- + # macro_expand_args() + # + # Given a Macro and list of arguments (each a token list), this method + # returns an expanded version of a macro. The return value is a token sequence + # representing the replacement macro tokens + # ---------------------------------------------------------------------- + + def macro_expand_args(self,macro,args): + # Make a copy of the macro token sequence + rep = [copy.copy(_x) for _x in macro.value] + + # Make string expansion patches. These do not alter the length of the replacement sequence + + str_expansion = {} + for argnum, i in macro.str_patch: + if argnum not in str_expansion: + str_expansion[argnum] = ('"%s"' % "".join([x.value for x in args[argnum]])).replace("\\","\\\\") + rep[i] = copy.copy(rep[i]) + rep[i].value = str_expansion[argnum] + + # Make the variadic macro comma patch. If the variadic macro argument is empty, we get rid + comma_patch = False + if macro.variadic and not args[-1]: + for i in macro.var_comma_patch: + rep[i] = None + comma_patch = True + + # Make all other patches. The order of these matters. It is assumed that the patch list + # has been sorted in reverse order of patch location since replacements will cause the + # size of the replacement sequence to expand from the patch point. + + expanded = { } + for ptype, argnum, i in macro.patch: + # Concatenation. Argument is left unexpanded + if ptype == 'c': + rep[i:i+1] = args[argnum] + # Normal expansion. Argument is macro expanded first + elif ptype == 'e': + if argnum not in expanded: + expanded[argnum] = self.expand_macros(args[argnum]) + rep[i:i+1] = expanded[argnum] + + # Get rid of removed comma if necessary + if comma_patch: + rep = [_i for _i in rep if _i] + + return rep + + + # ---------------------------------------------------------------------- + # expand_macros() + # + # Given a list of tokens, this function performs macro expansion. + # The expanded argument is a dictionary that contains macros already + # expanded. This is used to prevent infinite recursion. + # ---------------------------------------------------------------------- + + def expand_macros(self,tokens,expanded=None): + if expanded is None: + expanded = {} + i = 0 + while i < len(tokens): + t = tokens[i] + if t.type == self.t_ID: + if t.value in self.macros and t.value not in expanded: + # Yes, we found a macro match + expanded[t.value] = True + + m = self.macros[t.value] + if not m.arglist: + # A simple macro + ex = self.expand_macros([copy.copy(_x) for _x in m.value],expanded) + for e in ex: + e.lineno = t.lineno + tokens[i:i+1] = ex + i += len(ex) + else: + # A macro with arguments + j = i + 1 + while j < len(tokens) and tokens[j].type in self.t_WS: + j += 1 + if tokens[j].value == '(': + tokcount,args,positions = self.collect_args(tokens[j:]) + if not m.variadic and len(args) != len(m.arglist): + self.error(self.source,t.lineno,"Macro %s requires %d arguments" % (t.value,len(m.arglist))) + i = j + tokcount + elif m.variadic and len(args) < len(m.arglist)-1: + if len(m.arglist) > 2: + self.error(self.source,t.lineno,"Macro %s must have at least %d arguments" % (t.value, len(m.arglist)-1)) + else: + self.error(self.source,t.lineno,"Macro %s must have at least %d argument" % (t.value, len(m.arglist)-1)) + i = j + tokcount + else: + if m.variadic: + if len(args) == len(m.arglist)-1: + args.append([]) + else: + args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1] + del args[len(m.arglist):] + + # Get macro replacement text + rep = self.macro_expand_args(m,args) + rep = self.expand_macros(rep,expanded) + for r in rep: + r.lineno = t.lineno + tokens[i:j+tokcount] = rep + i += len(rep) + del expanded[t.value] + continue + elif t.value == '__LINE__': + t.type = self.t_INTEGER + t.value = self.t_INTEGER_TYPE(t.lineno) + + i += 1 + return tokens + + # ---------------------------------------------------------------------- + # evalexpr() + # + # Evaluate an expression token sequence for the purposes of evaluating + # integral expressions. + # ---------------------------------------------------------------------- + + def evalexpr(self,tokens): + # tokens = tokenize(line) + # Search for defined macros + i = 0 + while i < len(tokens): + if tokens[i].type == self.t_ID and tokens[i].value == 'defined': + j = i + 1 + needparen = False + result = "0L" + while j < len(tokens): + if tokens[j].type in self.t_WS: + j += 1 + continue + elif tokens[j].type == self.t_ID: + if tokens[j].value in self.macros: + result = "1L" + else: + result = "0L" + if not needparen: break + elif tokens[j].value == '(': + needparen = True + elif tokens[j].value == ')': + break + else: + self.error(self.source,tokens[i].lineno,"Malformed defined()") + j += 1 + tokens[i].type = self.t_INTEGER + tokens[i].value = self.t_INTEGER_TYPE(result) + del tokens[i+1:j+1] + i += 1 + tokens = self.expand_macros(tokens) + for i,t in enumerate(tokens): + if t.type == self.t_ID: + tokens[i] = copy.copy(t) + tokens[i].type = self.t_INTEGER + tokens[i].value = self.t_INTEGER_TYPE("0L") + elif t.type == self.t_INTEGER: + tokens[i] = copy.copy(t) + # Strip off any trailing suffixes + tokens[i].value = str(tokens[i].value) + while tokens[i].value[-1] not in "0123456789abcdefABCDEF": + tokens[i].value = tokens[i].value[:-1] + + expr = "".join([str(x.value) for x in tokens]) + expr = expr.replace("&&"," and ") + expr = expr.replace("||"," or ") + expr = expr.replace("!"," not ") + try: + result = eval(expr) + except Exception: + self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression") + result = 0 + return result + + # ---------------------------------------------------------------------- + # parsegen() + # + # Parse an input string/ + # ---------------------------------------------------------------------- + def parsegen(self,input,source=None): + + # Replace trigraph sequences + t = trigraph(input) + lines = self.group_lines(t) + + if not source: + source = "" + + self.define("__FILE__ \"%s\"" % source) + + self.source = source + chunk = [] + enable = True + iftrigger = False + ifstack = [] + + for x in lines: + for i,tok in enumerate(x): + if tok.type not in self.t_WS: break + if tok.value == '#': + # Preprocessor directive + + # insert necessary whitespace instead of eaten tokens + for tok in x: + if tok.type in self.t_WS and '\n' in tok.value: + chunk.append(tok) + + dirtokens = self.tokenstrip(x[i+1:]) + if dirtokens: + name = dirtokens[0].value + args = self.tokenstrip(dirtokens[1:]) + else: + name = "" + args = [] + + if name == 'define': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + self.define(args) + elif name == 'include': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + oldfile = self.macros['__FILE__'] + for tok in self.include(args): + yield tok + self.macros['__FILE__'] = oldfile + self.source = source + elif name == 'undef': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + self.undef(args) + elif name == 'ifdef': + ifstack.append((enable,iftrigger)) + if enable: + if not args[0].value in self.macros: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'ifndef': + ifstack.append((enable,iftrigger)) + if enable: + if args[0].value in self.macros: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'if': + ifstack.append((enable,iftrigger)) + if enable: + result = self.evalexpr(args) + if not result: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'elif': + if ifstack: + if ifstack[-1][0]: # We only pay attention if outer "if" allows this + if enable: # If already true, we flip enable False + enable = False + elif not iftrigger: # If False, but not triggered yet, we'll check expression + result = self.evalexpr(args) + if result: + enable = True + iftrigger = True + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #elif") + + elif name == 'else': + if ifstack: + if ifstack[-1][0]: + if enable: + enable = False + elif not iftrigger: + enable = True + iftrigger = True + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #else") + + elif name == 'endif': + if ifstack: + enable,iftrigger = ifstack.pop() + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #endif") + else: + # Unknown preprocessor directive + pass + + else: + # Normal text + if enable: + chunk.extend(x) + + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + + # ---------------------------------------------------------------------- + # include() + # + # Implementation of file-inclusion + # ---------------------------------------------------------------------- + + def include(self,tokens): + # Try to extract the filename and then process an include file + if not tokens: + return + if tokens: + if tokens[0].value != '<' and tokens[0].type != self.t_STRING: + tokens = self.expand_macros(tokens) + + if tokens[0].value == '<': + # Include <...> + i = 1 + while i < len(tokens): + if tokens[i].value == '>': + break + i += 1 + else: + print("Malformed #include <...>") + return + filename = "".join([x.value for x in tokens[1:i]]) + path = self.path + [""] + self.temp_path + elif tokens[0].type == self.t_STRING: + filename = tokens[0].value[1:-1] + path = self.temp_path + [""] + self.path + else: + print("Malformed #include statement") + return + for p in path: + iname = os.path.join(p,filename) + try: + data = open(iname,"r").read() + dname = os.path.dirname(iname) + if dname: + self.temp_path.insert(0,dname) + for tok in self.parsegen(data,filename): + yield tok + if dname: + del self.temp_path[0] + break + except IOError: + pass + else: + print("Couldn't find '%s'" % filename) + + # ---------------------------------------------------------------------- + # define() + # + # Define a new macro + # ---------------------------------------------------------------------- + + def define(self,tokens): + if isinstance(tokens,STRING_TYPES): + tokens = self.tokenize(tokens) + + linetok = tokens + try: + name = linetok[0] + if len(linetok) > 1: + mtype = linetok[1] + else: + mtype = None + if not mtype: + m = Macro(name.value,[]) + self.macros[name.value] = m + elif mtype.type in self.t_WS: + # A normal macro + m = Macro(name.value,self.tokenstrip(linetok[2:])) + self.macros[name.value] = m + elif mtype.value == '(': + # A macro with arguments + tokcount, args, positions = self.collect_args(linetok[1:]) + variadic = False + for a in args: + if variadic: + print("No more arguments may follow a variadic argument") + break + astr = "".join([str(_i.value) for _i in a]) + if astr == "...": + variadic = True + a[0].type = self.t_ID + a[0].value = '__VA_ARGS__' + variadic = True + del a[1:] + continue + elif astr[-3:] == "..." and a[0].type == self.t_ID: + variadic = True + del a[1:] + # If, for some reason, "." is part of the identifier, strip off the name for the purposes + # of macro expansion + if a[0].value[-3:] == '...': + a[0].value = a[0].value[:-3] + continue + if len(a) > 1 or a[0].type != self.t_ID: + print("Invalid macro argument") + break + else: + mvalue = self.tokenstrip(linetok[1+tokcount:]) + i = 0 + while i < len(mvalue): + if i+1 < len(mvalue): + if mvalue[i].type in self.t_WS and mvalue[i+1].value == '##': + del mvalue[i] + continue + elif mvalue[i].value == '##' and mvalue[i+1].type in self.t_WS: + del mvalue[i+1] + i += 1 + m = Macro(name.value,mvalue,[x[0].value for x in args],variadic) + self.macro_prescan(m) + self.macros[name.value] = m + else: + print("Bad macro definition") + except LookupError: + print("Bad macro definition") + + # ---------------------------------------------------------------------- + # undef() + # + # Undefine a macro + # ---------------------------------------------------------------------- + + def undef(self,tokens): + id = tokens[0].value + try: + del self.macros[id] + except LookupError: + pass + + # ---------------------------------------------------------------------- + # parse() + # + # Parse input text. + # ---------------------------------------------------------------------- + def parse(self,input,source=None,ignore={}): + self.ignore = ignore + self.parser = self.parsegen(input,source) + + # ---------------------------------------------------------------------- + # token() + # + # Method to return individual tokens + # ---------------------------------------------------------------------- + def token(self): + try: + while True: + tok = next(self.parser) + if tok.type not in self.ignore: return tok + except StopIteration: + self.parser = None + return None + +if __name__ == '__main__': + import ply.lex as lex + lexer = lex.lex() + + # Run a preprocessor + import sys + f = open(sys.argv[1]) + input = f.read() + + p = Preprocessor(lexer) + p.parse(input,sys.argv[1]) + while True: + tok = p.token() + if not tok: break + print(p.source, tok) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ctokens.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ctokens.py new file mode 100644 index 0000000000000000000000000000000000000000..f6f6952d605ee5fa0a25eff03f18769b6b445fae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ctokens.py @@ -0,0 +1,133 @@ +# ---------------------------------------------------------------------- +# ctokens.py +# +# Token specifications for symbols in ANSI C and C++. This file is +# meant to be used as a library in other tokenizers. +# ---------------------------------------------------------------------- + +# Reserved words + +tokens = [ + # Literals (identifier, integer constant, float constant, string constant, char const) + 'ID', 'TYPEID', 'INTEGER', 'FLOAT', 'STRING', 'CHARACTER', + + # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=) + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MODULO', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=) + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL', + + # Increment/decrement (++,--) + 'INCREMENT', 'DECREMENT', + + # Structure dereference (->) + 'ARROW', + + # Ternary operator (?) + 'TERNARY', + + # Delimeters ( ) [ ] { } , . ; : + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'COMMA', 'PERIOD', 'SEMI', 'COLON', + + # Ellipsis (...) + 'ELLIPSIS', +] + +# Operators +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_MODULO = r'%' +t_OR = r'\|' +t_AND = r'&' +t_NOT = r'~' +t_XOR = r'\^' +t_LSHIFT = r'<<' +t_RSHIFT = r'>>' +t_LOR = r'\|\|' +t_LAND = r'&&' +t_LNOT = r'!' +t_LT = r'<' +t_GT = r'>' +t_LE = r'<=' +t_GE = r'>=' +t_EQ = r'==' +t_NE = r'!=' + +# Assignment operators + +t_EQUALS = r'=' +t_TIMESEQUAL = r'\*=' +t_DIVEQUAL = r'/=' +t_MODEQUAL = r'%=' +t_PLUSEQUAL = r'\+=' +t_MINUSEQUAL = r'-=' +t_LSHIFTEQUAL = r'<<=' +t_RSHIFTEQUAL = r'>>=' +t_ANDEQUAL = r'&=' +t_OREQUAL = r'\|=' +t_XOREQUAL = r'\^=' + +# Increment/decrement +t_INCREMENT = r'\+\+' +t_DECREMENT = r'--' + +# -> +t_ARROW = r'->' + +# ? +t_TERNARY = r'\?' + +# Delimeters +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_COMMA = r',' +t_PERIOD = r'\.' +t_SEMI = r';' +t_COLON = r':' +t_ELLIPSIS = r'\.\.\.' + +# Identifiers +t_ID = r'[A-Za-z_][A-Za-z0-9_]*' + +# Integer literal +t_INTEGER = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?' + +# Floating literal +t_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +t_STRING = r'\"([^\\\n]|(\\.))*?\"' + +# Character constant 'c' or L'c' +t_CHARACTER = r'(L)?\'([^\\\n]|(\\.))*?\'' + +# Comment (C-Style) +def t_COMMENT(t): + r'/\*(.|\n)*?\*/' + t.lexer.lineno += t.value.count('\n') + return t + +# Comment (C++-Style) +def t_CPPCOMMENT(t): + r'//.*\n' + t.lexer.lineno += 1 + return t + + + + + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/lex.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/lex.py new file mode 100644 index 0000000000000000000000000000000000000000..4bdd76ca06d1aee995142be8a3183894776df6fa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/lex.py @@ -0,0 +1,1099 @@ +# ----------------------------------------------------------------------------- +# ply: lex.py +# +# Copyright (C) 2001-2017 +# David M. Beazley (Dabeaz LLC) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- + +__version__ = '3.10' +__tabversion__ = '3.10' + +import re +import sys +import types +import copy +import os +import inspect + +# This tuple contains known string types +try: + # Python 2.6 + StringTypes = (types.StringType, types.UnicodeType) +except AttributeError: + # Python 3.0 + StringTypes = (str, bytes) + +# This regular expression is used to match valid token names +_is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') + +# Exception thrown when invalid token encountered and no default error +# handler is defined. +class LexError(Exception): + def __init__(self, message, s): + self.args = (message,) + self.text = s + + +# Token class. This class is used to represent the tokens produced. +class LexToken(object): + def __str__(self): + return 'LexToken(%s,%r,%d,%d)' % (self.type, self.value, self.lineno, self.lexpos) + + def __repr__(self): + return str(self) + + +# This object is a stand-in for a logging object created by the +# logging module. + +class PlyLogger(object): + def __init__(self, f): + self.f = f + + def critical(self, msg, *args, **kwargs): + self.f.write((msg % args) + '\n') + + def warning(self, msg, *args, **kwargs): + self.f.write('WARNING: ' + (msg % args) + '\n') + + def error(self, msg, *args, **kwargs): + self.f.write('ERROR: ' + (msg % args) + '\n') + + info = critical + debug = critical + + +# Null logger is used when no output is generated. Does nothing. +class NullLogger(object): + def __getattribute__(self, name): + return self + + def __call__(self, *args, **kwargs): + return self + + +# ----------------------------------------------------------------------------- +# === Lexing Engine === +# +# The following Lexer class implements the lexer runtime. There are only +# a few public methods and attributes: +# +# input() - Store a new string in the lexer +# token() - Get the next token +# clone() - Clone the lexer +# +# lineno - Current line number +# lexpos - Current position in the input string +# ----------------------------------------------------------------------------- + +class Lexer: + def __init__(self): + self.lexre = None # Master regular expression. This is a list of + # tuples (re, findex) where re is a compiled + # regular expression and findex is a list + # mapping regex group numbers to rules + self.lexretext = None # Current regular expression strings + self.lexstatere = {} # Dictionary mapping lexer states to master regexs + self.lexstateretext = {} # Dictionary mapping lexer states to regex strings + self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names + self.lexstate = 'INITIAL' # Current lexer state + self.lexstatestack = [] # Stack of lexer states + self.lexstateinfo = None # State information + self.lexstateignore = {} # Dictionary of ignored characters for each state + self.lexstateerrorf = {} # Dictionary of error functions for each state + self.lexstateeoff = {} # Dictionary of eof functions for each state + self.lexreflags = 0 # Optional re compile flags + self.lexdata = None # Actual input data (as a string) + self.lexpos = 0 # Current position in input text + self.lexlen = 0 # Length of the input text + self.lexerrorf = None # Error rule (if any) + self.lexeoff = None # EOF rule (if any) + self.lextokens = None # List of valid tokens + self.lexignore = '' # Ignored characters + self.lexliterals = '' # Literal characters that can be passed through + self.lexmodule = None # Module + self.lineno = 1 # Current line number + self.lexoptimize = False # Optimized mode + + def clone(self, object=None): + c = copy.copy(self) + + # If the object parameter has been supplied, it means we are attaching the + # lexer to a new object. In this case, we have to rebind all methods in + # the lexstatere and lexstateerrorf tables. + + if object: + newtab = {} + for key, ritem in self.lexstatere.items(): + newre = [] + for cre, findex in ritem: + newfindex = [] + for f in findex: + if not f or not f[0]: + newfindex.append(f) + continue + newfindex.append((getattr(object, f[0].__name__), f[1])) + newre.append((cre, newfindex)) + newtab[key] = newre + c.lexstatere = newtab + c.lexstateerrorf = {} + for key, ef in self.lexstateerrorf.items(): + c.lexstateerrorf[key] = getattr(object, ef.__name__) + c.lexmodule = object + return c + + # ------------------------------------------------------------ + # writetab() - Write lexer information to a table file + # ------------------------------------------------------------ + def writetab(self, lextab, outputdir=''): + if isinstance(lextab, types.ModuleType): + raise IOError("Won't overwrite existing lextab module") + basetabmodule = lextab.split('.')[-1] + filename = os.path.join(outputdir, basetabmodule) + '.py' + with open(filename, 'w') as tf: + tf.write('# %s.py. This file automatically created by PLY (version %s). Don\'t edit!\n' % (basetabmodule, __version__)) + tf.write('_tabversion = %s\n' % repr(__tabversion__)) + tf.write('_lextokens = set(%s)\n' % repr(tuple(self.lextokens))) + tf.write('_lexreflags = %s\n' % repr(self.lexreflags)) + tf.write('_lexliterals = %s\n' % repr(self.lexliterals)) + tf.write('_lexstateinfo = %s\n' % repr(self.lexstateinfo)) + + # Rewrite the lexstatere table, replacing function objects with function names + tabre = {} + for statename, lre in self.lexstatere.items(): + titem = [] + for (pat, func), retext, renames in zip(lre, self.lexstateretext[statename], self.lexstaterenames[statename]): + titem.append((retext, _funcs_to_names(func, renames))) + tabre[statename] = titem + + tf.write('_lexstatere = %s\n' % repr(tabre)) + tf.write('_lexstateignore = %s\n' % repr(self.lexstateignore)) + + taberr = {} + for statename, ef in self.lexstateerrorf.items(): + taberr[statename] = ef.__name__ if ef else None + tf.write('_lexstateerrorf = %s\n' % repr(taberr)) + + tabeof = {} + for statename, ef in self.lexstateeoff.items(): + tabeof[statename] = ef.__name__ if ef else None + tf.write('_lexstateeoff = %s\n' % repr(tabeof)) + + # ------------------------------------------------------------ + # readtab() - Read lexer information from a tab file + # ------------------------------------------------------------ + def readtab(self, tabfile, fdict): + if isinstance(tabfile, types.ModuleType): + lextab = tabfile + else: + exec('import %s' % tabfile) + lextab = sys.modules[tabfile] + + if getattr(lextab, '_tabversion', '0.0') != __tabversion__: + raise ImportError('Inconsistent PLY version') + + self.lextokens = lextab._lextokens + self.lexreflags = lextab._lexreflags + self.lexliterals = lextab._lexliterals + self.lextokens_all = self.lextokens | set(self.lexliterals) + self.lexstateinfo = lextab._lexstateinfo + self.lexstateignore = lextab._lexstateignore + self.lexstatere = {} + self.lexstateretext = {} + for statename, lre in lextab._lexstatere.items(): + titem = [] + txtitem = [] + for pat, func_name in lre: + titem.append((re.compile(pat, lextab._lexreflags), _names_to_funcs(func_name, fdict))) + + self.lexstatere[statename] = titem + self.lexstateretext[statename] = txtitem + + self.lexstateerrorf = {} + for statename, ef in lextab._lexstateerrorf.items(): + self.lexstateerrorf[statename] = fdict[ef] + + self.lexstateeoff = {} + for statename, ef in lextab._lexstateeoff.items(): + self.lexstateeoff[statename] = fdict[ef] + + self.begin('INITIAL') + + # ------------------------------------------------------------ + # input() - Push a new string into the lexer + # ------------------------------------------------------------ + def input(self, s): + # Pull off the first character to see if s looks like a string + c = s[:1] + if not isinstance(c, StringTypes): + raise ValueError('Expected a string') + self.lexdata = s + self.lexpos = 0 + self.lexlen = len(s) + + # ------------------------------------------------------------ + # begin() - Changes the lexing state + # ------------------------------------------------------------ + def begin(self, state): + if state not in self.lexstatere: + raise ValueError('Undefined state') + self.lexre = self.lexstatere[state] + self.lexretext = self.lexstateretext[state] + self.lexignore = self.lexstateignore.get(state, '') + self.lexerrorf = self.lexstateerrorf.get(state, None) + self.lexeoff = self.lexstateeoff.get(state, None) + self.lexstate = state + + # ------------------------------------------------------------ + # push_state() - Changes the lexing state and saves old on stack + # ------------------------------------------------------------ + def push_state(self, state): + self.lexstatestack.append(self.lexstate) + self.begin(state) + + # ------------------------------------------------------------ + # pop_state() - Restores the previous state + # ------------------------------------------------------------ + def pop_state(self): + self.begin(self.lexstatestack.pop()) + + # ------------------------------------------------------------ + # current_state() - Returns the current lexing state + # ------------------------------------------------------------ + def current_state(self): + return self.lexstate + + # ------------------------------------------------------------ + # skip() - Skip ahead n characters + # ------------------------------------------------------------ + def skip(self, n): + self.lexpos += n + + # ------------------------------------------------------------ + # opttoken() - Return the next token from the Lexer + # + # Note: This function has been carefully implemented to be as fast + # as possible. Don't make changes unless you really know what + # you are doing + # ------------------------------------------------------------ + def token(self): + # Make local copies of frequently referenced attributes + lexpos = self.lexpos + lexlen = self.lexlen + lexignore = self.lexignore + lexdata = self.lexdata + + while lexpos < lexlen: + # This code provides some short-circuit code for whitespace, tabs, and other ignored characters + if lexdata[lexpos] in lexignore: + lexpos += 1 + continue + + # Look for a regular expression match + for lexre, lexindexfunc in self.lexre: + m = lexre.match(lexdata, lexpos) + if not m: + continue + + # Create a token for return + tok = LexToken() + tok.value = m.group() + tok.lineno = self.lineno + tok.lexpos = lexpos + + i = m.lastindex + func, tok.type = lexindexfunc[i] + + if not func: + # If no token type was set, it's an ignored token + if tok.type: + self.lexpos = m.end() + return tok + else: + lexpos = m.end() + break + + lexpos = m.end() + + # If token is processed by a function, call it + + tok.lexer = self # Set additional attributes useful in token rules + self.lexmatch = m + self.lexpos = lexpos + + newtok = func(tok) + + # Every function must return a token, if nothing, we just move to next token + if not newtok: + lexpos = self.lexpos # This is here in case user has updated lexpos. + lexignore = self.lexignore # This is here in case there was a state change + break + + # Verify type of the token. If not in the token map, raise an error + if not self.lexoptimize: + if newtok.type not in self.lextokens_all: + raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( + func.__code__.co_filename, func.__code__.co_firstlineno, + func.__name__, newtok.type), lexdata[lexpos:]) + + return newtok + else: + # No match, see if in literals + if lexdata[lexpos] in self.lexliterals: + tok = LexToken() + tok.value = lexdata[lexpos] + tok.lineno = self.lineno + tok.type = tok.value + tok.lexpos = lexpos + self.lexpos = lexpos + 1 + return tok + + # No match. Call t_error() if defined. + if self.lexerrorf: + tok = LexToken() + tok.value = self.lexdata[lexpos:] + tok.lineno = self.lineno + tok.type = 'error' + tok.lexer = self + tok.lexpos = lexpos + self.lexpos = lexpos + newtok = self.lexerrorf(tok) + if lexpos == self.lexpos: + # Error method didn't change text position at all. This is an error. + raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) + lexpos = self.lexpos + if not newtok: + continue + return newtok + + self.lexpos = lexpos + raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos], lexpos), lexdata[lexpos:]) + + if self.lexeoff: + tok = LexToken() + tok.type = 'eof' + tok.value = '' + tok.lineno = self.lineno + tok.lexpos = lexpos + tok.lexer = self + self.lexpos = lexpos + newtok = self.lexeoff(tok) + return newtok + + self.lexpos = lexpos + 1 + if self.lexdata is None: + raise RuntimeError('No input string given with input()') + return None + + # Iterator interface + def __iter__(self): + return self + + def next(self): + t = self.token() + if t is None: + raise StopIteration + return t + + __next__ = next + +# ----------------------------------------------------------------------------- +# ==== Lex Builder === +# +# The functions and classes below are used to collect lexing information +# and build a Lexer object from it. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# _get_regex(func) +# +# Returns the regular expression assigned to a function either as a doc string +# or as a .regex attribute attached by the @TOKEN decorator. +# ----------------------------------------------------------------------------- +def _get_regex(func): + return getattr(func, 'regex', func.__doc__) + +# ----------------------------------------------------------------------------- +# get_caller_module_dict() +# +# This function returns a dictionary containing all of the symbols defined within +# a caller further down the call stack. This is used to get the environment +# associated with the yacc() call if none was provided. +# ----------------------------------------------------------------------------- +def get_caller_module_dict(levels): + f = sys._getframe(levels) + ldict = f.f_globals.copy() + if f.f_globals != f.f_locals: + ldict.update(f.f_locals) + return ldict + +# ----------------------------------------------------------------------------- +# _funcs_to_names() +# +# Given a list of regular expression functions, this converts it to a list +# suitable for output to a table file +# ----------------------------------------------------------------------------- +def _funcs_to_names(funclist, namelist): + result = [] + for f, name in zip(funclist, namelist): + if f and f[0]: + result.append((name, f[1])) + else: + result.append(f) + return result + +# ----------------------------------------------------------------------------- +# _names_to_funcs() +# +# Given a list of regular expression function names, this converts it back to +# functions. +# ----------------------------------------------------------------------------- +def _names_to_funcs(namelist, fdict): + result = [] + for n in namelist: + if n and n[0]: + result.append((fdict[n[0]], n[1])) + else: + result.append(n) + return result + +# ----------------------------------------------------------------------------- +# _form_master_re() +# +# This function takes a list of all of the regex components and attempts to +# form the master regular expression. Given limitations in the Python re +# module, it may be necessary to break the master regex into separate expressions. +# ----------------------------------------------------------------------------- +def _form_master_re(relist, reflags, ldict, toknames): + if not relist: + return [] + regex = '|'.join(relist) + try: + lexre = re.compile(regex, reflags) + + # Build the index to function map for the matching engine + lexindexfunc = [None] * (max(lexre.groupindex.values()) + 1) + lexindexnames = lexindexfunc[:] + + for f, i in lexre.groupindex.items(): + handle = ldict.get(f, None) + if type(handle) in (types.FunctionType, types.MethodType): + lexindexfunc[i] = (handle, toknames[f]) + lexindexnames[i] = f + elif handle is not None: + lexindexnames[i] = f + if f.find('ignore_') > 0: + lexindexfunc[i] = (None, None) + else: + lexindexfunc[i] = (None, toknames[f]) + + return [(lexre, lexindexfunc)], [regex], [lexindexnames] + except Exception: + m = int(len(relist)/2) + if m == 0: + m = 1 + llist, lre, lnames = _form_master_re(relist[:m], reflags, ldict, toknames) + rlist, rre, rnames = _form_master_re(relist[m:], reflags, ldict, toknames) + return (llist+rlist), (lre+rre), (lnames+rnames) + +# ----------------------------------------------------------------------------- +# def _statetoken(s,names) +# +# Given a declaration name s of the form "t_" and a dictionary whose keys are +# state names, this function returns a tuple (states,tokenname) where states +# is a tuple of state names and tokenname is the name of the token. For example, +# calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') +# ----------------------------------------------------------------------------- +def _statetoken(s, names): + nonstate = 1 + parts = s.split('_') + for i, part in enumerate(parts[1:], 1): + if part not in names and part != 'ANY': + break + + if i > 1: + states = tuple(parts[1:i]) + else: + states = ('INITIAL',) + + if 'ANY' in states: + states = tuple(names) + + tokenname = '_'.join(parts[i:]) + return (states, tokenname) + + +# ----------------------------------------------------------------------------- +# LexerReflect() +# +# This class represents information needed to build a lexer as extracted from a +# user's input file. +# ----------------------------------------------------------------------------- +class LexerReflect(object): + def __init__(self, ldict, log=None, reflags=0): + self.ldict = ldict + self.error_func = None + self.tokens = [] + self.reflags = reflags + self.stateinfo = {'INITIAL': 'inclusive'} + self.modules = set() + self.error = False + self.log = PlyLogger(sys.stderr) if log is None else log + + # Get all of the basic information + def get_all(self): + self.get_tokens() + self.get_literals() + self.get_states() + self.get_rules() + + # Validate all of the information + def validate_all(self): + self.validate_tokens() + self.validate_literals() + self.validate_rules() + return self.error + + # Get the tokens map + def get_tokens(self): + tokens = self.ldict.get('tokens', None) + if not tokens: + self.log.error('No token list is defined') + self.error = True + return + + if not isinstance(tokens, (list, tuple)): + self.log.error('tokens must be a list or tuple') + self.error = True + return + + if not tokens: + self.log.error('tokens is empty') + self.error = True + return + + self.tokens = tokens + + # Validate the tokens + def validate_tokens(self): + terminals = {} + for n in self.tokens: + if not _is_identifier.match(n): + self.log.error("Bad token name '%s'", n) + self.error = True + if n in terminals: + self.log.warning("Token '%s' multiply defined", n) + terminals[n] = 1 + + # Get the literals specifier + def get_literals(self): + self.literals = self.ldict.get('literals', '') + if not self.literals: + self.literals = '' + + # Validate literals + def validate_literals(self): + try: + for c in self.literals: + if not isinstance(c, StringTypes) or len(c) > 1: + self.log.error('Invalid literal %s. Must be a single character', repr(c)) + self.error = True + + except TypeError: + self.log.error('Invalid literals specification. literals must be a sequence of characters') + self.error = True + + def get_states(self): + self.states = self.ldict.get('states', None) + # Build statemap + if self.states: + if not isinstance(self.states, (tuple, list)): + self.log.error('states must be defined as a tuple or list') + self.error = True + else: + for s in self.states: + if not isinstance(s, tuple) or len(s) != 2: + self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')", repr(s)) + self.error = True + continue + name, statetype = s + if not isinstance(name, StringTypes): + self.log.error('State name %s must be a string', repr(name)) + self.error = True + continue + if not (statetype == 'inclusive' or statetype == 'exclusive'): + self.log.error("State type for state %s must be 'inclusive' or 'exclusive'", name) + self.error = True + continue + if name in self.stateinfo: + self.log.error("State '%s' already defined", name) + self.error = True + continue + self.stateinfo[name] = statetype + + # Get all of the symbols with a t_ prefix and sort them into various + # categories (functions, strings, error functions, and ignore characters) + + def get_rules(self): + tsymbols = [f for f in self.ldict if f[:2] == 't_'] + + # Now build up a list of functions and a list of strings + self.toknames = {} # Mapping of symbols to token names + self.funcsym = {} # Symbols defined as functions + self.strsym = {} # Symbols defined as strings + self.ignore = {} # Ignore strings by state + self.errorf = {} # Error functions by state + self.eoff = {} # EOF functions by state + + for s in self.stateinfo: + self.funcsym[s] = [] + self.strsym[s] = [] + + if len(tsymbols) == 0: + self.log.error('No rules of the form t_rulename are defined') + self.error = True + return + + for f in tsymbols: + t = self.ldict[f] + states, tokname = _statetoken(f, self.stateinfo) + self.toknames[f] = tokname + + if hasattr(t, '__call__'): + if tokname == 'error': + for s in states: + self.errorf[s] = t + elif tokname == 'eof': + for s in states: + self.eoff[s] = t + elif tokname == 'ignore': + line = t.__code__.co_firstlineno + file = t.__code__.co_filename + self.log.error("%s:%d: Rule '%s' must be defined as a string", file, line, t.__name__) + self.error = True + else: + for s in states: + self.funcsym[s].append((f, t)) + elif isinstance(t, StringTypes): + if tokname == 'ignore': + for s in states: + self.ignore[s] = t + if '\\' in t: + self.log.warning("%s contains a literal backslash '\\'", f) + + elif tokname == 'error': + self.log.error("Rule '%s' must be defined as a function", f) + self.error = True + else: + for s in states: + self.strsym[s].append((f, t)) + else: + self.log.error('%s not defined as a function or string', f) + self.error = True + + # Sort the functions by line number + for f in self.funcsym.values(): + f.sort(key=lambda x: x[1].__code__.co_firstlineno) + + # Sort the strings by regular expression length + for s in self.strsym.values(): + s.sort(key=lambda x: len(x[1]), reverse=True) + + # Validate all of the t_rules collected + def validate_rules(self): + for state in self.stateinfo: + # Validate all rules defined by functions + + for fname, f in self.funcsym[state]: + line = f.__code__.co_firstlineno + file = f.__code__.co_filename + module = inspect.getmodule(f) + self.modules.add(module) + + tokname = self.toknames[fname] + if isinstance(f, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + nargs = f.__code__.co_argcount + if nargs > reqargs: + self.log.error("%s:%d: Rule '%s' has too many arguments", file, line, f.__name__) + self.error = True + continue + + if nargs < reqargs: + self.log.error("%s:%d: Rule '%s' requires an argument", file, line, f.__name__) + self.error = True + continue + + if not _get_regex(f): + self.log.error("%s:%d: No regular expression defined for rule '%s'", file, line, f.__name__) + self.error = True + continue + + try: + c = re.compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags) + if c.match(''): + self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file, line, f.__name__) + self.error = True + except re.error as e: + self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file, line, f.__name__, e) + if '#' in _get_regex(f): + self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'", file, line, f.__name__) + self.error = True + + # Validate all rules defined by strings + for name, r in self.strsym[state]: + tokname = self.toknames[name] + if tokname == 'error': + self.log.error("Rule '%s' must be defined as a function", name) + self.error = True + continue + + if tokname not in self.tokens and tokname.find('ignore_') < 0: + self.log.error("Rule '%s' defined for an unspecified token %s", name, tokname) + self.error = True + continue + + try: + c = re.compile('(?P<%s>%s)' % (name, r), self.reflags) + if (c.match('')): + self.log.error("Regular expression for rule '%s' matches empty string", name) + self.error = True + except re.error as e: + self.log.error("Invalid regular expression for rule '%s'. %s", name, e) + if '#' in r: + self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'", name) + self.error = True + + if not self.funcsym[state] and not self.strsym[state]: + self.log.error("No rules defined for state '%s'", state) + self.error = True + + # Validate the error function + efunc = self.errorf.get(state, None) + if efunc: + f = efunc + line = f.__code__.co_firstlineno + file = f.__code__.co_filename + module = inspect.getmodule(f) + self.modules.add(module) + + if isinstance(f, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + nargs = f.__code__.co_argcount + if nargs > reqargs: + self.log.error("%s:%d: Rule '%s' has too many arguments", file, line, f.__name__) + self.error = True + + if nargs < reqargs: + self.log.error("%s:%d: Rule '%s' requires an argument", file, line, f.__name__) + self.error = True + + for module in self.modules: + self.validate_module(module) + + # ----------------------------------------------------------------------------- + # validate_module() + # + # This checks to see if there are duplicated t_rulename() functions or strings + # in the parser input file. This is done using a simple regular expression + # match on each line in the source code of the given module. + # ----------------------------------------------------------------------------- + + def validate_module(self, module): + try: + lines, linen = inspect.getsourcelines(module) + except IOError: + return + + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') + + counthash = {} + linen += 1 + for line in lines: + m = fre.match(line) + if not m: + m = sre.match(line) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + filename = inspect.getsourcefile(module) + self.log.error('%s:%d: Rule %s redefined. Previously defined on line %d', filename, linen, name, prev) + self.error = True + linen += 1 + +# ----------------------------------------------------------------------------- +# lex(module) +# +# Build all of the regular expression rules from definitions in the supplied module +# ----------------------------------------------------------------------------- +def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab', + reflags=int(re.VERBOSE), nowarn=False, outputdir=None, debuglog=None, errorlog=None): + + if lextab is None: + lextab = 'lextab' + + global lexer + + ldict = None + stateinfo = {'INITIAL': 'inclusive'} + lexobj = Lexer() + lexobj.lexoptimize = optimize + global token, input + + if errorlog is None: + errorlog = PlyLogger(sys.stderr) + + if debug: + if debuglog is None: + debuglog = PlyLogger(sys.stderr) + + # Get the module dictionary used for the lexer + if object: + module = object + + # Get the module dictionary used for the parser + if module: + _items = [(k, getattr(module, k)) for k in dir(module)] + ldict = dict(_items) + # If no __file__ attribute is available, try to obtain it from the __module__ instead + if '__file__' not in ldict: + ldict['__file__'] = sys.modules[ldict['__module__']].__file__ + else: + ldict = get_caller_module_dict(2) + + # Determine if the module is package of a package or not. + # If so, fix the tabmodule setting so that tables load correctly + pkg = ldict.get('__package__') + if pkg and isinstance(lextab, str): + if '.' not in lextab: + lextab = pkg + '.' + lextab + + # Collect parser information from the dictionary + linfo = LexerReflect(ldict, log=errorlog, reflags=reflags) + linfo.get_all() + if not optimize: + if linfo.validate_all(): + raise SyntaxError("Can't build lexer") + + if optimize and lextab: + try: + lexobj.readtab(lextab, ldict) + token = lexobj.token + input = lexobj.input + lexer = lexobj + return lexobj + + except ImportError: + pass + + # Dump some basic debugging information + if debug: + debuglog.info('lex: tokens = %r', linfo.tokens) + debuglog.info('lex: literals = %r', linfo.literals) + debuglog.info('lex: states = %r', linfo.stateinfo) + + # Build a dictionary of valid token names + lexobj.lextokens = set() + for n in linfo.tokens: + lexobj.lextokens.add(n) + + # Get literals specification + if isinstance(linfo.literals, (list, tuple)): + lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals) + else: + lexobj.lexliterals = linfo.literals + + lexobj.lextokens_all = lexobj.lextokens | set(lexobj.lexliterals) + + # Get the stateinfo dictionary + stateinfo = linfo.stateinfo + + regexs = {} + # Build the master regular expressions + for state in stateinfo: + regex_list = [] + + # Add rules defined by functions first + for fname, f in linfo.funcsym[state]: + line = f.__code__.co_firstlineno + file = f.__code__.co_filename + regex_list.append('(?P<%s>%s)' % (fname, _get_regex(f))) + if debug: + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", fname, _get_regex(f), state) + + # Now add all of the simple rules + for name, r in linfo.strsym[state]: + regex_list.append('(?P<%s>%s)' % (name, r)) + if debug: + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", name, r, state) + + regexs[state] = regex_list + + # Build the master regular expressions + + if debug: + debuglog.info('lex: ==== MASTER REGEXS FOLLOW ====') + + for state in regexs: + lexre, re_text, re_names = _form_master_re(regexs[state], reflags, ldict, linfo.toknames) + lexobj.lexstatere[state] = lexre + lexobj.lexstateretext[state] = re_text + lexobj.lexstaterenames[state] = re_names + if debug: + for i, text in enumerate(re_text): + debuglog.info("lex: state '%s' : regex[%d] = '%s'", state, i, text) + + # For inclusive states, we need to add the regular expressions from the INITIAL state + for state, stype in stateinfo.items(): + if state != 'INITIAL' and stype == 'inclusive': + lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) + lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) + lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) + + lexobj.lexstateinfo = stateinfo + lexobj.lexre = lexobj.lexstatere['INITIAL'] + lexobj.lexretext = lexobj.lexstateretext['INITIAL'] + lexobj.lexreflags = reflags + + # Set up ignore variables + lexobj.lexstateignore = linfo.ignore + lexobj.lexignore = lexobj.lexstateignore.get('INITIAL', '') + + # Set up error functions + lexobj.lexstateerrorf = linfo.errorf + lexobj.lexerrorf = linfo.errorf.get('INITIAL', None) + if not lexobj.lexerrorf: + errorlog.warning('No t_error rule is defined') + + # Set up eof functions + lexobj.lexstateeoff = linfo.eoff + lexobj.lexeoff = linfo.eoff.get('INITIAL', None) + + # Check state information for ignore and error rules + for s, stype in stateinfo.items(): + if stype == 'exclusive': + if s not in linfo.errorf: + errorlog.warning("No error rule is defined for exclusive state '%s'", s) + if s not in linfo.ignore and lexobj.lexignore: + errorlog.warning("No ignore rule is defined for exclusive state '%s'", s) + elif stype == 'inclusive': + if s not in linfo.errorf: + linfo.errorf[s] = linfo.errorf.get('INITIAL', None) + if s not in linfo.ignore: + linfo.ignore[s] = linfo.ignore.get('INITIAL', '') + + # Create global versions of the token() and input() functions + token = lexobj.token + input = lexobj.input + lexer = lexobj + + # If in optimize mode, we write the lextab + if lextab and optimize: + if outputdir is None: + # If no output directory is set, the location of the output files + # is determined according to the following rules: + # - If lextab specifies a package, files go into that package directory + # - Otherwise, files go in the same directory as the specifying module + if isinstance(lextab, types.ModuleType): + srcfile = lextab.__file__ + else: + if '.' not in lextab: + srcfile = ldict['__file__'] + else: + parts = lextab.split('.') + pkgname = '.'.join(parts[:-1]) + exec('import %s' % pkgname) + srcfile = getattr(sys.modules[pkgname], '__file__', '') + outputdir = os.path.dirname(srcfile) + try: + lexobj.writetab(lextab, outputdir) + except IOError as e: + errorlog.warning("Couldn't write lextab module %r. %s" % (lextab, e)) + + return lexobj + +# ----------------------------------------------------------------------------- +# runmain() +# +# This runs the lexer as a main program +# ----------------------------------------------------------------------------- + +def runmain(lexer=None, data=None): + if not data: + try: + filename = sys.argv[1] + f = open(filename) + data = f.read() + f.close() + except IndexError: + sys.stdout.write('Reading from standard input (type EOF to end):\n') + data = sys.stdin.read() + + if lexer: + _input = lexer.input + else: + _input = input + _input(data) + if lexer: + _token = lexer.token + else: + _token = token + + while True: + tok = _token() + if not tok: + break + sys.stdout.write('(%s,%r,%d,%d)\n' % (tok.type, tok.value, tok.lineno, tok.lexpos)) + +# ----------------------------------------------------------------------------- +# @TOKEN(regex) +# +# This decorator function can be used to set the regex expression on a function +# when its docstring might need to be set in an alternative way +# ----------------------------------------------------------------------------- + +def TOKEN(r): + def set_regex(f): + if hasattr(r, '__call__'): + f.regex = _get_regex(r) + else: + f.regex = r + return f + return set_regex + +# Alternative spelling of the TOKEN decorator +Token = TOKEN diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/yacc.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/yacc.py new file mode 100644 index 0000000000000000000000000000000000000000..20b4f2863cc7193ad4b779a30375c865495fa50c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/yacc.py @@ -0,0 +1,3494 @@ +# ----------------------------------------------------------------------------- +# ply: yacc.py +# +# Copyright (C) 2001-2017 +# David M. Beazley (Dabeaz LLC) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# +# This implements an LR parser that is constructed from grammar rules defined +# as Python functions. The grammer is specified by supplying the BNF inside +# Python documentation strings. The inspiration for this technique was borrowed +# from John Aycock's Spark parsing system. PLY might be viewed as cross between +# Spark and the GNU bison utility. +# +# The current implementation is only somewhat object-oriented. The +# LR parser itself is defined in terms of an object (which allows multiple +# parsers to co-exist). However, most of the variables used during table +# construction are defined in terms of global variables. Users shouldn't +# notice unless they are trying to define multiple parsers at the same +# time using threads (in which case they should have their head examined). +# +# This implementation supports both SLR and LALR(1) parsing. LALR(1) +# support was originally implemented by Elias Ioup (ezioup@alumni.uchicago.edu), +# using the algorithm found in Aho, Sethi, and Ullman "Compilers: Principles, +# Techniques, and Tools" (The Dragon Book). LALR(1) has since been replaced +# by the more efficient DeRemer and Pennello algorithm. +# +# :::::::: WARNING ::::::: +# +# Construction of LR parsing tables is fairly complicated and expensive. +# To make this module run fast, a *LOT* of work has been put into +# optimization---often at the expensive of readability and what might +# consider to be good Python "coding style." Modify the code at your +# own risk! +# ---------------------------------------------------------------------------- + +import re +import types +import sys +import os.path +import inspect +import base64 +import warnings + +__version__ = '3.10' +__tabversion__ = '3.10' + +#----------------------------------------------------------------------------- +# === User configurable parameters === +# +# Change these to modify the default behavior of yacc (if you wish) +#----------------------------------------------------------------------------- + +yaccdebug = True # Debugging mode. If set, yacc generates a + # a 'parser.out' file in the current directory + +debug_file = 'parser.out' # Default name of the debugging file +tab_module = 'parsetab' # Default name of the table module +default_lr = 'LALR' # Default LR table generation method + +error_count = 3 # Number of symbols that must be shifted to leave recovery mode + +yaccdevel = False # Set to True if developing yacc. This turns off optimized + # implementations of certain functions. + +resultlimit = 40 # Size limit of results when running in debug mode. + +pickle_protocol = 0 # Protocol to use when writing pickle files + +# String type-checking compatibility +if sys.version_info[0] < 3: + string_types = basestring +else: + string_types = str + +MAXINT = sys.maxsize + +# This object is a stand-in for a logging object created by the +# logging module. PLY will use this by default to create things +# such as the parser.out file. If a user wants more detailed +# information, they can create their own logging object and pass +# it into PLY. + +class PlyLogger(object): + def __init__(self, f): + self.f = f + + def debug(self, msg, *args, **kwargs): + self.f.write((msg % args) + '\n') + + info = debug + + def warning(self, msg, *args, **kwargs): + self.f.write('WARNING: ' + (msg % args) + '\n') + + def error(self, msg, *args, **kwargs): + self.f.write('ERROR: ' + (msg % args) + '\n') + + critical = debug + +# Null logger is used when no output is generated. Does nothing. +class NullLogger(object): + def __getattribute__(self, name): + return self + + def __call__(self, *args, **kwargs): + return self + +# Exception raised for yacc-related errors +class YaccError(Exception): + pass + +# Format the result message that the parser produces when running in debug mode. +def format_result(r): + repr_str = repr(r) + if '\n' in repr_str: + repr_str = repr(repr_str) + if len(repr_str) > resultlimit: + repr_str = repr_str[:resultlimit] + ' ...' + result = '<%s @ 0x%x> (%s)' % (type(r).__name__, id(r), repr_str) + return result + +# Format stack entries when the parser is running in debug mode +def format_stack_entry(r): + repr_str = repr(r) + if '\n' in repr_str: + repr_str = repr(repr_str) + if len(repr_str) < 16: + return repr_str + else: + return '<%s @ 0x%x>' % (type(r).__name__, id(r)) + +# Panic mode error recovery support. This feature is being reworked--much of the +# code here is to offer a deprecation/backwards compatible transition + +_errok = None +_token = None +_restart = None +_warnmsg = '''PLY: Don't use global functions errok(), token(), and restart() in p_error(). +Instead, invoke the methods on the associated parser instance: + + def p_error(p): + ... + # Use parser.errok(), parser.token(), parser.restart() + ... + + parser = yacc.yacc() +''' + +def errok(): + warnings.warn(_warnmsg) + return _errok() + +def restart(): + warnings.warn(_warnmsg) + return _restart() + +def token(): + warnings.warn(_warnmsg) + return _token() + +# Utility function to call the p_error() function with some deprecation hacks +def call_errorfunc(errorfunc, token, parser): + global _errok, _token, _restart + _errok = parser.errok + _token = parser.token + _restart = parser.restart + r = errorfunc(token) + try: + del _errok, _token, _restart + except NameError: + pass + return r + +#----------------------------------------------------------------------------- +# === LR Parsing Engine === +# +# The following classes are used for the LR parser itself. These are not +# used during table construction and are independent of the actual LR +# table generation algorithm +#----------------------------------------------------------------------------- + +# This class is used to hold non-terminal grammar symbols during parsing. +# It normally has the following attributes set: +# .type = Grammar symbol type +# .value = Symbol value +# .lineno = Starting line number +# .endlineno = Ending line number (optional, set automatically) +# .lexpos = Starting lex position +# .endlexpos = Ending lex position (optional, set automatically) + +class YaccSymbol: + def __str__(self): + return self.type + + def __repr__(self): + return str(self) + +# This class is a wrapper around the objects actually passed to each +# grammar rule. Index lookup and assignment actually assign the +# .value attribute of the underlying YaccSymbol object. +# The lineno() method returns the line number of a given +# item (or 0 if not defined). The linespan() method returns +# a tuple of (startline,endline) representing the range of lines +# for a symbol. The lexspan() method returns a tuple (lexpos,endlexpos) +# representing the range of positional information for a symbol. + +class YaccProduction: + def __init__(self, s, stack=None): + self.slice = s + self.stack = stack + self.lexer = None + self.parser = None + + def __getitem__(self, n): + if isinstance(n, slice): + return [s.value for s in self.slice[n]] + elif n >= 0: + return self.slice[n].value + else: + return self.stack[n].value + + def __setitem__(self, n, v): + self.slice[n].value = v + + def __getslice__(self, i, j): + return [s.value for s in self.slice[i:j]] + + def __len__(self): + return len(self.slice) + + def lineno(self, n): + return getattr(self.slice[n], 'lineno', 0) + + def set_lineno(self, n, lineno): + self.slice[n].lineno = lineno + + def linespan(self, n): + startline = getattr(self.slice[n], 'lineno', 0) + endline = getattr(self.slice[n], 'endlineno', startline) + return startline, endline + + def lexpos(self, n): + return getattr(self.slice[n], 'lexpos', 0) + + def lexspan(self, n): + startpos = getattr(self.slice[n], 'lexpos', 0) + endpos = getattr(self.slice[n], 'endlexpos', startpos) + return startpos, endpos + + def error(self): + raise SyntaxError + +# ----------------------------------------------------------------------------- +# == LRParser == +# +# The LR Parsing engine. +# ----------------------------------------------------------------------------- + +class LRParser: + def __init__(self, lrtab, errorf): + self.productions = lrtab.lr_productions + self.action = lrtab.lr_action + self.goto = lrtab.lr_goto + self.errorfunc = errorf + self.set_defaulted_states() + self.errorok = True + + def errok(self): + self.errorok = True + + def restart(self): + del self.statestack[:] + del self.symstack[:] + sym = YaccSymbol() + sym.type = '$end' + self.symstack.append(sym) + self.statestack.append(0) + + # Defaulted state support. + # This method identifies parser states where there is only one possible reduction action. + # For such states, the parser can make a choose to make a rule reduction without consuming + # the next look-ahead token. This delayed invocation of the tokenizer can be useful in + # certain kinds of advanced parsing situations where the lexer and parser interact with + # each other or change states (i.e., manipulation of scope, lexer states, etc.). + # + # See: https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions + def set_defaulted_states(self): + self.defaulted_states = {} + for state, actions in self.action.items(): + rules = list(actions.values()) + if len(rules) == 1 and rules[0] < 0: + self.defaulted_states[state] = rules[0] + + def disable_defaulted_states(self): + self.defaulted_states = {} + + def parse(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None): + if debug or yaccdevel: + if isinstance(debug, int): + debug = PlyLogger(sys.stderr) + return self.parsedebug(input, lexer, debug, tracking, tokenfunc) + elif tracking: + return self.parseopt(input, lexer, debug, tracking, tokenfunc) + else: + return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc) + + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parsedebug(). + # + # This is the debugging enabled version of parse(). All changes made to the + # parsing engine should be made here. Optimized versions of this function + # are automatically created by the ply/ygen.py script. This script cuts out + # sections enclosed in markers such as this: + # + # #--! DEBUG + # statements + # #--! DEBUG + # + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + def parsedebug(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None): + #--! parsedebug-start + lookahead = None # Current lookahead symbol + lookaheadstack = [] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + defaulted_states = self.defaulted_states # Local reference to defaulted states + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + #--! DEBUG + debug.info('PLY: PARSE DEBUG START') + #--! DEBUG + + # If no lexer was given, we will try to use the lex module + if not lexer: + from . import lex + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set the parser() token method (sometimes used in error recovery) + self.token = get_token + + # Set up the state and symbol stacks + + statestack = [] # Stack of parsing states + self.statestack = statestack + symstack = [] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = '$end' + symstack.append(sym) + state = 0 + while True: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + #--! DEBUG + debug.debug('') + debug.debug('State : %s', state) + #--! DEBUG + + if state not in defaulted_states: + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + else: + t = defaulted_states[state] + #--! DEBUG + debug.debug('Defaulted state %s: Reduce using %d', state, -t) + #--! DEBUG + + #--! DEBUG + debug.debug('Stack : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) + #--! DEBUG + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + #--! DEBUG + debug.debug('Action : Shift and goto state %s', t) + #--! DEBUG + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: + errorcount -= 1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + #--! DEBUG + if plen: + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, + '['+','.join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+']', + goto[statestack[-1-plen]][pname]) + else: + debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, [], + goto[statestack[-1]][pname]) + + #--! DEBUG + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + #--! TRACKING + if tracking: + t1 = targ[1] + sym.lineno = t1.lineno + sym.lexpos = t1.lexpos + t1 = targ[-1] + sym.endlineno = getattr(t1, 'endlineno', t1.lineno) + sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos) + #--! TRACKING + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + self.state = state + p.callable(pslice) + del statestack[-plen:] + #--! DEBUG + debug.info('Result : %s', format_result(pslice[0])) + #--! DEBUG + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + symstack.extend(targ[1:-1]) # Put the production slice back on the stack + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + #--! TRACKING + if tracking: + sym.lineno = lexer.lineno + sym.lexpos = lexer.lexpos + #--! TRACKING + + targ = [sym] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + self.state = state + p.callable(pslice) + #--! DEBUG + debug.info('Result : %s', format_result(pslice[0])) + #--! DEBUG + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + result = getattr(n, 'value', None) + #--! DEBUG + debug.info('Done : Returning %s', format_result(result)) + debug.info('PLY: PARSE DEBUG END') + #--! DEBUG + return result + + if t is None: + + #--! DEBUG + debug.error('Error : %s', + ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) + #--! DEBUG + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = False + errtoken = lookahead + if errtoken.type == '$end': + errtoken = None # End of file! + if self.errorfunc: + if errtoken and not hasattr(errtoken, 'lexer'): + errtoken.lexer = lexer + self.state = state + tok = call_errorfunc(self.errorfunc, errtoken, self) + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken, 'lineno'): + lineno = lookahead.lineno + else: + lineno = 0 + if lineno: + sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type)) + else: + sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type) + else: + sys.stderr.write('yacc: Parse error in input. EOF\n') + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$end': + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$end': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + #--! TRACKING + if tracking: + sym.endlineno = getattr(lookahead, 'lineno', sym.lineno) + sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos) + #--! TRACKING + lookahead = None + continue + + # Create the error symbol for the first time and make it the new lookahead symbol + t = YaccSymbol() + t.type = 'error' + + if hasattr(lookahead, 'lineno'): + t.lineno = t.endlineno = lookahead.lineno + if hasattr(lookahead, 'lexpos'): + t.lexpos = t.endlexpos = lookahead.lexpos + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + sym = symstack.pop() + #--! TRACKING + if tracking: + lookahead.lineno = sym.lineno + lookahead.lexpos = sym.lexpos + #--! TRACKING + statestack.pop() + state = statestack[-1] + + continue + + # Call an error function here + raise RuntimeError('yacc: internal parser error!!!\n') + + #--! parsedebug-end + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parseopt(). + # + # Optimized version of parse() method. DO NOT EDIT THIS CODE DIRECTLY! + # This code is automatically generated by the ply/ygen.py script. Make + # changes to the parsedebug() method instead. + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + def parseopt(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None): + #--! parseopt-start + lookahead = None # Current lookahead symbol + lookaheadstack = [] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + defaulted_states = self.defaulted_states # Local reference to defaulted states + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + + # If no lexer was given, we will try to use the lex module + if not lexer: + from . import lex + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set the parser() token method (sometimes used in error recovery) + self.token = get_token + + # Set up the state and symbol stacks + + statestack = [] # Stack of parsing states + self.statestack = statestack + symstack = [] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = '$end' + symstack.append(sym) + state = 0 + while True: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + + if state not in defaulted_states: + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + else: + t = defaulted_states[state] + + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: + errorcount -= 1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + #--! TRACKING + if tracking: + t1 = targ[1] + sym.lineno = t1.lineno + sym.lexpos = t1.lexpos + t1 = targ[-1] + sym.endlineno = getattr(t1, 'endlineno', t1.lineno) + sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos) + #--! TRACKING + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + self.state = state + p.callable(pslice) + del statestack[-plen:] + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + symstack.extend(targ[1:-1]) # Put the production slice back on the stack + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + #--! TRACKING + if tracking: + sym.lineno = lexer.lineno + sym.lexpos = lexer.lexpos + #--! TRACKING + + targ = [sym] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + self.state = state + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + result = getattr(n, 'value', None) + return result + + if t is None: + + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = False + errtoken = lookahead + if errtoken.type == '$end': + errtoken = None # End of file! + if self.errorfunc: + if errtoken and not hasattr(errtoken, 'lexer'): + errtoken.lexer = lexer + self.state = state + tok = call_errorfunc(self.errorfunc, errtoken, self) + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken, 'lineno'): + lineno = lookahead.lineno + else: + lineno = 0 + if lineno: + sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type)) + else: + sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type) + else: + sys.stderr.write('yacc: Parse error in input. EOF\n') + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$end': + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$end': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + #--! TRACKING + if tracking: + sym.endlineno = getattr(lookahead, 'lineno', sym.lineno) + sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos) + #--! TRACKING + lookahead = None + continue + + # Create the error symbol for the first time and make it the new lookahead symbol + t = YaccSymbol() + t.type = 'error' + + if hasattr(lookahead, 'lineno'): + t.lineno = t.endlineno = lookahead.lineno + if hasattr(lookahead, 'lexpos'): + t.lexpos = t.endlexpos = lookahead.lexpos + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + sym = symstack.pop() + #--! TRACKING + if tracking: + lookahead.lineno = sym.lineno + lookahead.lexpos = sym.lexpos + #--! TRACKING + statestack.pop() + state = statestack[-1] + + continue + + # Call an error function here + raise RuntimeError('yacc: internal parser error!!!\n') + + #--! parseopt-end + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parseopt_notrack(). + # + # Optimized version of parseopt() with line number tracking removed. + # DO NOT EDIT THIS CODE DIRECTLY. This code is automatically generated + # by the ply/ygen.py script. Make changes to the parsedebug() method instead. + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + def parseopt_notrack(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None): + #--! parseopt-notrack-start + lookahead = None # Current lookahead symbol + lookaheadstack = [] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + defaulted_states = self.defaulted_states # Local reference to defaulted states + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + + # If no lexer was given, we will try to use the lex module + if not lexer: + from . import lex + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set the parser() token method (sometimes used in error recovery) + self.token = get_token + + # Set up the state and symbol stacks + + statestack = [] # Stack of parsing states + self.statestack = statestack + symstack = [] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = '$end' + symstack.append(sym) + state = 0 + while True: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + + if state not in defaulted_states: + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + else: + t = defaulted_states[state] + + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: + errorcount -= 1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + self.state = state + p.callable(pslice) + del statestack[-plen:] + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + symstack.extend(targ[1:-1]) # Put the production slice back on the stack + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + + targ = [sym] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + self.state = state + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) # Save the current lookahead token + statestack.pop() # Pop back one state (before the reduce) + state = statestack[-1] + sym.type = 'error' + sym.value = 'error' + lookahead = sym + errorcount = error_count + self.errorok = False + + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + result = getattr(n, 'value', None) + return result + + if t is None: + + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = False + errtoken = lookahead + if errtoken.type == '$end': + errtoken = None # End of file! + if self.errorfunc: + if errtoken and not hasattr(errtoken, 'lexer'): + errtoken.lexer = lexer + self.state = state + tok = call_errorfunc(self.errorfunc, errtoken, self) + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken, 'lineno'): + lineno = lookahead.lineno + else: + lineno = 0 + if lineno: + sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type)) + else: + sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type) + else: + sys.stderr.write('yacc: Parse error in input. EOF\n') + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$end': + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$end': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + + # Create the error symbol for the first time and make it the new lookahead symbol + t = YaccSymbol() + t.type = 'error' + + if hasattr(lookahead, 'lineno'): + t.lineno = t.endlineno = lookahead.lineno + if hasattr(lookahead, 'lexpos'): + t.lexpos = t.endlexpos = lookahead.lexpos + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + sym = symstack.pop() + statestack.pop() + state = statestack[-1] + + continue + + # Call an error function here + raise RuntimeError('yacc: internal parser error!!!\n') + + #--! parseopt-notrack-end + +# ----------------------------------------------------------------------------- +# === Grammar Representation === +# +# The following functions, classes, and variables are used to represent and +# manipulate the rules that make up a grammar. +# ----------------------------------------------------------------------------- + +# regex matching identifiers +_is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') + +# ----------------------------------------------------------------------------- +# class Production: +# +# This class stores the raw information about a single production or grammar rule. +# A grammar rule refers to a specification such as this: +# +# expr : expr PLUS term +# +# Here are the basic attributes defined on all productions +# +# name - Name of the production. For example 'expr' +# prod - A list of symbols on the right side ['expr','PLUS','term'] +# prec - Production precedence level +# number - Production number. +# func - Function that executes on reduce +# file - File where production function is defined +# lineno - Line number where production function is defined +# +# The following attributes are defined or optional. +# +# len - Length of the production (number of symbols on right hand side) +# usyms - Set of unique symbols found in the production +# ----------------------------------------------------------------------------- + +class Production(object): + reduced = 0 + def __init__(self, number, name, prod, precedence=('right', 0), func=None, file='', line=0): + self.name = name + self.prod = tuple(prod) + self.number = number + self.func = func + self.callable = None + self.file = file + self.line = line + self.prec = precedence + + # Internal settings used during table construction + + self.len = len(self.prod) # Length of the production + + # Create a list of unique production symbols used in the production + self.usyms = [] + for s in self.prod: + if s not in self.usyms: + self.usyms.append(s) + + # List of all LR items for the production + self.lr_items = [] + self.lr_next = None + + # Create a string representation + if self.prod: + self.str = '%s -> %s' % (self.name, ' '.join(self.prod)) + else: + self.str = '%s -> <empty>' % self.name + + def __str__(self): + return self.str + + def __repr__(self): + return 'Production(' + str(self) + ')' + + def __len__(self): + return len(self.prod) + + def __nonzero__(self): + return 1 + + def __getitem__(self, index): + return self.prod[index] + + # Return the nth lr_item from the production (or None if at the end) + def lr_item(self, n): + if n > len(self.prod): + return None + p = LRItem(self, n) + # Precompute the list of productions immediately following. + try: + p.lr_after = Prodnames[p.prod[n+1]] + except (IndexError, KeyError): + p.lr_after = [] + try: + p.lr_before = p.prod[n-1] + except IndexError: + p.lr_before = None + return p + + # Bind the production function name to a callable + def bind(self, pdict): + if self.func: + self.callable = pdict[self.func] + +# This class serves as a minimal standin for Production objects when +# reading table data from files. It only contains information +# actually used by the LR parsing engine, plus some additional +# debugging information. +class MiniProduction(object): + def __init__(self, str, name, len, func, file, line): + self.name = name + self.len = len + self.func = func + self.callable = None + self.file = file + self.line = line + self.str = str + + def __str__(self): + return self.str + + def __repr__(self): + return 'MiniProduction(%s)' % self.str + + # Bind the production function name to a callable + def bind(self, pdict): + if self.func: + self.callable = pdict[self.func] + + +# ----------------------------------------------------------------------------- +# class LRItem +# +# This class represents a specific stage of parsing a production rule. For +# example: +# +# expr : expr . PLUS term +# +# In the above, the "." represents the current location of the parse. Here +# basic attributes: +# +# name - Name of the production. For example 'expr' +# prod - A list of symbols on the right side ['expr','.', 'PLUS','term'] +# number - Production number. +# +# lr_next Next LR item. Example, if we are ' expr -> expr . PLUS term' +# then lr_next refers to 'expr -> expr PLUS . term' +# lr_index - LR item index (location of the ".") in the prod list. +# lookaheads - LALR lookahead symbols for this item +# len - Length of the production (number of symbols on right hand side) +# lr_after - List of all productions that immediately follow +# lr_before - Grammar symbol immediately before +# ----------------------------------------------------------------------------- + +class LRItem(object): + def __init__(self, p, n): + self.name = p.name + self.prod = list(p.prod) + self.number = p.number + self.lr_index = n + self.lookaheads = {} + self.prod.insert(n, '.') + self.prod = tuple(self.prod) + self.len = len(self.prod) + self.usyms = p.usyms + + def __str__(self): + if self.prod: + s = '%s -> %s' % (self.name, ' '.join(self.prod)) + else: + s = '%s -> <empty>' % self.name + return s + + def __repr__(self): + return 'LRItem(' + str(self) + ')' + +# ----------------------------------------------------------------------------- +# rightmost_terminal() +# +# Return the rightmost terminal from a list of symbols. Used in add_production() +# ----------------------------------------------------------------------------- +def rightmost_terminal(symbols, terminals): + i = len(symbols) - 1 + while i >= 0: + if symbols[i] in terminals: + return symbols[i] + i -= 1 + return None + +# ----------------------------------------------------------------------------- +# === GRAMMAR CLASS === +# +# The following class represents the contents of the specified grammar along +# with various computed properties such as first sets, follow sets, LR items, etc. +# This data is used for critical parts of the table generation process later. +# ----------------------------------------------------------------------------- + +class GrammarError(YaccError): + pass + +class Grammar(object): + def __init__(self, terminals): + self.Productions = [None] # A list of all of the productions. The first + # entry is always reserved for the purpose of + # building an augmented grammar + + self.Prodnames = {} # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. + + self.Prodmap = {} # A dictionary that is only used to detect duplicate + # productions. + + self.Terminals = {} # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. + + for term in terminals: + self.Terminals[term] = [] + + self.Terminals['error'] = [] + + self.Nonterminals = {} # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. + + self.First = {} # A dictionary of precomputed FIRST(x) symbols + + self.Follow = {} # A dictionary of precomputed FOLLOW(x) symbols + + self.Precedence = {} # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) + + self.UsedPrecedence = set() # Precedence rules that were actually used by the grammer. + # This is only used to provide error checking and to generate + # a warning about unused precedence rules. + + self.Start = None # Starting symbol for the grammar + + + def __len__(self): + return len(self.Productions) + + def __getitem__(self, index): + return self.Productions[index] + + # ----------------------------------------------------------------------------- + # set_precedence() + # + # Sets the precedence for a given terminal. assoc is the associativity such as + # 'left','right', or 'nonassoc'. level is a numeric level. + # + # ----------------------------------------------------------------------------- + + def set_precedence(self, term, assoc, level): + assert self.Productions == [None], 'Must call set_precedence() before add_production()' + if term in self.Precedence: + raise GrammarError('Precedence already specified for terminal %r' % term) + if assoc not in ['left', 'right', 'nonassoc']: + raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'") + self.Precedence[term] = (assoc, level) + + # ----------------------------------------------------------------------------- + # add_production() + # + # Given an action function, this function assembles a production rule and + # computes its precedence level. + # + # The production rule is supplied as a list of symbols. For example, + # a rule such as 'expr : expr PLUS term' has a production name of 'expr' and + # symbols ['expr','PLUS','term']. + # + # Precedence is determined by the precedence of the right-most non-terminal + # or the precedence of a terminal specified by %prec. + # + # A variety of error checks are performed to make sure production symbols + # are valid and that %prec is used correctly. + # ----------------------------------------------------------------------------- + + def add_production(self, prodname, syms, func=None, file='', line=0): + + if prodname in self.Terminals: + raise GrammarError('%s:%d: Illegal rule name %r. Already defined as a token' % (file, line, prodname)) + if prodname == 'error': + raise GrammarError('%s:%d: Illegal rule name %r. error is a reserved word' % (file, line, prodname)) + if not _is_identifier.match(prodname): + raise GrammarError('%s:%d: Illegal rule name %r' % (file, line, prodname)) + + # Look for literal tokens + for n, s in enumerate(syms): + if s[0] in "'\"": + try: + c = eval(s) + if (len(c) > 1): + raise GrammarError('%s:%d: Literal token %s in rule %r may only be a single character' % + (file, line, s, prodname)) + if c not in self.Terminals: + self.Terminals[c] = [] + syms[n] = c + continue + except SyntaxError: + pass + if not _is_identifier.match(s) and s != '%prec': + raise GrammarError('%s:%d: Illegal name %r in rule %r' % (file, line, s, prodname)) + + # Determine the precedence level + if '%prec' in syms: + if syms[-1] == '%prec': + raise GrammarError('%s:%d: Syntax error. Nothing follows %%prec' % (file, line)) + if syms[-2] != '%prec': + raise GrammarError('%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule' % + (file, line)) + precname = syms[-1] + prodprec = self.Precedence.get(precname) + if not prodprec: + raise GrammarError('%s:%d: Nothing known about the precedence of %r' % (file, line, precname)) + else: + self.UsedPrecedence.add(precname) + del syms[-2:] # Drop %prec from the rule + else: + # If no %prec, precedence is determined by the rightmost terminal symbol + precname = rightmost_terminal(syms, self.Terminals) + prodprec = self.Precedence.get(precname, ('right', 0)) + + # See if the rule is already in the rulemap + map = '%s -> %s' % (prodname, syms) + if map in self.Prodmap: + m = self.Prodmap[map] + raise GrammarError('%s:%d: Duplicate rule %s. ' % (file, line, m) + + 'Previous definition at %s:%d' % (m.file, m.line)) + + # From this point on, everything is valid. Create a new Production instance + pnumber = len(self.Productions) + if prodname not in self.Nonterminals: + self.Nonterminals[prodname] = [] + + # Add the production number to Terminals and Nonterminals + for t in syms: + if t in self.Terminals: + self.Terminals[t].append(pnumber) + else: + if t not in self.Nonterminals: + self.Nonterminals[t] = [] + self.Nonterminals[t].append(pnumber) + + # Create a production and add it to the list of productions + p = Production(pnumber, prodname, syms, prodprec, func, file, line) + self.Productions.append(p) + self.Prodmap[map] = p + + # Add to the global productions list + try: + self.Prodnames[prodname].append(p) + except KeyError: + self.Prodnames[prodname] = [p] + + # ----------------------------------------------------------------------------- + # set_start() + # + # Sets the starting symbol and creates the augmented grammar. Production + # rule 0 is S' -> start where start is the start symbol. + # ----------------------------------------------------------------------------- + + def set_start(self, start=None): + if not start: + start = self.Productions[1].name + if start not in self.Nonterminals: + raise GrammarError('start symbol %s undefined' % start) + self.Productions[0] = Production(0, "S'", [start]) + self.Nonterminals[start].append(0) + self.Start = start + + # ----------------------------------------------------------------------------- + # find_unreachable() + # + # Find all of the nonterminal symbols that can't be reached from the starting + # symbol. Returns a list of nonterminals that can't be reached. + # ----------------------------------------------------------------------------- + + def find_unreachable(self): + + # Mark all symbols that are reachable from a symbol s + def mark_reachable_from(s): + if s in reachable: + return + reachable.add(s) + for p in self.Prodnames.get(s, []): + for r in p.prod: + mark_reachable_from(r) + + reachable = set() + mark_reachable_from(self.Productions[0].prod[0]) + return [s for s in self.Nonterminals if s not in reachable] + + # ----------------------------------------------------------------------------- + # infinite_cycles() + # + # This function looks at the various parsing rules and tries to detect + # infinite recursion cycles (grammar rules where there is no possible way + # to derive a string of only terminals). + # ----------------------------------------------------------------------------- + + def infinite_cycles(self): + terminates = {} + + # Terminals: + for t in self.Terminals: + terminates[t] = True + + terminates['$end'] = True + + # Nonterminals: + + # Initialize to false: + for n in self.Nonterminals: + terminates[n] = False + + # Then propagate termination until no change: + while True: + some_change = False + for (n, pl) in self.Prodnames.items(): + # Nonterminal n terminates iff any of its productions terminates. + for p in pl: + # Production p terminates iff all of its rhs symbols terminate. + for s in p.prod: + if not terminates[s]: + # The symbol s does not terminate, + # so production p does not terminate. + p_terminates = False + break + else: + # didn't break from the loop, + # so every symbol s terminates + # so production p terminates. + p_terminates = True + + if p_terminates: + # symbol n terminates! + if not terminates[n]: + terminates[n] = True + some_change = True + # Don't need to consider any more productions for this n. + break + + if not some_change: + break + + infinite = [] + for (s, term) in terminates.items(): + if not term: + if s not in self.Prodnames and s not in self.Terminals and s != 'error': + # s is used-but-not-defined, and we've already warned of that, + # so it would be overkill to say that it's also non-terminating. + pass + else: + infinite.append(s) + + return infinite + + # ----------------------------------------------------------------------------- + # undefined_symbols() + # + # Find all symbols that were used the grammar, but not defined as tokens or + # grammar rules. Returns a list of tuples (sym, prod) where sym in the symbol + # and prod is the production where the symbol was used. + # ----------------------------------------------------------------------------- + def undefined_symbols(self): + result = [] + for p in self.Productions: + if not p: + continue + + for s in p.prod: + if s not in self.Prodnames and s not in self.Terminals and s != 'error': + result.append((s, p)) + return result + + # ----------------------------------------------------------------------------- + # unused_terminals() + # + # Find all terminals that were defined, but not used by the grammar. Returns + # a list of all symbols. + # ----------------------------------------------------------------------------- + def unused_terminals(self): + unused_tok = [] + for s, v in self.Terminals.items(): + if s != 'error' and not v: + unused_tok.append(s) + + return unused_tok + + # ------------------------------------------------------------------------------ + # unused_rules() + # + # Find all grammar rules that were defined, but not used (maybe not reachable) + # Returns a list of productions. + # ------------------------------------------------------------------------------ + + def unused_rules(self): + unused_prod = [] + for s, v in self.Nonterminals.items(): + if not v: + p = self.Prodnames[s][0] + unused_prod.append(p) + return unused_prod + + # ----------------------------------------------------------------------------- + # unused_precedence() + # + # Returns a list of tuples (term,precedence) corresponding to precedence + # rules that were never used by the grammar. term is the name of the terminal + # on which precedence was applied and precedence is a string such as 'left' or + # 'right' corresponding to the type of precedence. + # ----------------------------------------------------------------------------- + + def unused_precedence(self): + unused = [] + for termname in self.Precedence: + if not (termname in self.Terminals or termname in self.UsedPrecedence): + unused.append((termname, self.Precedence[termname][0])) + + return unused + + # ------------------------------------------------------------------------- + # _first() + # + # Compute the value of FIRST1(beta) where beta is a tuple of symbols. + # + # During execution of compute_first1, the result may be incomplete. + # Afterward (e.g., when called from compute_follow()), it will be complete. + # ------------------------------------------------------------------------- + def _first(self, beta): + + # We are computing First(x1,x2,x3,...,xn) + result = [] + for x in beta: + x_produces_empty = False + + # Add all the non-<empty> symbols of First[x] to the result. + for f in self.First[x]: + if f == '<empty>': + x_produces_empty = True + else: + if f not in result: + result.append(f) + + if x_produces_empty: + # We have to consider the next x in beta, + # i.e. stay in the loop. + pass + else: + # We don't have to consider any further symbols in beta. + break + else: + # There was no 'break' from the loop, + # so x_produces_empty was true for all x in beta, + # so beta produces empty as well. + result.append('<empty>') + + return result + + # ------------------------------------------------------------------------- + # compute_first() + # + # Compute the value of FIRST1(X) for all symbols + # ------------------------------------------------------------------------- + def compute_first(self): + if self.First: + return self.First + + # Terminals: + for t in self.Terminals: + self.First[t] = [t] + + self.First['$end'] = ['$end'] + + # Nonterminals: + + # Initialize to the empty set: + for n in self.Nonterminals: + self.First[n] = [] + + # Then propagate symbols until no change: + while True: + some_change = False + for n in self.Nonterminals: + for p in self.Prodnames[n]: + for f in self._first(p.prod): + if f not in self.First[n]: + self.First[n].append(f) + some_change = True + if not some_change: + break + + return self.First + + # --------------------------------------------------------------------- + # compute_follow() + # + # Computes all of the follow sets for every non-terminal symbol. The + # follow set is the set of all symbols that might follow a given + # non-terminal. See the Dragon book, 2nd Ed. p. 189. + # --------------------------------------------------------------------- + def compute_follow(self, start=None): + # If already computed, return the result + if self.Follow: + return self.Follow + + # If first sets not computed yet, do that first. + if not self.First: + self.compute_first() + + # Add '$end' to the follow list of the start symbol + for k in self.Nonterminals: + self.Follow[k] = [] + + if not start: + start = self.Productions[1].name + + self.Follow[start] = ['$end'] + + while True: + didadd = False + for p in self.Productions[1:]: + # Here is the production set + for i, B in enumerate(p.prod): + if B in self.Nonterminals: + # Okay. We got a non-terminal in a production + fst = self._first(p.prod[i+1:]) + hasempty = False + for f in fst: + if f != '<empty>' and f not in self.Follow[B]: + self.Follow[B].append(f) + didadd = True + if f == '<empty>': + hasempty = True + if hasempty or i == (len(p.prod)-1): + # Add elements of follow(a) to follow(b) + for f in self.Follow[p.name]: + if f not in self.Follow[B]: + self.Follow[B].append(f) + didadd = True + if not didadd: + break + return self.Follow + + + # ----------------------------------------------------------------------------- + # build_lritems() + # + # This function walks the list of productions and builds a complete set of the + # LR items. The LR items are stored in two ways: First, they are uniquely + # numbered and placed in the list _lritems. Second, a linked list of LR items + # is built for each production. For example: + # + # E -> E PLUS E + # + # Creates the list + # + # [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ] + # ----------------------------------------------------------------------------- + + def build_lritems(self): + for p in self.Productions: + lastlri = p + i = 0 + lr_items = [] + while True: + if i > len(p): + lri = None + else: + lri = LRItem(p, i) + # Precompute the list of productions immediately following + try: + lri.lr_after = self.Prodnames[lri.prod[i+1]] + except (IndexError, KeyError): + lri.lr_after = [] + try: + lri.lr_before = lri.prod[i-1] + except IndexError: + lri.lr_before = None + + lastlri.lr_next = lri + if not lri: + break + lr_items.append(lri) + lastlri = lri + i += 1 + p.lr_items = lr_items + +# ----------------------------------------------------------------------------- +# == Class LRTable == +# +# This basic class represents a basic table of LR parsing information. +# Methods for generating the tables are not defined here. They are defined +# in the derived class LRGeneratedTable. +# ----------------------------------------------------------------------------- + +class VersionError(YaccError): + pass + +class LRTable(object): + def __init__(self): + self.lr_action = None + self.lr_goto = None + self.lr_productions = None + self.lr_method = None + + def read_table(self, module): + if isinstance(module, types.ModuleType): + parsetab = module + else: + exec('import %s' % module) + parsetab = sys.modules[module] + + if parsetab._tabversion != __tabversion__: + raise VersionError('yacc table file version is out of date') + + self.lr_action = parsetab._lr_action + self.lr_goto = parsetab._lr_goto + + self.lr_productions = [] + for p in parsetab._lr_productions: + self.lr_productions.append(MiniProduction(*p)) + + self.lr_method = parsetab._lr_method + return parsetab._lr_signature + + def read_pickle(self, filename): + try: + import cPickle as pickle + except ImportError: + import pickle + + if not os.path.exists(filename): + raise ImportError + + in_f = open(filename, 'rb') + + tabversion = pickle.load(in_f) + if tabversion != __tabversion__: + raise VersionError('yacc table file version is out of date') + self.lr_method = pickle.load(in_f) + signature = pickle.load(in_f) + self.lr_action = pickle.load(in_f) + self.lr_goto = pickle.load(in_f) + productions = pickle.load(in_f) + + self.lr_productions = [] + for p in productions: + self.lr_productions.append(MiniProduction(*p)) + + in_f.close() + return signature + + # Bind all production function names to callable objects in pdict + def bind_callables(self, pdict): + for p in self.lr_productions: + p.bind(pdict) + + +# ----------------------------------------------------------------------------- +# === LR Generator === +# +# The following classes and functions are used to generate LR parsing tables on +# a grammar. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# digraph() +# traverse() +# +# The following two functions are used to compute set valued functions +# of the form: +# +# F(x) = F'(x) U U{F(y) | x R y} +# +# This is used to compute the values of Read() sets as well as FOLLOW sets +# in LALR(1) generation. +# +# Inputs: X - An input set +# R - A relation +# FP - Set-valued function +# ------------------------------------------------------------------------------ + +def digraph(X, R, FP): + N = {} + for x in X: + N[x] = 0 + stack = [] + F = {} + for x in X: + if N[x] == 0: + traverse(x, N, stack, F, X, R, FP) + return F + +def traverse(x, N, stack, F, X, R, FP): + stack.append(x) + d = len(stack) + N[x] = d + F[x] = FP(x) # F(X) <- F'(x) + + rel = R(x) # Get y's related to x + for y in rel: + if N[y] == 0: + traverse(y, N, stack, F, X, R, FP) + N[x] = min(N[x], N[y]) + for a in F.get(y, []): + if a not in F[x]: + F[x].append(a) + if N[x] == d: + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + while element != x: + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + +class LALRError(YaccError): + pass + +# ----------------------------------------------------------------------------- +# == LRGeneratedTable == +# +# This class implements the LR table generation algorithm. There are no +# public methods except for write() +# ----------------------------------------------------------------------------- + +class LRGeneratedTable(LRTable): + def __init__(self, grammar, method='LALR', log=None): + if method not in ['SLR', 'LALR']: + raise LALRError('Unsupported method %s' % method) + + self.grammar = grammar + self.lr_method = method + + # Set up the logger + if not log: + log = NullLogger() + self.log = log + + # Internal attributes + self.lr_action = {} # Action table + self.lr_goto = {} # Goto table + self.lr_productions = grammar.Productions # Copy of grammar Production array + self.lr_goto_cache = {} # Cache of computed gotos + self.lr0_cidhash = {} # Cache of closures + + self._add_count = 0 # Internal counter used to detect cycles + + # Diagonistic information filled in by the table generator + self.sr_conflict = 0 + self.rr_conflict = 0 + self.conflicts = [] # List of conflicts + + self.sr_conflicts = [] + self.rr_conflicts = [] + + # Build the tables + self.grammar.build_lritems() + self.grammar.compute_first() + self.grammar.compute_follow() + self.lr_parse_table() + + # Compute the LR(0) closure operation on I, where I is a set of LR(0) items. + + def lr0_closure(self, I): + self._add_count += 1 + + # Add everything in I to J + J = I[:] + didadd = True + while didadd: + didadd = False + for j in J: + for x in j.lr_after: + if getattr(x, 'lr0_added', 0) == self._add_count: + continue + # Add B --> .G to J + J.append(x.lr_next) + x.lr0_added = self._add_count + didadd = True + + return J + + # Compute the LR(0) goto function goto(I,X) where I is a set + # of LR(0) items and X is a grammar symbol. This function is written + # in a way that guarantees uniqueness of the generated goto sets + # (i.e. the same goto set will never be returned as two different Python + # objects). With uniqueness, we can later do fast set comparisons using + # id(obj) instead of element-wise comparison. + + def lr0_goto(self, I, x): + # First we look for a previously cached entry + g = self.lr_goto_cache.get((id(I), x)) + if g: + return g + + # Now we generate the goto set in a way that guarantees uniqueness + # of the result + + s = self.lr_goto_cache.get(x) + if not s: + s = {} + self.lr_goto_cache[x] = s + + gs = [] + for p in I: + n = p.lr_next + if n and n.lr_before == x: + s1 = s.get(id(n)) + if not s1: + s1 = {} + s[id(n)] = s1 + gs.append(n) + s = s1 + g = s.get('$end') + if not g: + if gs: + g = self.lr0_closure(gs) + s['$end'] = g + else: + s['$end'] = gs + self.lr_goto_cache[(id(I), x)] = g + return g + + # Compute the LR(0) sets of item function + def lr0_items(self): + C = [self.lr0_closure([self.grammar.Productions[0].lr_next])] + i = 0 + for I in C: + self.lr0_cidhash[id(I)] = i + i += 1 + + # Loop over the items in C and each grammar symbols + i = 0 + while i < len(C): + I = C[i] + i += 1 + + # Collect all of the symbols that could possibly be in the goto(I,X) sets + asyms = {} + for ii in I: + for s in ii.usyms: + asyms[s] = None + + for x in asyms: + g = self.lr0_goto(I, x) + if not g or id(g) in self.lr0_cidhash: + continue + self.lr0_cidhash[id(g)] = len(C) + C.append(g) + + return C + + # ----------------------------------------------------------------------------- + # ==== LALR(1) Parsing ==== + # + # LALR(1) parsing is almost exactly the same as SLR except that instead of + # relying upon Follow() sets when performing reductions, a more selective + # lookahead set that incorporates the state of the LR(0) machine is utilized. + # Thus, we mainly just have to focus on calculating the lookahead sets. + # + # The method used here is due to DeRemer and Pennelo (1982). + # + # DeRemer, F. L., and T. J. Pennelo: "Efficient Computation of LALR(1) + # Lookahead Sets", ACM Transactions on Programming Languages and Systems, + # Vol. 4, No. 4, Oct. 1982, pp. 615-649 + # + # Further details can also be found in: + # + # J. Tremblay and P. Sorenson, "The Theory and Practice of Compiler Writing", + # McGraw-Hill Book Company, (1985). + # + # ----------------------------------------------------------------------------- + + # ----------------------------------------------------------------------------- + # compute_nullable_nonterminals() + # + # Creates a dictionary containing all of the non-terminals that might produce + # an empty production. + # ----------------------------------------------------------------------------- + + def compute_nullable_nonterminals(self): + nullable = set() + num_nullable = 0 + while True: + for p in self.grammar.Productions[1:]: + if p.len == 0: + nullable.add(p.name) + continue + for t in p.prod: + if t not in nullable: + break + else: + nullable.add(p.name) + if len(nullable) == num_nullable: + break + num_nullable = len(nullable) + return nullable + + # ----------------------------------------------------------------------------- + # find_nonterminal_trans(C) + # + # Given a set of LR(0) items, this functions finds all of the non-terminal + # transitions. These are transitions in which a dot appears immediately before + # a non-terminal. Returns a list of tuples of the form (state,N) where state + # is the state number and N is the nonterminal symbol. + # + # The input C is the set of LR(0) items. + # ----------------------------------------------------------------------------- + + def find_nonterminal_transitions(self, C): + trans = [] + for stateno, state in enumerate(C): + for p in state: + if p.lr_index < p.len - 1: + t = (stateno, p.prod[p.lr_index+1]) + if t[1] in self.grammar.Nonterminals: + if t not in trans: + trans.append(t) + return trans + + # ----------------------------------------------------------------------------- + # dr_relation() + # + # Computes the DR(p,A) relationships for non-terminal transitions. The input + # is a tuple (state,N) where state is a number and N is a nonterminal symbol. + # + # Returns a list of terminals. + # ----------------------------------------------------------------------------- + + def dr_relation(self, C, trans, nullable): + dr_set = {} + state, N = trans + terms = [] + + g = self.lr0_goto(C[state], N) + for p in g: + if p.lr_index < p.len - 1: + a = p.prod[p.lr_index+1] + if a in self.grammar.Terminals: + if a not in terms: + terms.append(a) + + # This extra bit is to handle the start state + if state == 0 and N == self.grammar.Productions[0].prod[0]: + terms.append('$end') + + return terms + + # ----------------------------------------------------------------------------- + # reads_relation() + # + # Computes the READS() relation (p,A) READS (t,C). + # ----------------------------------------------------------------------------- + + def reads_relation(self, C, trans, empty): + # Look for empty transitions + rel = [] + state, N = trans + + g = self.lr0_goto(C[state], N) + j = self.lr0_cidhash.get(id(g), -1) + for p in g: + if p.lr_index < p.len - 1: + a = p.prod[p.lr_index + 1] + if a in empty: + rel.append((j, a)) + + return rel + + # ----------------------------------------------------------------------------- + # compute_lookback_includes() + # + # Determines the lookback and includes relations + # + # LOOKBACK: + # + # This relation is determined by running the LR(0) state machine forward. + # For example, starting with a production "N : . A B C", we run it forward + # to obtain "N : A B C ." We then build a relationship between this final + # state and the starting state. These relationships are stored in a dictionary + # lookdict. + # + # INCLUDES: + # + # Computes the INCLUDE() relation (p,A) INCLUDES (p',B). + # + # This relation is used to determine non-terminal transitions that occur + # inside of other non-terminal transition states. (p,A) INCLUDES (p', B) + # if the following holds: + # + # B -> LAT, where T -> epsilon and p' -L-> p + # + # L is essentially a prefix (which may be empty), T is a suffix that must be + # able to derive an empty string. State p' must lead to state p with the string L. + # + # ----------------------------------------------------------------------------- + + def compute_lookback_includes(self, C, trans, nullable): + lookdict = {} # Dictionary of lookback relations + includedict = {} # Dictionary of include relations + + # Make a dictionary of non-terminal transitions + dtrans = {} + for t in trans: + dtrans[t] = 1 + + # Loop over all transitions and compute lookbacks and includes + for state, N in trans: + lookb = [] + includes = [] + for p in C[state]: + if p.name != N: + continue + + # Okay, we have a name match. We now follow the production all the way + # through the state machine until we get the . on the right hand side + + lr_index = p.lr_index + j = state + while lr_index < p.len - 1: + lr_index = lr_index + 1 + t = p.prod[lr_index] + + # Check to see if this symbol and state are a non-terminal transition + if (j, t) in dtrans: + # Yes. Okay, there is some chance that this is an includes relation + # the only way to know for certain is whether the rest of the + # production derives empty + + li = lr_index + 1 + while li < p.len: + if p.prod[li] in self.grammar.Terminals: + break # No forget it + if p.prod[li] not in nullable: + break + li = li + 1 + else: + # Appears to be a relation between (j,t) and (state,N) + includes.append((j, t)) + + g = self.lr0_goto(C[j], t) # Go to next set + j = self.lr0_cidhash.get(id(g), -1) # Go to next state + + # When we get here, j is the final state, now we have to locate the production + for r in C[j]: + if r.name != p.name: + continue + if r.len != p.len: + continue + i = 0 + # This look is comparing a production ". A B C" with "A B C ." + while i < r.lr_index: + if r.prod[i] != p.prod[i+1]: + break + i = i + 1 + else: + lookb.append((j, r)) + for i in includes: + if i not in includedict: + includedict[i] = [] + includedict[i].append((state, N)) + lookdict[(state, N)] = lookb + + return lookdict, includedict + + # ----------------------------------------------------------------------------- + # compute_read_sets() + # + # Given a set of LR(0) items, this function computes the read sets. + # + # Inputs: C = Set of LR(0) items + # ntrans = Set of nonterminal transitions + # nullable = Set of empty transitions + # + # Returns a set containing the read sets + # ----------------------------------------------------------------------------- + + def compute_read_sets(self, C, ntrans, nullable): + FP = lambda x: self.dr_relation(C, x, nullable) + R = lambda x: self.reads_relation(C, x, nullable) + F = digraph(ntrans, R, FP) + return F + + # ----------------------------------------------------------------------------- + # compute_follow_sets() + # + # Given a set of LR(0) items, a set of non-terminal transitions, a readset, + # and an include set, this function computes the follow sets + # + # Follow(p,A) = Read(p,A) U U {Follow(p',B) | (p,A) INCLUDES (p',B)} + # + # Inputs: + # ntrans = Set of nonterminal transitions + # readsets = Readset (previously computed) + # inclsets = Include sets (previously computed) + # + # Returns a set containing the follow sets + # ----------------------------------------------------------------------------- + + def compute_follow_sets(self, ntrans, readsets, inclsets): + FP = lambda x: readsets[x] + R = lambda x: inclsets.get(x, []) + F = digraph(ntrans, R, FP) + return F + + # ----------------------------------------------------------------------------- + # add_lookaheads() + # + # Attaches the lookahead symbols to grammar rules. + # + # Inputs: lookbacks - Set of lookback relations + # followset - Computed follow set + # + # This function directly attaches the lookaheads to productions contained + # in the lookbacks set + # ----------------------------------------------------------------------------- + + def add_lookaheads(self, lookbacks, followset): + for trans, lb in lookbacks.items(): + # Loop over productions in lookback + for state, p in lb: + if state not in p.lookaheads: + p.lookaheads[state] = [] + f = followset.get(trans, []) + for a in f: + if a not in p.lookaheads[state]: + p.lookaheads[state].append(a) + + # ----------------------------------------------------------------------------- + # add_lalr_lookaheads() + # + # This function does all of the work of adding lookahead information for use + # with LALR parsing + # ----------------------------------------------------------------------------- + + def add_lalr_lookaheads(self, C): + # Determine all of the nullable nonterminals + nullable = self.compute_nullable_nonterminals() + + # Find all non-terminal transitions + trans = self.find_nonterminal_transitions(C) + + # Compute read sets + readsets = self.compute_read_sets(C, trans, nullable) + + # Compute lookback/includes relations + lookd, included = self.compute_lookback_includes(C, trans, nullable) + + # Compute LALR FOLLOW sets + followsets = self.compute_follow_sets(trans, readsets, included) + + # Add all of the lookaheads + self.add_lookaheads(lookd, followsets) + + # ----------------------------------------------------------------------------- + # lr_parse_table() + # + # This function constructs the parse tables for SLR or LALR + # ----------------------------------------------------------------------------- + def lr_parse_table(self): + Productions = self.grammar.Productions + Precedence = self.grammar.Precedence + goto = self.lr_goto # Goto array + action = self.lr_action # Action array + log = self.log # Logger for output + + actionp = {} # Action production array (temporary) + + log.info('Parsing method: %s', self.lr_method) + + # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items + # This determines the number of states + + C = self.lr0_items() + + if self.lr_method == 'LALR': + self.add_lalr_lookaheads(C) + + # Build the parser table, state by state + st = 0 + for I in C: + # Loop over each production in I + actlist = [] # List of actions + st_action = {} + st_actionp = {} + st_goto = {} + log.info('') + log.info('state %d', st) + log.info('') + for p in I: + log.info(' (%d) %s', p.number, p) + log.info('') + + for p in I: + if p.len == p.lr_index + 1: + if p.name == "S'": + # Start symbol. Accept! + st_action['$end'] = 0 + st_actionp['$end'] = p + else: + # We are at the end of a production. Reduce! + if self.lr_method == 'LALR': + laheads = p.lookaheads[st] + else: + laheads = self.grammar.Follow[p.name] + for a in laheads: + actlist.append((a, p, 'reduce using rule %d (%s)' % (p.number, p))) + r = st_action.get(a) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from rule being reduced (p) + rprec, rlevel = Productions[p.number].prec + + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + st_action[a] = -p.number + st_actionp[a] = p + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + Productions[p.number].reduced += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the shift + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + st_action[a] = -p.number + st_actionp[a] = p + chosenp, rejectp = pp, oldp + Productions[p.number].reduced += 1 + Productions[oldp.number].reduced -= 1 + else: + chosenp, rejectp = oldp, pp + self.rr_conflicts.append((st, chosenp, rejectp)) + log.info(' ! reduce/reduce conflict for %s resolved using rule %d (%s)', + a, st_actionp[a].number, st_actionp[a]) + else: + raise LALRError('Unknown conflict in state %d' % st) + else: + st_action[a] = -p.number + st_actionp[a] = p + Productions[p.number].reduced += 1 + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if a in self.grammar.Terminals: + g = self.lr0_goto(I, a) + j = self.lr0_cidhash.get(id(g), -1) + if j >= 0: + # We are in a shift state + actlist.append((a, p, 'shift and go to state %d' % j)) + r = st_action.get(a) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + raise LALRError('Shift/shift conflict in state %d' % st) + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + + # Shift precedence comes from the token + sprec, slevel = Precedence.get(a, ('right', 0)) + + # Reduce precedence comes from the rule that could have been reduced + rprec, rlevel = Productions[st_actionp[a].number].prec + + if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): + # We decide to shift here... highest precedence to shift + Productions[st_actionp[a].number].reduced -= 1 + st_action[a] = j + st_actionp[a] = p + if not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as shift', a) + self.sr_conflicts.append((st, a, 'shift')) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + log.info(' ! shift/reduce conflict for %s resolved as reduce', a) + self.sr_conflicts.append((st, a, 'reduce')) + + else: + raise LALRError('Unknown conflict in state %d' % st) + else: + st_action[a] = j + st_actionp[a] = p + + # Print the actions associated with each terminal + _actprint = {} + for a, p, m in actlist: + if a in st_action: + if p is st_actionp[a]: + log.info(' %-15s %s', a, m) + _actprint[(a, m)] = 1 + log.info('') + # Print the actions that were not used. (debugging) + not_used = 0 + for a, p, m in actlist: + if a in st_action: + if p is not st_actionp[a]: + if not (a, m) in _actprint: + log.debug(' ! %-15s [ %s ]', a, m) + not_used = 1 + _actprint[(a, m)] = 1 + if not_used: + log.debug('') + + # Construct the goto table for this state + + nkeys = {} + for ii in I: + for s in ii.usyms: + if s in self.grammar.Nonterminals: + nkeys[s] = None + for n in nkeys: + g = self.lr0_goto(I, n) + j = self.lr0_cidhash.get(id(g), -1) + if j >= 0: + st_goto[n] = j + log.info(' %-30s shift and go to state %d', n, j) + + action[st] = st_action + actionp[st] = st_actionp + goto[st] = st_goto + st += 1 + + # ----------------------------------------------------------------------------- + # write() + # + # This function writes the LR parsing tables to a file + # ----------------------------------------------------------------------------- + + def write_table(self, tabmodule, outputdir='', signature=''): + if isinstance(tabmodule, types.ModuleType): + raise IOError("Won't overwrite existing tabmodule") + + basemodulename = tabmodule.split('.')[-1] + filename = os.path.join(outputdir, basemodulename) + '.py' + try: + f = open(filename, 'w') + + f.write(''' +# %s +# This file is automatically generated. Do not edit. +_tabversion = %r + +_lr_method = %r + +_lr_signature = %r + ''' % (os.path.basename(filename), __tabversion__, self.lr_method, signature)) + + # Change smaller to 0 to go back to original tables + smaller = 1 + + # Factor out names to try and make smaller + if smaller: + items = {} + + for s, nd in self.lr_action.items(): + for name, v in nd.items(): + i = items.get(name) + if not i: + i = ([], []) + items[name] = i + i[0].append(s) + i[1].append(v) + + f.write('\n_lr_action_items = {') + for k, v in items.items(): + f.write('%r:([' % k) + for i in v[0]: + f.write('%r,' % i) + f.write('],[') + for i in v[1]: + f.write('%r,' % i) + + f.write(']),') + f.write('}\n') + + f.write(''' +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items +''') + + else: + f.write('\n_lr_action = { ') + for k, v in self.lr_action.items(): + f.write('(%r,%r):%r,' % (k[0], k[1], v)) + f.write('}\n') + + if smaller: + # Factor out names to try and make smaller + items = {} + + for s, nd in self.lr_goto.items(): + for name, v in nd.items(): + i = items.get(name) + if not i: + i = ([], []) + items[name] = i + i[0].append(s) + i[1].append(v) + + f.write('\n_lr_goto_items = {') + for k, v in items.items(): + f.write('%r:([' % k) + for i in v[0]: + f.write('%r,' % i) + f.write('],[') + for i in v[1]: + f.write('%r,' % i) + + f.write(']),') + f.write('}\n') + + f.write(''' +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +''') + else: + f.write('\n_lr_goto = { ') + for k, v in self.lr_goto.items(): + f.write('(%r,%r):%r,' % (k[0], k[1], v)) + f.write('}\n') + + # Write production table + f.write('_lr_productions = [\n') + for p in self.lr_productions: + if p.func: + f.write(' (%r,%r,%d,%r,%r,%d),\n' % (p.str, p.name, p.len, + p.func, os.path.basename(p.file), p.line)) + else: + f.write(' (%r,%r,%d,None,None,None),\n' % (str(p), p.name, p.len)) + f.write(']\n') + f.close() + + except IOError as e: + raise + + + # ----------------------------------------------------------------------------- + # pickle_table() + # + # This function pickles the LR parsing tables to a supplied file object + # ----------------------------------------------------------------------------- + + def pickle_table(self, filename, signature=''): + try: + import cPickle as pickle + except ImportError: + import pickle + with open(filename, 'wb') as outf: + pickle.dump(__tabversion__, outf, pickle_protocol) + pickle.dump(self.lr_method, outf, pickle_protocol) + pickle.dump(signature, outf, pickle_protocol) + pickle.dump(self.lr_action, outf, pickle_protocol) + pickle.dump(self.lr_goto, outf, pickle_protocol) + + outp = [] + for p in self.lr_productions: + if p.func: + outp.append((p.str, p.name, p.len, p.func, os.path.basename(p.file), p.line)) + else: + outp.append((str(p), p.name, p.len, None, None, None)) + pickle.dump(outp, outf, pickle_protocol) + +# ----------------------------------------------------------------------------- +# === INTROSPECTION === +# +# The following functions and classes are used to implement the PLY +# introspection features followed by the yacc() function itself. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# get_caller_module_dict() +# +# This function returns a dictionary containing all of the symbols defined within +# a caller further down the call stack. This is used to get the environment +# associated with the yacc() call if none was provided. +# ----------------------------------------------------------------------------- + +def get_caller_module_dict(levels): + f = sys._getframe(levels) + ldict = f.f_globals.copy() + if f.f_globals != f.f_locals: + ldict.update(f.f_locals) + return ldict + +# ----------------------------------------------------------------------------- +# parse_grammar() +# +# This takes a raw grammar rule string and parses it into production data +# ----------------------------------------------------------------------------- +def parse_grammar(doc, file, line): + grammar = [] + # Split the doc string into lines + pstrings = doc.splitlines() + lastp = None + dline = line + for ps in pstrings: + dline += 1 + p = ps.split() + if not p: + continue + try: + if p[0] == '|': + # This is a continuation of a previous rule + if not lastp: + raise SyntaxError("%s:%d: Misplaced '|'" % (file, dline)) + prodname = lastp + syms = p[1:] + else: + prodname = p[0] + lastp = prodname + syms = p[2:] + assign = p[1] + if assign != ':' and assign != '::=': + raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file, dline)) + + grammar.append((file, dline, prodname, syms)) + except SyntaxError: + raise + except Exception: + raise SyntaxError('%s:%d: Syntax error in rule %r' % (file, dline, ps.strip())) + + return grammar + +# ----------------------------------------------------------------------------- +# ParserReflect() +# +# This class represents information extracted for building a parser including +# start symbol, error function, tokens, precedence list, action functions, +# etc. +# ----------------------------------------------------------------------------- +class ParserReflect(object): + def __init__(self, pdict, log=None): + self.pdict = pdict + self.start = None + self.error_func = None + self.tokens = None + self.modules = set() + self.grammar = [] + self.error = False + + if log is None: + self.log = PlyLogger(sys.stderr) + else: + self.log = log + + # Get all of the basic information + def get_all(self): + self.get_start() + self.get_error_func() + self.get_tokens() + self.get_precedence() + self.get_pfunctions() + + # Validate all of the information + def validate_all(self): + self.validate_start() + self.validate_error_func() + self.validate_tokens() + self.validate_precedence() + self.validate_pfunctions() + self.validate_modules() + return self.error + + # Compute a signature over the grammar + def signature(self): + parts = [] + try: + if self.start: + parts.append(self.start) + if self.prec: + parts.append(''.join([''.join(p) for p in self.prec])) + if self.tokens: + parts.append(' '.join(self.tokens)) + for f in self.pfuncs: + if f[3]: + parts.append(f[3]) + except (TypeError, ValueError): + pass + return ''.join(parts) + + # ----------------------------------------------------------------------------- + # validate_modules() + # + # This method checks to see if there are duplicated p_rulename() functions + # in the parser module file. Without this function, it is really easy for + # users to make mistakes by cutting and pasting code fragments (and it's a real + # bugger to try and figure out why the resulting parser doesn't work). Therefore, + # we just do a little regular expression pattern matching of def statements + # to try and detect duplicates. + # ----------------------------------------------------------------------------- + + def validate_modules(self): + # Match def p_funcname( + fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') + + for module in self.modules: + try: + lines, linen = inspect.getsourcelines(module) + except IOError: + continue + + counthash = {} + for linen, line in enumerate(lines): + linen += 1 + m = fre.match(line) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + filename = inspect.getsourcefile(module) + self.log.warning('%s:%d: Function %s redefined. Previously defined on line %d', + filename, linen, name, prev) + + # Get the start symbol + def get_start(self): + self.start = self.pdict.get('start') + + # Validate the start symbol + def validate_start(self): + if self.start is not None: + if not isinstance(self.start, string_types): + self.log.error("'start' must be a string") + + # Look for error handler + def get_error_func(self): + self.error_func = self.pdict.get('p_error') + + # Validate the error function + def validate_error_func(self): + if self.error_func: + if isinstance(self.error_func, types.FunctionType): + ismethod = 0 + elif isinstance(self.error_func, types.MethodType): + ismethod = 1 + else: + self.log.error("'p_error' defined, but is not a function or method") + self.error = True + return + + eline = self.error_func.__code__.co_firstlineno + efile = self.error_func.__code__.co_filename + module = inspect.getmodule(self.error_func) + self.modules.add(module) + + argcount = self.error_func.__code__.co_argcount - ismethod + if argcount != 1: + self.log.error('%s:%d: p_error() requires 1 argument', efile, eline) + self.error = True + + # Get the tokens map + def get_tokens(self): + tokens = self.pdict.get('tokens') + if not tokens: + self.log.error('No token list is defined') + self.error = True + return + + if not isinstance(tokens, (list, tuple)): + self.log.error('tokens must be a list or tuple') + self.error = True + return + + if not tokens: + self.log.error('tokens is empty') + self.error = True + return + + self.tokens = tokens + + # Validate the tokens + def validate_tokens(self): + # Validate the tokens. + if 'error' in self.tokens: + self.log.error("Illegal token name 'error'. Is a reserved word") + self.error = True + return + + terminals = set() + for n in self.tokens: + if n in terminals: + self.log.warning('Token %r multiply defined', n) + terminals.add(n) + + # Get the precedence map (if any) + def get_precedence(self): + self.prec = self.pdict.get('precedence') + + # Validate and parse the precedence map + def validate_precedence(self): + preclist = [] + if self.prec: + if not isinstance(self.prec, (list, tuple)): + self.log.error('precedence must be a list or tuple') + self.error = True + return + for level, p in enumerate(self.prec): + if not isinstance(p, (list, tuple)): + self.log.error('Bad precedence table') + self.error = True + return + + if len(p) < 2: + self.log.error('Malformed precedence entry %s. Must be (assoc, term, ..., term)', p) + self.error = True + return + assoc = p[0] + if not isinstance(assoc, string_types): + self.log.error('precedence associativity must be a string') + self.error = True + return + for term in p[1:]: + if not isinstance(term, string_types): + self.log.error('precedence items must be strings') + self.error = True + return + preclist.append((term, assoc, level+1)) + self.preclist = preclist + + # Get all p_functions from the grammar + def get_pfunctions(self): + p_functions = [] + for name, item in self.pdict.items(): + if not name.startswith('p_') or name == 'p_error': + continue + if isinstance(item, (types.FunctionType, types.MethodType)): + line = getattr(item, 'co_firstlineno', item.__code__.co_firstlineno) + module = inspect.getmodule(item) + p_functions.append((line, module, name, item.__doc__)) + + # Sort all of the actions by line number; make sure to stringify + # modules to make them sortable, since `line` may not uniquely sort all + # p functions + p_functions.sort(key=lambda p_function: ( + p_function[0], + str(p_function[1]), + p_function[2], + p_function[3])) + self.pfuncs = p_functions + + # Validate all of the p_functions + def validate_pfunctions(self): + grammar = [] + # Check for non-empty symbols + if len(self.pfuncs) == 0: + self.log.error('no rules of the form p_rulename are defined') + self.error = True + return + + for line, module, name, doc in self.pfuncs: + file = inspect.getsourcefile(module) + func = self.pdict[name] + if isinstance(func, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + if func.__code__.co_argcount > reqargs: + self.log.error('%s:%d: Rule %r has too many arguments', file, line, func.__name__) + self.error = True + elif func.__code__.co_argcount < reqargs: + self.log.error('%s:%d: Rule %r requires an argument', file, line, func.__name__) + self.error = True + elif not func.__doc__: + self.log.warning('%s:%d: No documentation string specified in function %r (ignored)', + file, line, func.__name__) + else: + try: + parsed_g = parse_grammar(doc, file, line) + for g in parsed_g: + grammar.append((name, g)) + except SyntaxError as e: + self.log.error(str(e)) + self.error = True + + # Looks like a valid grammar rule + # Mark the file in which defined. + self.modules.add(module) + + # Secondary validation step that looks for p_ definitions that are not functions + # or functions that look like they might be grammar rules. + + for n, v in self.pdict.items(): + if n.startswith('p_') and isinstance(v, (types.FunctionType, types.MethodType)): + continue + if n.startswith('t_'): + continue + if n.startswith('p_') and n != 'p_error': + self.log.warning('%r not defined as a function', n) + if ((isinstance(v, types.FunctionType) and v.__code__.co_argcount == 1) or + (isinstance(v, types.MethodType) and v.__func__.__code__.co_argcount == 2)): + if v.__doc__: + try: + doc = v.__doc__.split(' ') + if doc[1] == ':': + self.log.warning('%s:%d: Possible grammar rule %r defined without p_ prefix', + v.__code__.co_filename, v.__code__.co_firstlineno, n) + except IndexError: + pass + + self.grammar = grammar + +# ----------------------------------------------------------------------------- +# yacc(module) +# +# Build a parser +# ----------------------------------------------------------------------------- + +def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None, + check_recursion=True, optimize=False, write_tables=True, debugfile=debug_file, + outputdir=None, debuglog=None, errorlog=None, picklefile=None): + + if tabmodule is None: + tabmodule = tab_module + + # Reference to the parsing method of the last built parser + global parse + + # If pickling is enabled, table files are not created + if picklefile: + write_tables = 0 + + if errorlog is None: + errorlog = PlyLogger(sys.stderr) + + # Get the module dictionary used for the parser + if module: + _items = [(k, getattr(module, k)) for k in dir(module)] + pdict = dict(_items) + # If no __file__ attribute is available, try to obtain it from the __module__ instead + if '__file__' not in pdict: + pdict['__file__'] = sys.modules[pdict['__module__']].__file__ + else: + pdict = get_caller_module_dict(2) + + if outputdir is None: + # If no output directory is set, the location of the output files + # is determined according to the following rules: + # - If tabmodule specifies a package, files go into that package directory + # - Otherwise, files go in the same directory as the specifying module + if isinstance(tabmodule, types.ModuleType): + srcfile = tabmodule.__file__ + else: + if '.' not in tabmodule: + srcfile = pdict['__file__'] + else: + parts = tabmodule.split('.') + pkgname = '.'.join(parts[:-1]) + exec('import %s' % pkgname) + srcfile = getattr(sys.modules[pkgname], '__file__', '') + outputdir = os.path.dirname(srcfile) + + # Determine if the module is package of a package or not. + # If so, fix the tabmodule setting so that tables load correctly + pkg = pdict.get('__package__') + if pkg and isinstance(tabmodule, str): + if '.' not in tabmodule: + tabmodule = pkg + '.' + tabmodule + + + + # Set start symbol if it's specified directly using an argument + if start is not None: + pdict['start'] = start + + # Collect parser information from the dictionary + pinfo = ParserReflect(pdict, log=errorlog) + pinfo.get_all() + + if pinfo.error: + raise YaccError('Unable to build parser') + + # Check signature against table files (if any) + signature = pinfo.signature() + + # Read the tables + try: + lr = LRTable() + if picklefile: + read_signature = lr.read_pickle(picklefile) + else: + read_signature = lr.read_table(tabmodule) + if optimize or (read_signature == signature): + try: + lr.bind_callables(pinfo.pdict) + parser = LRParser(lr, pinfo.error_func) + parse = parser.parse + return parser + except Exception as e: + errorlog.warning('There was a problem loading the table file: %r', e) + except VersionError as e: + errorlog.warning(str(e)) + except ImportError: + pass + + if debuglog is None: + if debug: + try: + debuglog = PlyLogger(open(os.path.join(outputdir, debugfile), 'w')) + except IOError as e: + errorlog.warning("Couldn't open %r. %s" % (debugfile, e)) + debuglog = NullLogger() + else: + debuglog = NullLogger() + + debuglog.info('Created by PLY version %s (http://www.dabeaz.com/ply)', __version__) + + errors = False + + # Validate the parser information + if pinfo.validate_all(): + raise YaccError('Unable to build parser') + + if not pinfo.error_func: + errorlog.warning('no p_error() function is defined') + + # Create a grammar object + grammar = Grammar(pinfo.tokens) + + # Set precedence level for terminals + for term, assoc, level in pinfo.preclist: + try: + grammar.set_precedence(term, assoc, level) + except GrammarError as e: + errorlog.warning('%s', e) + + # Add productions to the grammar + for funcname, gram in pinfo.grammar: + file, line, prodname, syms = gram + try: + grammar.add_production(prodname, syms, funcname, file, line) + except GrammarError as e: + errorlog.error('%s', e) + errors = True + + # Set the grammar start symbols + try: + if start is None: + grammar.set_start(pinfo.start) + else: + grammar.set_start(start) + except GrammarError as e: + errorlog.error(str(e)) + errors = True + + if errors: + raise YaccError('Unable to build parser') + + # Verify the grammar structure + undefined_symbols = grammar.undefined_symbols() + for sym, prod in undefined_symbols: + errorlog.error('%s:%d: Symbol %r used, but not defined as a token or a rule', prod.file, prod.line, sym) + errors = True + + unused_terminals = grammar.unused_terminals() + if unused_terminals: + debuglog.info('') + debuglog.info('Unused terminals:') + debuglog.info('') + for term in unused_terminals: + errorlog.warning('Token %r defined, but not used', term) + debuglog.info(' %s', term) + + # Print out all productions to the debug log + if debug: + debuglog.info('') + debuglog.info('Grammar') + debuglog.info('') + for n, p in enumerate(grammar.Productions): + debuglog.info('Rule %-5d %s', n, p) + + # Find unused non-terminals + unused_rules = grammar.unused_rules() + for prod in unused_rules: + errorlog.warning('%s:%d: Rule %r defined, but not used', prod.file, prod.line, prod.name) + + if len(unused_terminals) == 1: + errorlog.warning('There is 1 unused token') + if len(unused_terminals) > 1: + errorlog.warning('There are %d unused tokens', len(unused_terminals)) + + if len(unused_rules) == 1: + errorlog.warning('There is 1 unused rule') + if len(unused_rules) > 1: + errorlog.warning('There are %d unused rules', len(unused_rules)) + + if debug: + debuglog.info('') + debuglog.info('Terminals, with rules where they appear') + debuglog.info('') + terms = list(grammar.Terminals) + terms.sort() + for term in terms: + debuglog.info('%-20s : %s', term, ' '.join([str(s) for s in grammar.Terminals[term]])) + + debuglog.info('') + debuglog.info('Nonterminals, with rules where they appear') + debuglog.info('') + nonterms = list(grammar.Nonterminals) + nonterms.sort() + for nonterm in nonterms: + debuglog.info('%-20s : %s', nonterm, ' '.join([str(s) for s in grammar.Nonterminals[nonterm]])) + debuglog.info('') + + if check_recursion: + unreachable = grammar.find_unreachable() + for u in unreachable: + errorlog.warning('Symbol %r is unreachable', u) + + infinite = grammar.infinite_cycles() + for inf in infinite: + errorlog.error('Infinite recursion detected for symbol %r', inf) + errors = True + + unused_prec = grammar.unused_precedence() + for term, assoc in unused_prec: + errorlog.error('Precedence rule %r defined for unknown symbol %r', assoc, term) + errors = True + + if errors: + raise YaccError('Unable to build parser') + + # Run the LRGeneratedTable on the grammar + if debug: + errorlog.debug('Generating %s tables', method) + + lr = LRGeneratedTable(grammar, method, debuglog) + + if debug: + num_sr = len(lr.sr_conflicts) + + # Report shift/reduce and reduce/reduce conflicts + if num_sr == 1: + errorlog.warning('1 shift/reduce conflict') + elif num_sr > 1: + errorlog.warning('%d shift/reduce conflicts', num_sr) + + num_rr = len(lr.rr_conflicts) + if num_rr == 1: + errorlog.warning('1 reduce/reduce conflict') + elif num_rr > 1: + errorlog.warning('%d reduce/reduce conflicts', num_rr) + + # Write out conflicts to the output file + if debug and (lr.sr_conflicts or lr.rr_conflicts): + debuglog.warning('') + debuglog.warning('Conflicts:') + debuglog.warning('') + + for state, tok, resolution in lr.sr_conflicts: + debuglog.warning('shift/reduce conflict for %s in state %d resolved as %s', tok, state, resolution) + + already_reported = set() + for state, rule, rejected in lr.rr_conflicts: + if (state, id(rule), id(rejected)) in already_reported: + continue + debuglog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + debuglog.warning('rejected rule (%s) in state %d', rejected, state) + errorlog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule) + errorlog.warning('rejected rule (%s) in state %d', rejected, state) + already_reported.add((state, id(rule), id(rejected))) + + warned_never = [] + for state, rule, rejected in lr.rr_conflicts: + if not rejected.reduced and (rejected not in warned_never): + debuglog.warning('Rule (%s) is never reduced', rejected) + errorlog.warning('Rule (%s) is never reduced', rejected) + warned_never.append(rejected) + + # Write the table file if requested + if write_tables: + try: + lr.write_table(tabmodule, outputdir, signature) + except IOError as e: + errorlog.warning("Couldn't create %r. %s" % (tabmodule, e)) + + # Write a pickled version of the tables + if picklefile: + try: + lr.pickle_table(picklefile, signature) + except IOError as e: + errorlog.warning("Couldn't create %r. %s" % (picklefile, e)) + + # Build the parser + lr.bind_callables(pinfo.pdict) + parser = LRParser(lr, pinfo.error_func) + + parse = parser.parse + return parser diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ygen.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ygen.py new file mode 100644 index 0000000000000000000000000000000000000000..acf5ca1a37b69389256227c570c65eed96e3228e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/ply/ygen.py @@ -0,0 +1,74 @@ +# ply: ygen.py +# +# This is a support program that auto-generates different versions of the YACC parsing +# function with different features removed for the purposes of performance. +# +# Users should edit the method LParser.parsedebug() in yacc.py. The source code +# for that method is then used to create the other methods. See the comments in +# yacc.py for further details. + +import os.path +import shutil + +def get_source_range(lines, tag): + srclines = enumerate(lines) + start_tag = '#--! %s-start' % tag + end_tag = '#--! %s-end' % tag + + for start_index, line in srclines: + if line.strip().startswith(start_tag): + break + + for end_index, line in srclines: + if line.strip().endswith(end_tag): + break + + return (start_index + 1, end_index) + +def filter_section(lines, tag): + filtered_lines = [] + include = True + tag_text = '#--! %s' % tag + for line in lines: + if line.strip().startswith(tag_text): + include = not include + elif include: + filtered_lines.append(line) + return filtered_lines + +def main(): + dirname = os.path.dirname(__file__) + shutil.copy2(os.path.join(dirname, 'yacc.py'), os.path.join(dirname, 'yacc.py.bak')) + with open(os.path.join(dirname, 'yacc.py'), 'r') as f: + lines = f.readlines() + + parse_start, parse_end = get_source_range(lines, 'parsedebug') + parseopt_start, parseopt_end = get_source_range(lines, 'parseopt') + parseopt_notrack_start, parseopt_notrack_end = get_source_range(lines, 'parseopt-notrack') + + # Get the original source + orig_lines = lines[parse_start:parse_end] + + # Filter the DEBUG sections out + parseopt_lines = filter_section(orig_lines, 'DEBUG') + + # Filter the TRACKING sections out + parseopt_notrack_lines = filter_section(parseopt_lines, 'TRACKING') + + # Replace the parser source sections with updated versions + lines[parseopt_notrack_start:parseopt_notrack_end] = parseopt_notrack_lines + lines[parseopt_start:parseopt_end] = parseopt_lines + + lines = [line.rstrip()+'\n' for line in lines] + with open(os.path.join(dirname, 'yacc.py'), 'w') as f: + f.writelines(lines) + + print('Updated yacc.py') + +if __name__ == '__main__': + main() + + + + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/plyparser.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/plyparser.py new file mode 100644 index 0000000000000000000000000000000000000000..b8f4c4395ea7ed07572aeb3a9d9064c0373b504b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/plyparser.py @@ -0,0 +1,133 @@ +#----------------------------------------------------------------- +# plyparser.py +# +# PLYParser class and other utilities for simplifying programming +# parsers with PLY +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +import warnings + +class Coord(object): + """ Coordinates of a syntactic element. Consists of: + - File name + - Line number + - (optional) column number, for the Lexer + """ + __slots__ = ('file', 'line', 'column', '__weakref__') + def __init__(self, file, line, column=None): + self.file = file + self.line = line + self.column = column + + def __str__(self): + str = "%s:%s" % (self.file, self.line) + if self.column: str += ":%s" % self.column + return str + + +class ParseError(Exception): pass + + +class PLYParser(object): + def _create_opt_rule(self, rulename): + """ Given a rule name, creates an optional ply.yacc rule + for it. The name of the optional rule is + <rulename>_opt + """ + optname = rulename + '_opt' + + def optrule(self, p): + p[0] = p[1] + + optrule.__doc__ = '%s : empty\n| %s' % (optname, rulename) + optrule.__name__ = 'p_%s' % optname + setattr(self.__class__, optrule.__name__, optrule) + + def _coord(self, lineno, column=None): + return Coord( + file=self.clex.filename, + line=lineno, + column=column) + + def _token_coord(self, p, token_idx): + """ Returns the coordinates for the YaccProduction object 'p' indexed + with 'token_idx'. The coordinate includes the 'lineno' and + 'column'. Both follow the lex semantic, starting from 1. + """ + last_cr = p.lexer.lexer.lexdata.rfind('\n', 0, p.lexpos(token_idx)) + if last_cr < 0: + last_cr = -1 + column = (p.lexpos(token_idx) - (last_cr)) + return self._coord(p.lineno(token_idx), column) + + def _parse_error(self, msg, coord): + raise ParseError("%s: %s" % (coord, msg)) + + +def parameterized(*params): + """ Decorator to create parameterized rules. + + Parameterized rule methods must be named starting with 'p_' and contain + 'xxx', and their docstrings may contain 'xxx' and 'yyy'. These will be + replaced by the given parameter tuples. For example, ``p_xxx_rule()`` with + docstring 'xxx_rule : yyy' when decorated with + ``@parameterized(('id', 'ID'))`` produces ``p_id_rule()`` with the docstring + 'id_rule : ID'. Using multiple tuples produces multiple rules. + """ + def decorate(rule_func): + rule_func._params = params + return rule_func + return decorate + + +def template(cls): + """ Class decorator to generate rules from parameterized rule templates. + + See `parameterized` for more information on parameterized rules. + """ + issued_nodoc_warning = False + for attr_name in dir(cls): + if attr_name.startswith('p_'): + method = getattr(cls, attr_name) + if hasattr(method, '_params'): + # Remove the template method + delattr(cls, attr_name) + # Create parameterized rules from this method; only run this if + # the method has a docstring. This is to address an issue when + # pycparser's users are installed in -OO mode which strips + # docstrings away. + # See: https://github.com/eliben/pycparser/pull/198/ and + # https://github.com/eliben/pycparser/issues/197 + # for discussion. + if method.__doc__ is not None: + _create_param_rules(cls, method) + elif not issued_nodoc_warning: + warnings.warn( + 'parsing methods must have __doc__ for pycparser to work properly', + RuntimeWarning, + stacklevel=2) + issued_nodoc_warning = True + return cls + + +def _create_param_rules(cls, func): + """ Create ply.yacc rules based on a parameterized rule function + + Generates new methods (one per each pair of parameters) based on the + template rule function `func`, and attaches them to `cls`. The rule + function's parameters must be accessible via its `_params` attribute. + """ + for xxx, yyy in func._params: + # Use the template method's body for each new method + def param_rule(self, p): + func(self, p) + + # Substitute in the params for the grammar rule and function name + param_rule.__doc__ = func.__doc__.replace('xxx', xxx).replace('yyy', yyy) + param_rule.__name__ = func.__name__.replace('xxx', xxx) + + # Attach the new method to the class + setattr(cls, param_rule.__name__, param_rule) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pycparser/yacctab.py b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/yacctab.py new file mode 100644 index 0000000000000000000000000000000000000000..0622c366021b0ce7d514b24772aec9fc9082fa7e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pycparser/yacctab.py @@ -0,0 +1,366 @@ + +# yacctab.py +# This file is automatically generated. Do not edit. +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'translation_unit_or_emptyleftLORleftLANDleftORleftXORleftANDleftEQNEleftGTGELTLEleftRSHIFTLSHIFTleftPLUSMINUSleftTIMESDIVIDEMODAUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER OFFSETOF RESTRICT RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE WHILE __INT128 _BOOL _COMPLEX _NORETURN _THREAD_LOCAL _STATIC_ASSERT _ATOMIC _ALIGNOF _ALIGNAS ID TYPEID INT_CONST_DEC INT_CONST_OCT INT_CONST_HEX INT_CONST_BIN INT_CONST_CHAR FLOAT_CONST HEX_FLOAT_CONST CHAR_CONST WCHAR_CONST U8CHAR_CONST U16CHAR_CONST U32CHAR_CONST STRING_LITERAL WSTRING_LITERAL U8STRING_LITERAL U16STRING_LITERAL U32STRING_LITERAL PLUS MINUS TIMES DIVIDE MOD OR AND NOT XOR LSHIFT RSHIFT LOR LAND LNOT LT LE GT GE EQ NE EQUALS TIMESEQUAL DIVEQUAL MODEQUAL PLUSEQUAL MINUSEQUAL LSHIFTEQUAL RSHIFTEQUAL ANDEQUAL XOREQUAL OREQUAL PLUSPLUS MINUSMINUS ARROW CONDOP LPAREN RPAREN LBRACKET RBRACKET LBRACE RBRACE COMMA PERIOD SEMI COLON ELLIPSIS PPHASH PPPRAGMA PPPRAGMASTRabstract_declarator_opt : empty\n| abstract_declaratorassignment_expression_opt : empty\n| assignment_expressionblock_item_list_opt : empty\n| block_item_listdeclaration_list_opt : empty\n| declaration_listdeclaration_specifiers_no_type_opt : empty\n| declaration_specifiers_no_typedesignation_opt : empty\n| designationexpression_opt : empty\n| expressionid_init_declarator_list_opt : empty\n| id_init_declarator_listidentifier_list_opt : empty\n| identifier_listinit_declarator_list_opt : empty\n| init_declarator_listinitializer_list_opt : empty\n| initializer_listparameter_type_list_opt : empty\n| parameter_type_liststruct_declarator_list_opt : empty\n| struct_declarator_listtype_qualifier_list_opt : empty\n| type_qualifier_list direct_id_declarator : ID\n direct_id_declarator : LPAREN id_declarator RPAREN\n direct_id_declarator : direct_id_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_id_declarator : direct_id_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_id_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_id_declarator : direct_id_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_id_declarator : direct_id_declarator LPAREN parameter_type_list RPAREN\n | direct_id_declarator LPAREN identifier_list_opt RPAREN\n direct_typeid_declarator : TYPEID\n direct_typeid_declarator : LPAREN typeid_declarator RPAREN\n direct_typeid_declarator : direct_typeid_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_typeid_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LPAREN parameter_type_list RPAREN\n | direct_typeid_declarator LPAREN identifier_list_opt RPAREN\n direct_typeid_noparen_declarator : TYPEID\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_typeid_noparen_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LPAREN parameter_type_list RPAREN\n | direct_typeid_noparen_declarator LPAREN identifier_list_opt RPAREN\n id_declarator : direct_id_declarator\n id_declarator : pointer direct_id_declarator\n typeid_declarator : direct_typeid_declarator\n typeid_declarator : pointer direct_typeid_declarator\n typeid_noparen_declarator : direct_typeid_noparen_declarator\n typeid_noparen_declarator : pointer direct_typeid_noparen_declarator\n translation_unit_or_empty : translation_unit\n | empty\n translation_unit : external_declaration\n translation_unit : translation_unit external_declaration\n external_declaration : function_definition\n external_declaration : declaration\n external_declaration : pp_directive\n | pppragma_directive\n external_declaration : SEMI\n external_declaration : static_assert\n static_assert : _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN\n | _STATIC_ASSERT LPAREN constant_expression RPAREN\n pp_directive : PPHASH\n pppragma_directive : PPPRAGMA\n | PPPRAGMA PPPRAGMASTR\n function_definition : id_declarator declaration_list_opt compound_statement\n function_definition : declaration_specifiers id_declarator declaration_list_opt compound_statement\n statement : labeled_statement\n | expression_statement\n | compound_statement\n | selection_statement\n | iteration_statement\n | jump_statement\n | pppragma_directive\n | static_assert\n pragmacomp_or_statement : pppragma_directive statement\n | statement\n decl_body : declaration_specifiers init_declarator_list_opt\n | declaration_specifiers_no_type id_init_declarator_list_opt\n declaration : decl_body SEMI\n declaration_list : declaration\n | declaration_list declaration\n declaration_specifiers_no_type : type_qualifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : storage_class_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : function_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : atomic_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : alignment_specifier declaration_specifiers_no_type_opt\n declaration_specifiers : declaration_specifiers type_qualifier\n declaration_specifiers : declaration_specifiers storage_class_specifier\n declaration_specifiers : declaration_specifiers function_specifier\n declaration_specifiers : declaration_specifiers type_specifier_no_typeid\n declaration_specifiers : type_specifier\n declaration_specifiers : declaration_specifiers_no_type type_specifier\n declaration_specifiers : declaration_specifiers alignment_specifier\n storage_class_specifier : AUTO\n | REGISTER\n | STATIC\n | EXTERN\n | TYPEDEF\n | _THREAD_LOCAL\n function_specifier : INLINE\n | _NORETURN\n type_specifier_no_typeid : VOID\n | _BOOL\n | CHAR\n | SHORT\n | INT\n | LONG\n | FLOAT\n | DOUBLE\n | _COMPLEX\n | SIGNED\n | UNSIGNED\n | __INT128\n type_specifier : typedef_name\n | enum_specifier\n | struct_or_union_specifier\n | type_specifier_no_typeid\n | atomic_specifier\n atomic_specifier : _ATOMIC LPAREN type_name RPAREN\n type_qualifier : CONST\n | RESTRICT\n | VOLATILE\n | _ATOMIC\n init_declarator_list : init_declarator\n | init_declarator_list COMMA init_declarator\n init_declarator : declarator\n | declarator EQUALS initializer\n id_init_declarator_list : id_init_declarator\n | id_init_declarator_list COMMA init_declarator\n id_init_declarator : id_declarator\n | id_declarator EQUALS initializer\n specifier_qualifier_list : specifier_qualifier_list type_specifier_no_typeid\n specifier_qualifier_list : specifier_qualifier_list type_qualifier\n specifier_qualifier_list : type_specifier\n specifier_qualifier_list : type_qualifier_list type_specifier\n specifier_qualifier_list : alignment_specifier\n specifier_qualifier_list : specifier_qualifier_list alignment_specifier\n struct_or_union_specifier : struct_or_union ID\n | struct_or_union TYPEID\n struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close\n | struct_or_union brace_open brace_close\n struct_or_union_specifier : struct_or_union ID brace_open struct_declaration_list brace_close\n | struct_or_union ID brace_open brace_close\n | struct_or_union TYPEID brace_open struct_declaration_list brace_close\n | struct_or_union TYPEID brace_open brace_close\n struct_or_union : STRUCT\n | UNION\n struct_declaration_list : struct_declaration\n | struct_declaration_list struct_declaration\n struct_declaration : specifier_qualifier_list struct_declarator_list_opt SEMI\n struct_declaration : SEMI\n struct_declaration : pppragma_directive\n struct_declarator_list : struct_declarator\n | struct_declarator_list COMMA struct_declarator\n struct_declarator : declarator\n struct_declarator : declarator COLON constant_expression\n | COLON constant_expression\n enum_specifier : ENUM ID\n | ENUM TYPEID\n enum_specifier : ENUM brace_open enumerator_list brace_close\n enum_specifier : ENUM ID brace_open enumerator_list brace_close\n | ENUM TYPEID brace_open enumerator_list brace_close\n enumerator_list : enumerator\n | enumerator_list COMMA\n | enumerator_list COMMA enumerator\n alignment_specifier : _ALIGNAS LPAREN type_name RPAREN\n | _ALIGNAS LPAREN constant_expression RPAREN\n enumerator : ID\n | ID EQUALS constant_expression\n declarator : id_declarator\n | typeid_declarator\n pointer : TIMES type_qualifier_list_opt\n | TIMES type_qualifier_list_opt pointer\n type_qualifier_list : type_qualifier\n | type_qualifier_list type_qualifier\n parameter_type_list : parameter_list\n | parameter_list COMMA ELLIPSIS\n parameter_list : parameter_declaration\n | parameter_list COMMA parameter_declaration\n parameter_declaration : declaration_specifiers id_declarator\n | declaration_specifiers typeid_noparen_declarator\n parameter_declaration : declaration_specifiers abstract_declarator_opt\n identifier_list : identifier\n | identifier_list COMMA identifier\n initializer : assignment_expression\n initializer : brace_open initializer_list_opt brace_close\n | brace_open initializer_list COMMA brace_close\n initializer_list : designation_opt initializer\n | initializer_list COMMA designation_opt initializer\n designation : designator_list EQUALS\n designator_list : designator\n | designator_list designator\n designator : LBRACKET constant_expression RBRACKET\n | PERIOD identifier\n type_name : specifier_qualifier_list abstract_declarator_opt\n abstract_declarator : pointer\n abstract_declarator : pointer direct_abstract_declarator\n abstract_declarator : direct_abstract_declarator\n direct_abstract_declarator : LPAREN abstract_declarator RPAREN direct_abstract_declarator : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET\n direct_abstract_declarator : LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_abstract_declarator : direct_abstract_declarator LBRACKET TIMES RBRACKET\n direct_abstract_declarator : LBRACKET TIMES RBRACKET\n direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN\n direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN\n block_item : declaration\n | statement\n block_item_list : block_item\n | block_item_list block_item\n compound_statement : brace_open block_item_list_opt brace_close labeled_statement : ID COLON pragmacomp_or_statement labeled_statement : CASE constant_expression COLON pragmacomp_or_statement labeled_statement : DEFAULT COLON pragmacomp_or_statement selection_statement : IF LPAREN expression RPAREN pragmacomp_or_statement selection_statement : IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement selection_statement : SWITCH LPAREN expression RPAREN pragmacomp_or_statement iteration_statement : WHILE LPAREN expression RPAREN pragmacomp_or_statement iteration_statement : DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement jump_statement : GOTO ID SEMI jump_statement : BREAK SEMI jump_statement : CONTINUE SEMI jump_statement : RETURN expression SEMI\n | RETURN SEMI\n expression_statement : expression_opt SEMI expression : assignment_expression\n | expression COMMA assignment_expression\n assignment_expression : LPAREN compound_statement RPAREN typedef_name : TYPEID assignment_expression : conditional_expression\n | unary_expression assignment_operator assignment_expression\n assignment_operator : EQUALS\n | XOREQUAL\n | TIMESEQUAL\n | DIVEQUAL\n | MODEQUAL\n | PLUSEQUAL\n | MINUSEQUAL\n | LSHIFTEQUAL\n | RSHIFTEQUAL\n | ANDEQUAL\n | OREQUAL\n constant_expression : conditional_expression conditional_expression : binary_expression\n | binary_expression CONDOP expression COLON conditional_expression\n binary_expression : cast_expression\n | binary_expression TIMES binary_expression\n | binary_expression DIVIDE binary_expression\n | binary_expression MOD binary_expression\n | binary_expression PLUS binary_expression\n | binary_expression MINUS binary_expression\n | binary_expression RSHIFT binary_expression\n | binary_expression LSHIFT binary_expression\n | binary_expression LT binary_expression\n | binary_expression LE binary_expression\n | binary_expression GE binary_expression\n | binary_expression GT binary_expression\n | binary_expression EQ binary_expression\n | binary_expression NE binary_expression\n | binary_expression AND binary_expression\n | binary_expression OR binary_expression\n | binary_expression XOR binary_expression\n | binary_expression LAND binary_expression\n | binary_expression LOR binary_expression\n cast_expression : unary_expression cast_expression : LPAREN type_name RPAREN cast_expression unary_expression : postfix_expression unary_expression : PLUSPLUS unary_expression\n | MINUSMINUS unary_expression\n | unary_operator cast_expression\n unary_expression : SIZEOF unary_expression\n | SIZEOF LPAREN type_name RPAREN\n | _ALIGNOF LPAREN type_name RPAREN\n unary_operator : AND\n | TIMES\n | PLUS\n | MINUS\n | NOT\n | LNOT\n postfix_expression : primary_expression postfix_expression : postfix_expression LBRACKET expression RBRACKET postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN\n | postfix_expression LPAREN RPAREN\n postfix_expression : postfix_expression PERIOD ID\n | postfix_expression PERIOD TYPEID\n | postfix_expression ARROW ID\n | postfix_expression ARROW TYPEID\n postfix_expression : postfix_expression PLUSPLUS\n | postfix_expression MINUSMINUS\n postfix_expression : LPAREN type_name RPAREN brace_open initializer_list brace_close\n | LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close\n primary_expression : identifier primary_expression : constant primary_expression : unified_string_literal\n | unified_wstring_literal\n primary_expression : LPAREN expression RPAREN primary_expression : OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN\n offsetof_member_designator : identifier\n | offsetof_member_designator PERIOD identifier\n | offsetof_member_designator LBRACKET expression RBRACKET\n argument_expression_list : assignment_expression\n | argument_expression_list COMMA assignment_expression\n identifier : ID constant : INT_CONST_DEC\n | INT_CONST_OCT\n | INT_CONST_HEX\n | INT_CONST_BIN\n | INT_CONST_CHAR\n constant : FLOAT_CONST\n | HEX_FLOAT_CONST\n constant : CHAR_CONST\n | WCHAR_CONST\n | U8CHAR_CONST\n | U16CHAR_CONST\n | U32CHAR_CONST\n unified_string_literal : STRING_LITERAL\n | unified_string_literal STRING_LITERAL\n unified_wstring_literal : WSTRING_LITERAL\n | U8STRING_LITERAL\n | U16STRING_LITERAL\n | U32STRING_LITERAL\n | unified_wstring_literal WSTRING_LITERAL\n | unified_wstring_literal U8STRING_LITERAL\n | unified_wstring_literal U16STRING_LITERAL\n | unified_wstring_literal U32STRING_LITERAL\n brace_open : LBRACE\n brace_close : RBRACE\n empty : ' + +_lr_action_items = {'INT_CONST_CHAR':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,132,-335,-28,-182,-27,132,-337,-87,-72,-337,132,-286,-285,132,132,-283,-287,-288,132,-284,132,132,132,-336,-183,132,132,-28,-337,132,-28,-337,-337,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,-337,-76,-79,-82,-75,132,-77,132,132,-81,-215,-214,-80,-216,132,-78,132,132,-69,-284,132,132,-284,132,132,-244,-247,-245,-241,-242,-246,-248,132,-250,-251,-243,-249,-12,132,132,-11,132,132,132,132,-234,-233,132,-231,132,132,-217,132,-230,132,-84,-218,132,132,132,-337,-337,-198,132,132,132,-337,-284,-229,-232,132,-221,132,-83,-219,-68,132,-28,-337,132,-11,132,132,-220,132,132,132,-284,132,132,132,-337,132,-225,-224,-222,-84,132,132,132,-226,-223,132,-228,-227,]),'VOID':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[6,-337,-113,-128,6,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,6,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,6,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,6,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,6,-131,-95,-101,-97,6,-53,-126,6,-88,6,6,-93,6,-147,-335,-146,6,-167,-166,-182,-100,-126,6,-87,-90,-94,-92,-61,-72,6,-144,-142,6,6,6,-73,6,-89,6,6,6,-149,-159,-160,-156,-336,6,-183,-30,6,6,-74,6,6,6,6,-174,-175,6,-143,-140,6,-141,-145,-76,-79,-82,-75,-77,6,-81,-215,-214,-80,-216,-78,-127,6,-153,6,-151,-148,-157,-168,-69,-36,-35,6,6,6,-234,-233,6,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,6,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LBRACKET':([2,3,5,6,7,10,11,12,13,18,20,22,23,26,27,30,33,34,35,36,39,42,43,44,46,48,49,50,54,56,58,60,62,68,71,73,76,77,80,81,82,86,96,97,98,100,101,103,104,105,106,109,111,127,132,133,134,136,138,139,140,141,142,143,145,147,148,152,153,154,156,160,161,163,164,166,167,168,169,176,177,187,191,198,199,200,211,216,227,230,235,236,237,238,240,241,261,263,269,275,276,278,279,280,283,310,312,314,316,317,328,340,341,342,344,345,347,355,356,371,376,402,403,404,405,407,411,414,442,443,448,449,453,454,457,458,464,465,470,472,474,482,483,488,489,490,492,511,512,518,519,520,526,527,529,530,531,532,544,545,547,550,551,559,560,563,565,570,571,572,],[-113,-128,-124,-110,-106,-104,-107,-125,-105,-99,-109,-120,-115,-102,-126,-108,-238,-111,-337,-122,-129,-29,-121,-116,-112,117,-123,-117,-119,-114,-130,-118,-103,-96,-98,128,-131,-37,-95,-101,-97,117,-147,-335,-146,-167,-166,-28,-180,-182,-27,-100,-126,128,-317,-321,-318,-303,-324,-330,-313,-319,-144,-301,-314,-142,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,265,-323,-312,282,-149,-336,-183,-181,-30,282,-38,373,-326,-334,-332,-331,-333,-174,-175,-298,-297,-143,-140,282,282,-141,-145,421,-312,-127,-153,-151,-148,-168,-36,-35,282,282,459,-45,-44,-43,-199,373,-296,-295,-294,-293,-292,-305,421,-152,-150,-170,-169,-31,-34,282,459,-39,-42,-202,373,-200,-290,-291,373,-213,-207,-211,-33,-32,-41,-40,-201,549,-307,-209,-208,-210,-212,-51,-50,-306,373,-299,-46,-49,-308,-300,-48,-47,-309,]),'WCHAR_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,133,-335,-28,-182,-27,133,-337,-87,-72,-337,133,-286,-285,133,133,-283,-287,-288,133,-284,133,133,133,-336,-183,133,133,-28,-337,133,-28,-337,-337,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,-337,-76,-79,-82,-75,133,-77,133,133,-81,-215,-214,-80,-216,133,-78,133,133,-69,-284,133,133,-284,133,133,-244,-247,-245,-241,-242,-246,-248,133,-250,-251,-243,-249,-12,133,133,-11,133,133,133,133,-234,-233,133,-231,133,133,-217,133,-230,133,-84,-218,133,133,133,-337,-337,-198,133,133,133,-337,-284,-229,-232,133,-221,133,-83,-219,-68,133,-28,-337,133,-11,133,133,-220,133,133,133,-284,133,133,133,-337,133,-225,-224,-222,-84,133,133,133,-226,-223,133,-228,-227,]),'FLOAT_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,134,-335,-28,-182,-27,134,-337,-87,-72,-337,134,-286,-285,134,134,-283,-287,-288,134,-284,134,134,134,-336,-183,134,134,-28,-337,134,-28,-337,-337,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,-337,-76,-79,-82,-75,134,-77,134,134,-81,-215,-214,-80,-216,134,-78,134,134,-69,-284,134,134,-284,134,134,-244,-247,-245,-241,-242,-246,-248,134,-250,-251,-243,-249,-12,134,134,-11,134,134,134,134,-234,-233,134,-231,134,134,-217,134,-230,134,-84,-218,134,134,134,-337,-337,-198,134,134,134,-337,-284,-229,-232,134,-221,134,-83,-219,-68,134,-28,-337,134,-11,134,134,-220,134,134,134,-284,134,134,134,-337,134,-225,-224,-222,-84,134,134,134,-226,-223,134,-228,-227,]),'MINUS':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,132,133,134,135,136,137,138,139,140,141,143,144,145,146,148,149,150,151,152,153,154,156,158,160,161,162,163,164,165,166,167,168,169,171,173,174,175,176,181,191,198,201,204,205,206,218,219,220,224,227,229,230,231,232,233,234,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,268,273,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,478,480,481,482,483,484,487,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,135,-335,-28,-182,-27,135,-337,-87,-72,-337,135,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-301,-274,-314,135,-327,135,-283,-287,-325,-304,-322,-302,-255,-315,-289,245,-328,-316,-288,-329,-320,-276,-323,135,-284,135,135,-312,135,-336,-183,135,135,-28,-337,135,-28,-337,-274,-337,135,-326,135,-280,135,-277,-334,-332,-331,-333,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,-298,-297,135,135,-279,-278,-337,-76,-79,-82,-75,135,-77,135,135,-81,-215,-214,-80,-216,135,-78,-312,135,135,-69,-284,135,135,-284,135,135,-244,-247,-245,-241,-242,-246,-248,135,-250,-251,-243,-249,-12,135,135,-11,245,245,245,-260,245,245,245,-259,245,245,-257,-256,245,245,245,245,245,-258,-296,-295,-294,-293,-292,-305,135,135,135,135,-234,-233,135,-231,135,135,-217,135,-230,135,-84,-218,135,135,135,-337,-337,-198,135,-281,-282,135,-290,-291,135,-275,-337,-284,-229,-232,135,-221,135,-83,-219,-68,135,-28,-337,135,-11,135,135,-220,135,135,135,-284,135,135,-306,135,-337,-299,135,-225,-224,-222,-84,-300,135,135,135,-226,-223,135,-228,-227,]),'RPAREN':([2,3,5,6,7,10,11,12,13,18,20,22,23,26,27,30,33,34,35,36,39,42,43,44,46,48,49,50,54,56,58,60,62,68,71,73,76,77,80,81,82,86,96,98,100,101,103,104,105,106,107,109,111,118,125,127,129,132,133,134,136,138,139,140,141,142,143,144,145,147,148,152,153,154,156,157,158,159,160,161,162,163,164,166,167,168,169,176,177,178,183,187,191,198,199,200,203,207,208,209,210,211,212,213,215,216,221,222,224,225,230,232,234,235,236,237,238,240,241,261,263,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,283,294,312,314,316,317,328,340,341,342,343,344,345,346,347,348,355,356,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,408,409,411,414,415,416,417,418,422,433,439,442,443,448,449,452,453,454,457,458,460,461,462,463,464,465,468,476,478,480,482,483,486,487,489,490,492,495,501,503,507,511,512,516,517,518,519,524,525,526,527,529,530,531,532,544,545,547,551,553,556,559,560,563,565,566,567,570,571,572,573,],[-113,-128,-124,-110,-106,-104,-107,-125,-105,-99,-109,-120,-115,-102,-126,-108,-238,-111,-337,-122,-129,-29,-121,-116,-112,-52,-123,-117,-119,-114,-130,-118,-103,-96,-98,-54,-131,-37,-95,-101,-97,-53,-147,-146,-167,-166,-28,-180,-182,-27,200,-100,-126,-337,216,-55,-337,-317,-321,-318,-303,-324,-330,-313,-319,-144,-301,-274,-314,-142,-327,-325,-304,-322,-302,240,-255,241,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-337,-252,312,-149,-336,-183,-181,-30,332,340,-17,341,-186,-337,-18,-184,-191,-38,355,356,-274,-239,-326,-280,-277,-334,-332,-331,-333,-174,-175,-298,-297,407,-279,-143,411,413,-235,-278,-203,-140,-204,-1,-337,-141,-145,-2,-206,-14,-127,-153,-151,-148,-168,-36,-35,-337,-190,-204,-56,-188,-45,-189,-44,-43,476,477,478,479,480,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-310,483,-305,-205,-23,-24,489,490,-337,-13,-218,-152,-150,-170,-169,510,-31,-34,-204,-57,-337,-192,-185,-187,-39,-42,-240,-237,-281,-282,-290,-291,-236,-275,-213,-207,-211,532,535,537,539,-33,-32,544,545,-41,-40,-254,-311,547,-307,-209,-208,-210,-212,-51,-50,-306,-299,-337,568,-46,-49,-308,-300,-337,574,-48,-47,-309,577,]),'STRUCT':([0,1,3,7,10,11,13,14,16,17,19,20,21,25,26,27,29,30,38,39,40,42,45,47,48,52,53,55,58,59,61,62,63,64,65,66,67,75,85,86,87,90,91,93,94,95,97,99,105,118,119,120,121,122,123,124,129,172,174,180,181,182,184,185,186,188,189,190,191,198,200,214,223,229,231,233,239,240,241,267,278,284,285,286,289,291,298,300,301,302,303,305,308,312,313,315,318,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,446,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[24,-337,-128,-106,-104,-107,-105,-64,-60,-67,-66,-109,24,-65,-102,-337,-131,-108,-63,-129,24,-29,-62,-70,-52,-337,-337,-337,-130,24,-71,-103,-337,-9,-131,-91,-10,24,24,-53,-337,-88,24,24,-93,24,-335,24,-182,24,-87,-90,-94,-92,-61,-72,24,24,24,-73,24,-89,24,24,24,-159,-160,-156,-336,-183,-30,24,-74,24,24,24,24,-174,-175,24,24,-76,-79,-82,-75,-77,24,-81,-215,-214,-80,-216,-78,-127,24,24,-157,-69,-36,-35,24,24,24,-234,-233,24,-231,-217,-230,-81,-84,-218,-158,-31,-34,24,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LONG':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[23,-337,-113,-128,23,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,23,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,23,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,23,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,23,-131,-95,-101,-97,23,-53,-126,23,-88,23,23,-93,23,-147,-335,-146,23,-167,-166,-182,-100,-126,23,-87,-90,-94,-92,-61,-72,23,-144,-142,23,23,23,-73,23,-89,23,23,23,-149,-159,-160,-156,-336,23,-183,-30,23,23,-74,23,23,23,23,-174,-175,23,-143,-140,23,-141,-145,-76,-79,-82,-75,-77,23,-81,-215,-214,-80,-216,-78,-127,23,-153,23,-151,-148,-157,-168,-69,-36,-35,23,23,23,-234,-233,23,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,23,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'PLUS':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,132,133,134,135,136,137,138,139,140,141,143,144,145,146,148,149,150,151,152,153,154,156,158,160,161,162,163,164,165,166,167,168,169,171,173,174,175,176,181,191,198,201,204,205,206,218,219,220,224,227,229,230,231,232,233,234,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,268,273,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,478,480,481,482,483,484,487,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,137,-335,-28,-182,-27,137,-337,-87,-72,-337,137,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-301,-274,-314,137,-327,137,-283,-287,-325,-304,-322,-302,-255,-315,-289,249,-328,-316,-288,-329,-320,-276,-323,137,-284,137,137,-312,137,-336,-183,137,137,-28,-337,137,-28,-337,-274,-337,137,-326,137,-280,137,-277,-334,-332,-331,-333,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,-298,-297,137,137,-279,-278,-337,-76,-79,-82,-75,137,-77,137,137,-81,-215,-214,-80,-216,137,-78,-312,137,137,-69,-284,137,137,-284,137,137,-244,-247,-245,-241,-242,-246,-248,137,-250,-251,-243,-249,-12,137,137,-11,249,249,249,-260,249,249,249,-259,249,249,-257,-256,249,249,249,249,249,-258,-296,-295,-294,-293,-292,-305,137,137,137,137,-234,-233,137,-231,137,137,-217,137,-230,137,-84,-218,137,137,137,-337,-337,-198,137,-281,-282,137,-290,-291,137,-275,-337,-284,-229,-232,137,-221,137,-83,-219,-68,137,-28,-337,137,-11,137,137,-220,137,137,137,-284,137,137,-306,137,-337,-299,137,-225,-224,-222,-84,-300,137,137,137,-226,-223,137,-228,-227,]),'ELLIPSIS':([350,],[462,]),'U32STRING_LITERAL':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,139,146,148,149,150,151,153,163,165,166,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,139,-335,-28,-182,-27,139,-337,-87,-72,-337,139,-286,-285,-330,139,-327,139,-283,-287,235,-328,-288,-329,139,-284,139,139,139,-336,-183,139,139,-28,-337,139,-28,-337,-337,139,139,139,-334,-332,-331,-333,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,-337,-76,-79,-82,-75,139,-77,139,139,-81,-215,-214,-80,-216,139,-78,139,139,-69,-284,139,139,-284,139,139,-244,-247,-245,-241,-242,-246,-248,139,-250,-251,-243,-249,-12,139,139,-11,139,139,139,139,-234,-233,139,-231,139,139,-217,139,-230,139,-84,-218,139,139,139,-337,-337,-198,139,139,139,-337,-284,-229,-232,139,-221,139,-83,-219,-68,139,-28,-337,139,-11,139,139,-220,139,139,139,-284,139,139,139,-337,139,-225,-224,-222,-84,139,139,139,-226,-223,139,-228,-227,]),'GT':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,250,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,250,-262,-260,-264,250,-263,-259,-266,250,-257,-256,-265,250,250,250,250,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'GOTO':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,287,-336,-76,-79,-82,-75,-77,287,-81,-215,-214,-80,-216,287,-78,-69,-234,-233,-231,287,-217,-230,287,-84,-218,287,-229,-232,-221,287,-83,-219,-68,287,-220,287,287,-225,-224,-222,-84,287,287,-226,-223,287,-228,-227,]),'ENUM':([0,1,3,7,10,11,13,14,16,17,19,20,21,25,26,27,29,30,38,39,40,42,45,47,48,52,53,55,58,59,61,62,63,64,65,66,67,75,85,86,87,90,91,93,94,95,97,99,105,118,119,120,121,122,123,124,129,172,174,180,181,182,184,185,186,188,189,190,191,198,200,214,223,229,231,233,239,240,241,267,278,284,285,286,289,291,298,300,301,302,303,305,308,312,313,315,318,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,446,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[32,-337,-128,-106,-104,-107,-105,-64,-60,-67,-66,-109,32,-65,-102,-337,-131,-108,-63,-129,32,-29,-62,-70,-52,-337,-337,-337,-130,32,-71,-103,-337,-9,-131,-91,-10,32,32,-53,-337,-88,32,32,-93,32,-335,32,-182,32,-87,-90,-94,-92,-61,-72,32,32,32,-73,32,-89,32,32,32,-159,-160,-156,-336,-183,-30,32,-74,32,32,32,32,-174,-175,32,32,-76,-79,-82,-75,-77,32,-81,-215,-214,-80,-216,-78,-127,32,32,-157,-69,-36,-35,32,32,32,-234,-233,32,-231,-217,-230,-81,-84,-218,-158,-31,-34,32,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'PERIOD':([97,132,133,134,136,138,139,140,141,143,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,227,230,235,236,237,238,261,263,310,371,376,402,403,404,405,407,411,470,472,474,482,483,488,520,526,527,547,550,551,563,565,572,],[-335,-317,-321,-318,-303,-324,-330,-313,-319,-301,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,264,-323,-312,-336,372,-326,-334,-332,-331,-333,-298,-297,-312,-199,372,-296,-295,-294,-293,-292,-305,-202,372,-200,-290,-291,372,-201,548,-307,-306,372,-299,-308,-300,-309,]),'GE':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,254,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,254,-262,-260,-264,254,-263,-259,-266,254,-257,-256,-265,254,254,254,254,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'INT_CONST_DEC':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,140,-335,-28,-182,-27,140,-337,-87,-72,-337,140,-286,-285,140,140,-283,-287,-288,140,-284,140,140,140,-336,-183,140,140,-28,-337,140,-28,-337,-337,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,-337,-76,-79,-82,-75,140,-77,140,140,-81,-215,-214,-80,-216,140,-78,140,140,-69,-284,140,140,-284,140,140,-244,-247,-245,-241,-242,-246,-248,140,-250,-251,-243,-249,-12,140,140,-11,140,140,140,140,-234,-233,140,-231,140,140,-217,140,-230,140,-84,-218,140,140,140,-337,-337,-198,140,140,140,-337,-284,-229,-232,140,-221,140,-83,-219,-68,140,-28,-337,140,-11,140,140,-220,140,140,140,-284,140,140,140,-337,140,-225,-224,-222,-84,140,140,140,-226,-223,140,-228,-227,]),'ARROW':([132,133,134,136,138,139,140,141,143,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,230,235,236,237,238,261,263,310,402,403,404,405,407,411,482,483,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,262,-323,-312,-336,-326,-334,-332,-331,-333,-298,-297,-312,-296,-295,-294,-293,-292,-305,-290,-291,-306,-299,-300,]),'_STATIC_ASSERT':([0,14,16,17,19,25,38,45,47,59,61,97,119,123,124,180,181,191,223,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[41,-64,-60,-67,-66,-65,-63,-62,-70,41,-71,-335,-87,-61,-72,-73,41,-336,-74,-76,-79,-82,-75,-77,41,-81,-215,-214,-80,-216,41,-78,-69,-234,-233,-231,41,-217,-230,41,-84,-218,41,-229,-232,-221,41,-83,-219,-68,41,-220,41,41,-225,-224,-222,-84,41,41,-226,-223,41,-228,-227,]),'CHAR':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[46,-337,-113,-128,46,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,46,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,46,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,46,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,46,-131,-95,-101,-97,46,-53,-126,46,-88,46,46,-93,46,-147,-335,-146,46,-167,-166,-182,-100,-126,46,-87,-90,-94,-92,-61,-72,46,-144,-142,46,46,46,-73,46,-89,46,46,46,-149,-159,-160,-156,-336,46,-183,-30,46,46,-74,46,46,46,46,-174,-175,46,-143,-140,46,-141,-145,-76,-79,-82,-75,-77,46,-81,-215,-214,-80,-216,-78,-127,46,-153,46,-151,-148,-157,-168,-69,-36,-35,46,46,46,-234,-233,46,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,46,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'HEX_FLOAT_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,141,-335,-28,-182,-27,141,-337,-87,-72,-337,141,-286,-285,141,141,-283,-287,-288,141,-284,141,141,141,-336,-183,141,141,-28,-337,141,-28,-337,-337,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,-337,-76,-79,-82,-75,141,-77,141,141,-81,-215,-214,-80,-216,141,-78,141,141,-69,-284,141,141,-284,141,141,-244,-247,-245,-241,-242,-246,-248,141,-250,-251,-243,-249,-12,141,141,-11,141,141,141,141,-234,-233,141,-231,141,141,-217,141,-230,141,-84,-218,141,141,141,-337,-337,-198,141,141,141,-337,-284,-229,-232,141,-221,141,-83,-219,-68,141,-28,-337,141,-11,141,141,-220,141,141,141,-284,141,141,141,-337,141,-225,-224,-222,-84,141,141,141,-226,-223,141,-228,-227,]),'DOUBLE':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[50,-337,-113,-128,50,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,50,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,50,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,50,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,50,-131,-95,-101,-97,50,-53,-126,50,-88,50,50,-93,50,-147,-335,-146,50,-167,-166,-182,-100,-126,50,-87,-90,-94,-92,-61,-72,50,-144,-142,50,50,50,-73,50,-89,50,50,50,-149,-159,-160,-156,-336,50,-183,-30,50,50,-74,50,50,50,50,-174,-175,50,-143,-140,50,-141,-145,-76,-79,-82,-75,-77,50,-81,-215,-214,-80,-216,-78,-127,50,-153,50,-151,-148,-157,-168,-69,-36,-35,50,50,50,-234,-233,50,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,50,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'MINUSEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,358,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'INT_CONST_OCT':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,145,-335,-28,-182,-27,145,-337,-87,-72,-337,145,-286,-285,145,145,-283,-287,-288,145,-284,145,145,145,-336,-183,145,145,-28,-337,145,-28,-337,-337,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,-337,-76,-79,-82,-75,145,-77,145,145,-81,-215,-214,-80,-216,145,-78,145,145,-69,-284,145,145,-284,145,145,-244,-247,-245,-241,-242,-246,-248,145,-250,-251,-243,-249,-12,145,145,-11,145,145,145,145,-234,-233,145,-231,145,145,-217,145,-230,145,-84,-218,145,145,145,-337,-337,-198,145,145,145,-337,-284,-229,-232,145,-221,145,-83,-219,-68,145,-28,-337,145,-11,145,145,-220,145,145,145,-284,145,145,145,-337,145,-225,-224,-222,-84,145,145,145,-226,-223,145,-228,-227,]),'TIMESEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,367,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'OR':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,259,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,259,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,259,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'SHORT':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[2,-337,-113,-128,2,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,2,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,2,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,2,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,2,-131,-95,-101,-97,2,-53,-126,2,-88,2,2,-93,2,-147,-335,-146,2,-167,-166,-182,-100,-126,2,-87,-90,-94,-92,-61,-72,2,-144,-142,2,2,2,-73,2,-89,2,2,2,-149,-159,-160,-156,-336,2,-183,-30,2,2,-74,2,2,2,2,-174,-175,2,-143,-140,2,-141,-145,-76,-79,-82,-75,-77,2,-81,-215,-214,-80,-216,-78,-127,2,-153,2,-151,-148,-157,-168,-69,-36,-35,2,2,2,-234,-233,2,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,2,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'RETURN':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,290,-336,-76,-79,-82,-75,-77,290,-81,-215,-214,-80,-216,290,-78,-69,-234,-233,-231,290,-217,-230,290,-84,-218,290,-229,-232,-221,290,-83,-219,-68,290,-220,290,290,-225,-224,-222,-84,290,290,-226,-223,290,-228,-227,]),'RSHIFTEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,368,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'_ALIGNAS':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,85,86,87,89,90,93,95,96,97,98,99,100,101,109,111,118,119,123,124,129,142,147,174,177,180,181,182,184,185,186,187,188,189,190,191,192,200,211,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[8,8,-113,-128,8,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,8,-120,-115,-65,-102,8,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,8,8,-119,8,-114,-130,8,-118,-71,-103,8,-131,-96,-98,8,-131,-95,-101,-97,8,-53,8,8,-88,8,8,-147,-335,-146,8,-167,-166,-100,-126,8,-87,-61,-72,8,-144,-142,8,8,-73,8,-89,8,8,8,-149,-159,-160,-156,-336,8,-30,8,-74,8,8,8,8,-174,-175,8,-143,-140,8,-141,-145,-76,-79,-82,-75,-77,8,-81,-215,-214,-80,-216,-78,-127,8,-153,8,-151,-148,-157,-168,-69,-36,-35,8,8,8,-234,-233,8,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,8,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'RESTRICT':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,35,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,85,86,87,89,90,93,95,96,97,98,99,100,101,103,105,109,111,117,118,119,123,124,128,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,205,206,211,219,220,223,229,231,233,239,240,241,267,269,275,278,279,280,282,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,459,460,496,497,500,505,506,510,511,512,514,515,536,554,555,557,558,575,576,578,579,],[39,39,-113,-128,39,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,39,-120,-115,-65,-102,39,-131,-108,-238,-111,39,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,39,39,-119,39,-114,-130,39,-118,-71,-103,39,-131,-96,-98,39,-131,-95,-101,-97,39,-53,39,39,-88,39,39,-147,-335,-146,39,-167,-166,39,-182,-100,-126,39,39,-87,-61,-72,39,39,-144,-142,39,39,39,-73,39,-89,39,39,39,-149,-159,-160,-156,-336,39,-183,-30,39,39,39,39,39,-74,39,39,39,39,-174,-175,39,-143,-140,39,-141,-145,39,-76,-79,-82,-75,-77,39,-81,-215,-214,-80,-216,-78,-127,39,-153,39,-151,-148,-157,-168,-69,-36,-35,39,39,39,-234,-233,39,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,39,39,-229,-232,-221,-83,-219,-68,-33,-32,39,39,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'STATIC':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,105,109,111,117,118,119,123,124,128,129,180,181,182,187,191,198,200,205,211,219,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,459,460,496,497,500,505,506,510,511,512,514,536,554,555,557,558,575,576,578,579,],[10,10,-113,-128,10,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,10,-120,-115,-65,-102,10,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,10,10,-119,10,-114,-130,10,-118,-71,-103,10,-131,-96,-98,10,-131,-95,-101,-97,-53,10,10,-88,10,-147,-335,-146,-167,-166,-182,-100,-126,206,10,-87,-61,-72,220,10,-73,10,-89,-149,-336,-183,-30,338,10,353,-74,-174,-175,10,-76,-79,-82,-75,-77,10,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,10,10,10,-234,-233,10,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,515,10,-229,-232,-221,-83,-219,-68,-33,-32,542,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'SIZEOF':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,146,-335,-28,-182,-27,146,-337,-87,-72,-337,146,-286,-285,146,146,-283,-287,-288,146,-284,146,146,146,-336,-183,146,146,-28,-337,146,-28,-337,-337,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,-337,-76,-79,-82,-75,146,-77,146,146,-81,-215,-214,-80,-216,146,-78,146,146,-69,-284,146,146,-284,146,146,-244,-247,-245,-241,-242,-246,-248,146,-250,-251,-243,-249,-12,146,146,-11,146,146,146,146,-234,-233,146,-231,146,146,-217,146,-230,146,-84,-218,146,146,146,-337,-337,-198,146,146,146,-337,-284,-229,-232,146,-221,146,-83,-219,-68,146,-28,-337,146,-11,146,146,-220,146,146,146,-284,146,146,146,-337,146,-225,-224,-222,-84,146,146,146,-226,-223,146,-228,-227,]),'UNSIGNED':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[22,-337,-113,-128,22,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,22,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,22,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,22,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,22,-131,-95,-101,-97,22,-53,-126,22,-88,22,22,-93,22,-147,-335,-146,22,-167,-166,-182,-100,-126,22,-87,-90,-94,-92,-61,-72,22,-144,-142,22,22,22,-73,22,-89,22,22,22,-149,-159,-160,-156,-336,22,-183,-30,22,22,-74,22,22,22,22,-174,-175,22,-143,-140,22,-141,-145,-76,-79,-82,-75,-77,22,-81,-215,-214,-80,-216,-78,-127,22,-153,22,-151,-148,-157,-168,-69,-36,-35,22,22,22,-234,-233,22,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,22,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'UNION':([0,1,3,7,10,11,13,14,16,17,19,20,21,25,26,27,29,30,38,39,40,42,45,47,48,52,53,55,58,59,61,62,63,64,65,66,67,75,85,86,87,90,91,93,94,95,97,99,105,118,119,120,121,122,123,124,129,172,174,180,181,182,184,185,186,188,189,190,191,198,200,214,223,229,231,233,239,240,241,267,278,284,285,286,289,291,298,300,301,302,303,305,308,312,313,315,318,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,446,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[28,-337,-128,-106,-104,-107,-105,-64,-60,-67,-66,-109,28,-65,-102,-337,-131,-108,-63,-129,28,-29,-62,-70,-52,-337,-337,-337,-130,28,-71,-103,-337,-9,-131,-91,-10,28,28,-53,-337,-88,28,28,-93,28,-335,28,-182,28,-87,-90,-94,-92,-61,-72,28,28,28,-73,28,-89,28,28,28,-159,-160,-156,-336,-183,-30,28,-74,28,28,28,28,-174,-175,28,28,-76,-79,-82,-75,-77,28,-81,-215,-214,-80,-216,-78,-127,28,28,-157,-69,-36,-35,28,28,28,-234,-233,28,-231,-217,-230,-81,-84,-218,-158,-31,-34,28,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'COLON':([2,3,5,6,12,22,23,33,34,36,39,42,43,44,46,48,49,50,54,56,58,60,73,74,76,77,86,96,98,100,101,111,127,132,133,134,136,138,139,140,141,142,143,144,145,147,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,178,179,187,191,192,200,216,224,225,230,232,234,235,236,237,238,240,241,261,263,268,269,272,273,275,279,280,295,310,312,314,316,317,324,328,340,341,355,356,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,407,411,431,442,443,445,448,449,453,454,464,465,468,476,478,480,482,483,486,487,511,512,518,519,524,547,551,565,],[-113,-128,-124,-110,-125,-120,-115,-238,-111,-122,-129,-29,-121,-116,-112,-52,-123,-117,-119,-114,-130,-118,-54,-179,-131,-37,-53,-147,-146,-167,-166,-126,-55,-317,-321,-318,-303,-324,-330,-313,-319,-144,-301,-274,-314,-142,-327,-325,-304,-322,-302,-255,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-252,-178,-149,-336,319,-30,-38,-274,-239,-326,-280,-277,-334,-332,-331,-333,-174,-175,-298,-297,-279,-143,-235,-278,-140,-141,-145,429,440,-127,-153,-151,-148,447,-168,-36,-35,-44,-43,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,481,-270,-258,-296,-295,-294,-293,-292,-305,502,-152,-150,319,-170,-169,-31,-34,-39,-42,-240,-237,-281,-282,-290,-291,-236,-275,-33,-32,-41,-40,-254,-306,-299,-300,]),'$end':([0,9,14,16,17,19,25,38,45,47,57,59,61,119,123,124,180,191,223,332,439,510,],[-337,0,-64,-60,-67,-66,-65,-63,-62,-70,-59,-58,-71,-87,-61,-72,-73,-336,-74,-69,-218,-68,]),'WSTRING_LITERAL':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,139,146,148,149,150,151,153,163,165,166,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,148,-335,-28,-182,-27,148,-337,-87,-72,-337,148,-286,-285,-330,148,-327,148,-283,-287,237,-328,-288,-329,148,-284,148,148,148,-336,-183,148,148,-28,-337,148,-28,-337,-337,148,148,148,-334,-332,-331,-333,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,-337,-76,-79,-82,-75,148,-77,148,148,-81,-215,-214,-80,-216,148,-78,148,148,-69,-284,148,148,-284,148,148,-244,-247,-245,-241,-242,-246,-248,148,-250,-251,-243,-249,-12,148,148,-11,148,148,148,148,-234,-233,148,-231,148,148,-217,148,-230,148,-84,-218,148,148,148,-337,-337,-198,148,148,148,-337,-284,-229,-232,148,-221,148,-83,-219,-68,148,-28,-337,148,-11,148,148,-220,148,148,148,-284,148,148,148,-337,148,-225,-224,-222,-84,148,148,148,-226,-223,148,-228,-227,]),'DIVIDE':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,252,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,252,252,252,252,252,252,252,252,252,252,-257,-256,252,252,252,252,252,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'FOR':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,292,-336,-76,-79,-82,-75,-77,292,-81,-215,-214,-80,-216,292,-78,-69,-234,-233,-231,292,-217,-230,292,-84,-218,292,-229,-232,-221,292,-83,-219,-68,292,-220,292,292,-225,-224,-222,-84,292,292,-226,-223,292,-228,-227,]),'PLUSPLUS':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,132,133,134,135,136,137,138,139,140,141,143,145,146,148,149,150,151,152,153,154,156,160,161,163,164,165,166,167,168,169,171,173,174,175,176,181,191,198,201,204,205,206,218,219,220,227,229,230,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,482,483,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,149,-335,-28,-182,-27,149,-337,-87,-72,-337,149,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-301,-314,149,-327,149,-283,-287,-325,-304,-322,-302,-315,-289,-328,-316,-288,-329,-320,263,-323,149,-284,149,149,-312,149,-336,-183,149,149,-28,-337,149,-28,-337,-337,149,-326,149,149,-334,-332,-331,-333,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,-298,-297,149,149,-337,-76,-79,-82,-75,149,-77,149,149,-81,-215,-214,-80,-216,149,-78,-312,149,149,-69,-284,149,149,-284,149,149,-244,-247,-245,-241,-242,-246,-248,149,-250,-251,-243,-249,-12,149,149,-11,-296,-295,-294,-293,-292,-305,149,149,149,149,-234,-233,149,-231,149,149,-217,149,-230,149,-84,-218,149,149,149,-337,-337,-198,149,149,-290,-291,149,-337,-284,-229,-232,149,-221,149,-83,-219,-68,149,-28,-337,149,-11,149,149,-220,149,149,149,-284,149,149,-306,149,-337,-299,149,-225,-224,-222,-84,-300,149,149,149,-226,-223,149,-228,-227,]),'EQUALS':([42,48,73,74,75,77,78,86,110,127,132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,179,191,197,200,216,224,230,232,234,235,236,237,238,261,263,268,273,310,340,341,355,356,371,376,402,403,404,405,407,411,453,454,464,465,470,474,478,480,482,483,487,511,512,518,519,520,547,551,565,],[-29,-52,-54,-179,-178,-37,131,-53,201,-55,-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-178,-336,329,-30,-38,360,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-36,-35,-44,-43,-199,475,-296,-295,-294,-293,-292,-305,-31,-34,-39,-42,-202,-200,-281,-282,-290,-291,-275,-33,-32,-41,-40,-201,-306,-299,-300,]),'ELSE':([61,124,191,284,285,286,289,291,300,303,308,332,424,425,428,435,437,438,439,496,497,500,505,506,510,536,554,555,557,558,575,576,578,579,],[-71,-72,-336,-76,-79,-82,-75,-77,-81,-80,-78,-69,-234,-233,-231,-230,-81,-84,-218,-229,-232,-221,-83,-219,-68,-220,-225,-224,-222,569,-226,-223,-228,-227,]),'ANDEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,365,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'EQ':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,256,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,256,-262,-260,-264,-268,-263,-259,-266,256,-257,-256,-265,256,-267,256,256,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'AND':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,132,133,134,135,136,137,138,139,140,141,143,144,145,146,148,149,150,151,152,153,154,156,158,160,161,162,163,164,165,166,167,168,169,171,173,174,175,176,181,191,198,201,204,205,206,218,219,220,224,227,229,230,231,232,233,234,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,268,273,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,478,480,481,482,483,484,487,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,150,-335,-28,-182,-27,150,-337,-87,-72,-337,150,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-301,-274,-314,150,-327,150,-283,-287,-325,-304,-322,-302,-255,-315,-289,257,-328,-316,-288,-329,-320,-276,-323,150,-284,150,150,-312,150,-336,-183,150,150,-28,-337,150,-28,-337,-274,-337,150,-326,150,-280,150,-277,-334,-332,-331,-333,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,-298,-297,150,150,-279,-278,-337,-76,-79,-82,-75,150,-77,150,150,-81,-215,-214,-80,-216,150,-78,-312,150,150,-69,-284,150,150,-284,150,150,-244,-247,-245,-241,-242,-246,-248,150,-250,-251,-243,-249,-12,150,150,-11,-261,257,-262,-260,-264,-268,-263,-259,-266,257,-257,-256,-265,257,-267,-269,257,-258,-296,-295,-294,-293,-292,-305,150,150,150,150,-234,-233,150,-231,150,150,-217,150,-230,150,-84,-218,150,150,150,-337,-337,-198,150,-281,-282,150,-290,-291,150,-275,-337,-284,-229,-232,150,-221,150,-83,-219,-68,150,-28,-337,150,-11,150,150,-220,150,150,150,-284,150,150,-306,150,-337,-299,150,-225,-224,-222,-84,-300,150,150,150,-226,-223,150,-228,-227,]),'TYPEID':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,69,71,72,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,103,104,105,106,109,111,118,119,120,121,122,123,124,126,129,142,147,172,174,180,181,182,184,185,186,187,188,189,190,191,192,198,199,200,202,211,214,223,229,231,233,239,240,241,262,264,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,344,350,422,424,425,427,428,432,435,437,438,439,442,443,445,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[33,-337,-113,-128,77,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,33,-120,-115,-154,-65,-102,-126,-155,-131,-108,96,100,-238,-111,-337,-122,-63,-129,33,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,33,-118,-71,-103,-337,-9,-131,-91,-10,-96,77,-98,77,33,-131,-95,-101,-97,33,-53,-126,77,-88,33,33,-93,33,-147,-335,-146,33,-167,-166,-28,-180,-182,-27,-100,-126,33,-87,-90,-94,-92,-61,-72,77,33,-144,-142,33,33,-73,33,-89,33,33,33,-149,-159,-160,-156,-336,77,-183,-181,-30,77,347,33,-74,33,33,33,33,-174,-175,402,404,33,-143,-140,33,-141,-145,-76,-79,-82,-75,-77,33,-81,-215,-214,-80,-216,-78,-127,33,-153,33,-151,-148,-157,-168,-69,-36,-35,33,347,33,33,-234,-233,33,-231,-217,-230,-81,-84,-218,-152,-150,77,-158,-170,-169,-31,-34,33,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LBRACE':([21,24,28,31,32,42,48,61,75,86,88,90,92,93,96,97,98,100,101,119,124,130,131,181,182,191,200,201,227,229,284,285,286,289,291,298,300,301,302,303,305,307,308,332,340,341,369,375,377,413,424,425,428,429,432,435,437,438,439,440,453,454,472,475,477,478,479,488,496,497,500,502,505,506,510,511,512,521,522,535,536,537,539,550,554,555,557,558,569,574,575,576,577,578,579,],[-337,-154,-155,97,97,-29,-52,-71,-337,-53,-7,-88,97,-8,97,-335,97,97,97,-87,-72,97,97,97,-89,-336,-30,97,-337,97,-76,-79,-82,-75,-77,97,-81,-215,-214,-80,-216,97,-78,-69,-36,-35,-12,97,-11,97,-234,-233,-231,97,-217,-230,97,-84,-218,97,-31,-34,-337,-198,97,97,97,-337,-229,-232,-221,97,-83,-219,-68,-33,-32,97,-11,97,-220,97,97,-337,-225,-224,-222,-84,97,97,-226,-223,97,-228,-227,]),'PPHASH':([0,14,16,17,19,25,38,45,47,59,61,119,123,124,180,191,223,332,439,510,],[47,-64,-60,-67,-66,-65,-63,-62,-70,47,-71,-87,-61,-72,-73,-336,-74,-69,-218,-68,]),'INT':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[56,-337,-113,-128,56,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,56,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,56,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,56,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,56,-131,-95,-101,-97,56,-53,-126,56,-88,56,56,-93,56,-147,-335,-146,56,-167,-166,-182,-100,-126,56,-87,-90,-94,-92,-61,-72,56,-144,-142,56,56,56,-73,56,-89,56,56,56,-149,-159,-160,-156,-336,56,-183,-30,56,56,-74,56,56,56,56,-174,-175,56,-143,-140,56,-141,-145,-76,-79,-82,-75,-77,56,-81,-215,-214,-80,-216,-78,-127,56,-153,56,-151,-148,-157,-168,-69,-36,-35,56,56,56,-234,-233,56,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,56,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'SIGNED':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[54,-337,-113,-128,54,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,54,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,54,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,54,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,54,-131,-95,-101,-97,54,-53,-126,54,-88,54,54,-93,54,-147,-335,-146,54,-167,-166,-182,-100,-126,54,-87,-90,-94,-92,-61,-72,54,-144,-142,54,54,54,-73,54,-89,54,54,54,-149,-159,-160,-156,-336,54,-183,-30,54,54,-74,54,54,54,54,-174,-175,54,-143,-140,54,-141,-145,-76,-79,-82,-75,-77,54,-81,-215,-214,-80,-216,-78,-127,54,-153,54,-151,-148,-157,-168,-69,-36,-35,54,54,54,-234,-233,54,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,54,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'CONTINUE':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,293,-336,-76,-79,-82,-75,-77,293,-81,-215,-214,-80,-216,293,-78,-69,-234,-233,-231,293,-217,-230,293,-84,-218,293,-229,-232,-221,293,-83,-219,-68,293,-220,293,293,-225,-224,-222,-84,293,293,-226,-223,293,-228,-227,]),'NOT':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,151,-335,-28,-182,-27,151,-337,-87,-72,-337,151,-286,-285,151,151,-283,-287,-288,151,-284,151,151,151,-336,-183,151,151,-28,-337,151,-28,-337,-337,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,-337,-76,-79,-82,-75,151,-77,151,151,-81,-215,-214,-80,-216,151,-78,151,151,-69,-284,151,151,-284,151,151,-244,-247,-245,-241,-242,-246,-248,151,-250,-251,-243,-249,-12,151,151,-11,151,151,151,151,-234,-233,151,-231,151,151,-217,151,-230,151,-84,-218,151,151,151,-337,-337,-198,151,151,151,-337,-284,-229,-232,151,-221,151,-83,-219,-68,151,-28,-337,151,-11,151,151,-220,151,151,151,-284,151,151,151,-337,151,-225,-224,-222,-84,151,151,151,-226,-223,151,-228,-227,]),'OREQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,366,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'MOD':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,260,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,260,260,260,260,260,260,260,260,260,260,-257,-256,260,260,260,260,260,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'RSHIFT':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,242,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,242,-262,-260,242,242,242,-259,242,242,-257,-256,242,242,242,242,242,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'DEFAULT':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,295,-336,-76,-79,-82,-75,-77,295,-81,-215,-214,-80,-216,295,-78,-69,-234,-233,-231,295,-217,-230,295,-84,-218,295,-229,-232,-221,295,-83,-219,-68,295,-220,295,295,-225,-224,-222,-84,295,295,-226,-223,295,-228,-227,]),'_NORETURN':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[20,20,-113,-128,20,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,20,-120,-115,-65,-102,20,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,20,20,-119,20,-114,-130,20,-118,-71,-103,20,-131,-96,-98,20,-131,-95,-101,-97,-53,20,20,-88,20,-147,-335,-146,-167,-166,-100,-126,20,-87,-61,-72,20,-73,20,-89,-149,-336,-30,20,-74,-174,-175,20,-76,-79,-82,-75,-77,20,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,20,20,20,-234,-233,20,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,20,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'__INT128':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[43,-337,-113,-128,43,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,43,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,43,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,43,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,43,-131,-95,-101,-97,43,-53,-126,43,-88,43,43,-93,43,-147,-335,-146,43,-167,-166,-182,-100,-126,43,-87,-90,-94,-92,-61,-72,43,-144,-142,43,43,43,-73,43,-89,43,43,43,-149,-159,-160,-156,-336,43,-183,-30,43,43,-74,43,43,43,43,-174,-175,43,-143,-140,43,-141,-145,-76,-79,-82,-75,-77,43,-81,-215,-214,-80,-216,-78,-127,43,-153,43,-151,-148,-157,-168,-69,-36,-35,43,43,43,-234,-233,43,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,43,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'WHILE':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,436,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,296,-336,-76,-79,-82,-75,-77,296,-81,-215,-214,-80,-216,296,-78,-69,-234,-233,-231,296,-217,-230,504,296,-84,-218,296,-229,-232,-221,296,-83,-219,-68,296,-220,296,296,-225,-224,-222,-84,296,296,-226,-223,296,-228,-227,]),'U8CHAR_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,154,-335,-28,-182,-27,154,-337,-87,-72,-337,154,-286,-285,154,154,-283,-287,-288,154,-284,154,154,154,-336,-183,154,154,-28,-337,154,-28,-337,-337,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,-337,-76,-79,-82,-75,154,-77,154,154,-81,-215,-214,-80,-216,154,-78,154,154,-69,-284,154,154,-284,154,154,-244,-247,-245,-241,-242,-246,-248,154,-250,-251,-243,-249,-12,154,154,-11,154,154,154,154,-234,-233,154,-231,154,154,-217,154,-230,154,-84,-218,154,154,154,-337,-337,-198,154,154,154,-337,-284,-229,-232,154,-221,154,-83,-219,-68,154,-28,-337,154,-11,154,154,-220,154,154,154,-284,154,154,154,-337,154,-225,-224,-222,-84,154,154,154,-226,-223,154,-228,-227,]),'_ALIGNOF':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,155,-335,-28,-182,-27,155,-337,-87,-72,-337,155,-286,-285,155,155,-283,-287,-288,155,-284,155,155,155,-336,-183,155,155,-28,-337,155,-28,-337,-337,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,-337,-76,-79,-82,-75,155,-77,155,155,-81,-215,-214,-80,-216,155,-78,155,155,-69,-284,155,155,-284,155,155,-244,-247,-245,-241,-242,-246,-248,155,-250,-251,-243,-249,-12,155,155,-11,155,155,155,155,-234,-233,155,-231,155,155,-217,155,-230,155,-84,-218,155,155,155,-337,-337,-198,155,155,155,-337,-284,-229,-232,155,-221,155,-83,-219,-68,155,-28,-337,155,-11,155,155,-220,155,155,155,-284,155,155,155,-337,155,-225,-224,-222,-84,155,155,155,-226,-223,155,-228,-227,]),'EXTERN':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[13,13,-113,-128,13,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,13,-120,-115,-65,-102,13,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,13,13,-119,13,-114,-130,13,-118,-71,-103,13,-131,-96,-98,13,-131,-95,-101,-97,-53,13,13,-88,13,-147,-335,-146,-167,-166,-100,-126,13,-87,-61,-72,13,-73,13,-89,-149,-336,-30,13,-74,-174,-175,13,-76,-79,-82,-75,-77,13,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,13,13,13,-234,-233,13,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,13,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'CASE':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,297,-336,-76,-79,-82,-75,-77,297,-81,-215,-214,-80,-216,297,-78,-69,-234,-233,-231,297,-217,-230,297,-84,-218,297,-229,-232,-221,297,-83,-219,-68,297,-220,297,297,-225,-224,-222,-84,297,297,-226,-223,297,-228,-227,]),'LAND':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,255,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,255,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'REGISTER':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[62,62,-113,-128,62,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,62,-120,-115,-65,-102,62,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,62,62,-119,62,-114,-130,62,-118,-71,-103,62,-131,-96,-98,62,-131,-95,-101,-97,-53,62,62,-88,62,-147,-335,-146,-167,-166,-100,-126,62,-87,-61,-72,62,-73,62,-89,-149,-336,-30,62,-74,-174,-175,62,-76,-79,-82,-75,-77,62,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,62,62,62,-234,-233,62,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,62,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'MODEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,359,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'NE':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,247,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,247,-262,-260,-264,-268,-263,-259,-266,247,-257,-256,-265,247,-267,247,247,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'SWITCH':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,299,-336,-76,-79,-82,-75,-77,299,-81,-215,-214,-80,-216,299,-78,-69,-234,-233,-231,299,-217,-230,299,-84,-218,299,-229,-232,-221,299,-83,-219,-68,299,-220,299,299,-225,-224,-222,-84,299,299,-226,-223,299,-228,-227,]),'INT_CONST_HEX':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,160,-335,-28,-182,-27,160,-337,-87,-72,-337,160,-286,-285,160,160,-283,-287,-288,160,-284,160,160,160,-336,-183,160,160,-28,-337,160,-28,-337,-337,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,-337,-76,-79,-82,-75,160,-77,160,160,-81,-215,-214,-80,-216,160,-78,160,160,-69,-284,160,160,-284,160,160,-244,-247,-245,-241,-242,-246,-248,160,-250,-251,-243,-249,-12,160,160,-11,160,160,160,160,-234,-233,160,-231,160,160,-217,160,-230,160,-84,-218,160,160,160,-337,-337,-198,160,160,160,-337,-284,-229,-232,160,-221,160,-83,-219,-68,160,-28,-337,160,-11,160,160,-220,160,160,160,-284,160,160,160,-337,160,-225,-224,-222,-84,160,160,160,-226,-223,160,-228,-227,]),'_COMPLEX':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[60,-337,-113,-128,60,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,60,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,60,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,60,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,60,-131,-95,-101,-97,60,-53,-126,60,-88,60,60,-93,60,-147,-335,-146,60,-167,-166,-182,-100,-126,60,-87,-90,-94,-92,-61,-72,60,-144,-142,60,60,60,-73,60,-89,60,60,60,-149,-159,-160,-156,-336,60,-183,-30,60,60,-74,60,60,60,60,-174,-175,60,-143,-140,60,-141,-145,-76,-79,-82,-75,-77,60,-81,-215,-214,-80,-216,-78,-127,60,-153,60,-151,-148,-157,-168,-69,-36,-35,60,60,60,-234,-233,60,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,60,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'PPPRAGMASTR':([61,],[124,]),'PLUSEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,362,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'U32CHAR_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,138,-335,-28,-182,-27,138,-337,-87,-72,-337,138,-286,-285,138,138,-283,-287,-288,138,-284,138,138,138,-336,-183,138,138,-28,-337,138,-28,-337,-337,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,-337,-76,-79,-82,-75,138,-77,138,138,-81,-215,-214,-80,-216,138,-78,138,138,-69,-284,138,138,-284,138,138,-244,-247,-245,-241,-242,-246,-248,138,-250,-251,-243,-249,-12,138,138,-11,138,138,138,138,-234,-233,138,-231,138,138,-217,138,-230,138,-84,-218,138,138,138,-337,-337,-198,138,138,138,-337,-284,-229,-232,138,-221,138,-83,-219,-68,138,-28,-337,138,-11,138,138,-220,138,138,138,-284,138,138,138,-337,138,-225,-224,-222,-84,138,138,138,-226,-223,138,-228,-227,]),'CONDOP':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,258,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'U8STRING_LITERAL':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,139,146,148,149,150,151,153,163,165,166,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,163,-335,-28,-182,-27,163,-337,-87,-72,-337,163,-286,-285,-330,163,-327,163,-283,-287,236,-328,-288,-329,163,-284,163,163,163,-336,-183,163,163,-28,-337,163,-28,-337,-337,163,163,163,-334,-332,-331,-333,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,-337,-76,-79,-82,-75,163,-77,163,163,-81,-215,-214,-80,-216,163,-78,163,163,-69,-284,163,163,-284,163,163,-244,-247,-245,-241,-242,-246,-248,163,-250,-251,-243,-249,-12,163,163,-11,163,163,163,163,-234,-233,163,-231,163,163,-217,163,-230,163,-84,-218,163,163,163,-337,-337,-198,163,163,163,-337,-284,-229,-232,163,-221,163,-83,-219,-68,163,-28,-337,163,-11,163,163,-220,163,163,163,-284,163,163,163,-337,163,-225,-224,-222,-84,163,163,163,-226,-223,163,-228,-227,]),'BREAK':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,304,-336,-76,-79,-82,-75,-77,304,-81,-215,-214,-80,-216,304,-78,-69,-234,-233,-231,304,-217,-230,304,-84,-218,304,-229,-232,-221,304,-83,-219,-68,304,-220,304,304,-225,-224,-222,-84,304,304,-226,-223,304,-228,-227,]),'VOLATILE':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,35,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,85,86,87,89,90,93,95,96,97,98,99,100,101,103,105,109,111,117,118,119,123,124,128,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,205,206,211,219,220,223,229,231,233,239,240,241,267,269,275,278,279,280,282,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,459,460,496,497,500,505,506,510,511,512,514,515,536,554,555,557,558,575,576,578,579,],[58,58,-113,-128,58,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,58,-120,-115,-65,-102,58,-131,-108,-238,-111,58,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,58,58,-119,58,-114,-130,58,-118,-71,-103,58,-131,-96,-98,58,-131,-95,-101,-97,58,-53,58,58,-88,58,58,-147,-335,-146,58,-167,-166,58,-182,-100,-126,58,58,-87,-61,-72,58,58,-144,-142,58,58,58,-73,58,-89,58,58,58,-149,-159,-160,-156,-336,58,-183,-30,58,58,58,58,58,-74,58,58,58,58,-174,-175,58,-143,-140,58,-141,-145,58,-76,-79,-82,-75,-77,58,-81,-215,-214,-80,-216,-78,-127,58,-153,58,-151,-148,-157,-168,-69,-36,-35,58,58,58,-234,-233,58,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,58,58,-229,-232,-221,-83,-219,-68,-33,-32,58,58,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'PPPRAGMA':([0,14,16,17,19,25,38,45,47,59,61,97,99,119,123,124,180,181,184,185,186,188,189,190,191,223,284,285,286,289,291,298,300,301,302,303,305,307,308,313,315,318,332,424,425,428,429,432,435,437,438,439,440,446,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[61,-64,-60,-67,-66,-65,-63,-62,-70,61,-71,-335,61,-87,-61,-72,-73,61,61,61,61,-159,-160,-156,-336,-74,-76,-79,-82,-75,-77,61,-81,-215,-214,-80,-216,61,-78,61,61,-157,-69,-234,-233,-231,61,-217,-230,61,-84,-218,61,-158,-229,-232,-221,61,-83,-219,-68,61,-220,61,61,-225,-224,-222,-84,61,61,-226,-223,61,-228,-227,]),'INLINE':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[30,30,-113,-128,30,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,30,-120,-115,-65,-102,30,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,30,30,-119,30,-114,-130,30,-118,-71,-103,30,-131,-96,-98,30,-131,-95,-101,-97,-53,30,30,-88,30,-147,-335,-146,-167,-166,-100,-126,30,-87,-61,-72,30,-73,30,-89,-149,-336,-30,30,-74,-174,-175,30,-76,-79,-82,-75,-77,30,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,30,30,30,-234,-233,30,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,30,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'INT_CONST_BIN':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,164,-335,-28,-182,-27,164,-337,-87,-72,-337,164,-286,-285,164,164,-283,-287,-288,164,-284,164,164,164,-336,-183,164,164,-28,-337,164,-28,-337,-337,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,-337,-76,-79,-82,-75,164,-77,164,164,-81,-215,-214,-80,-216,164,-78,164,164,-69,-284,164,164,-284,164,164,-244,-247,-245,-241,-242,-246,-248,164,-250,-251,-243,-249,-12,164,164,-11,164,164,164,164,-234,-233,164,-231,164,164,-217,164,-230,164,-84,-218,164,164,164,-337,-337,-198,164,164,164,-337,-284,-229,-232,164,-221,164,-83,-219,-68,164,-28,-337,164,-11,164,164,-220,164,164,164,-284,164,164,164,-337,164,-225,-224,-222,-84,164,164,164,-226,-223,164,-228,-227,]),'DO':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,307,-336,-76,-79,-82,-75,-77,307,-81,-215,-214,-80,-216,307,-78,-69,-234,-233,-231,307,-217,-230,307,-84,-218,307,-229,-232,-221,307,-83,-219,-68,307,-220,307,307,-225,-224,-222,-84,307,307,-226,-223,307,-228,-227,]),'LNOT':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,165,-335,-28,-182,-27,165,-337,-87,-72,-337,165,-286,-285,165,165,-283,-287,-288,165,-284,165,165,165,-336,-183,165,165,-28,-337,165,-28,-337,-337,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,-337,-76,-79,-82,-75,165,-77,165,165,-81,-215,-214,-80,-216,165,-78,165,165,-69,-284,165,165,-284,165,165,-244,-247,-245,-241,-242,-246,-248,165,-250,-251,-243,-249,-12,165,165,-11,165,165,165,165,-234,-233,165,-231,165,165,-217,165,-230,165,-84,-218,165,165,165,-337,-337,-198,165,165,165,-337,-284,-229,-232,165,-221,165,-83,-219,-68,165,-28,-337,165,-11,165,165,-220,165,165,165,-284,165,165,165,-337,165,-225,-224,-222,-84,165,165,165,-226,-223,165,-228,-227,]),'CONST':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,35,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,85,86,87,89,90,93,95,96,97,98,99,100,101,103,105,109,111,117,118,119,123,124,128,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,205,206,211,219,220,223,229,231,233,239,240,241,267,269,275,278,279,280,282,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,459,460,496,497,500,505,506,510,511,512,514,515,536,554,555,557,558,575,576,578,579,],[3,3,-113,-128,3,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,3,-120,-115,-65,-102,3,-131,-108,-238,-111,3,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,3,3,-119,3,-114,-130,3,-118,-71,-103,3,-131,-96,-98,3,-131,-95,-101,-97,3,-53,3,3,-88,3,3,-147,-335,-146,3,-167,-166,3,-182,-100,-126,3,3,-87,-61,-72,3,3,-144,-142,3,3,3,-73,3,-89,3,3,3,-149,-159,-160,-156,-336,3,-183,-30,3,3,3,3,3,-74,3,3,3,3,-174,-175,3,-143,-140,3,-141,-145,3,-76,-79,-82,-75,-77,3,-81,-215,-214,-80,-216,-78,-127,3,-153,3,-151,-148,-157,-168,-69,-36,-35,3,3,3,-234,-233,3,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,3,3,-229,-232,-221,-83,-219,-68,-33,-32,3,3,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LSHIFT':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,244,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,244,-262,-260,244,244,244,-259,244,244,-257,-256,244,244,244,244,244,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'LOR':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,243,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'CHAR_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,167,-335,-28,-182,-27,167,-337,-87,-72,-337,167,-286,-285,167,167,-283,-287,-288,167,-284,167,167,167,-336,-183,167,167,-28,-337,167,-28,-337,-337,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,-337,-76,-79,-82,-75,167,-77,167,167,-81,-215,-214,-80,-216,167,-78,167,167,-69,-284,167,167,-284,167,167,-244,-247,-245,-241,-242,-246,-248,167,-250,-251,-243,-249,-12,167,167,-11,167,167,167,167,-234,-233,167,-231,167,167,-217,167,-230,167,-84,-218,167,167,167,-337,-337,-198,167,167,167,-337,-284,-229,-232,167,-221,167,-83,-219,-68,167,-28,-337,167,-11,167,167,-220,167,167,167,-284,167,167,167,-337,167,-225,-224,-222,-84,167,167,167,-226,-223,167,-228,-227,]),'U16STRING_LITERAL':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,139,146,148,149,150,151,153,163,165,166,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,166,-335,-28,-182,-27,166,-337,-87,-72,-337,166,-286,-285,-330,166,-327,166,-283,-287,238,-328,-288,-329,166,-284,166,166,166,-336,-183,166,166,-28,-337,166,-28,-337,-337,166,166,166,-334,-332,-331,-333,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,-337,-76,-79,-82,-75,166,-77,166,166,-81,-215,-214,-80,-216,166,-78,166,166,-69,-284,166,166,-284,166,166,-244,-247,-245,-241,-242,-246,-248,166,-250,-251,-243,-249,-12,166,166,-11,166,166,166,166,-234,-233,166,-231,166,166,-217,166,-230,166,-84,-218,166,166,166,-337,-337,-198,166,166,166,-337,-284,-229,-232,166,-221,166,-83,-219,-68,166,-28,-337,166,-11,166,166,-220,166,166,166,-284,166,166,166,-337,166,-225,-224,-222,-84,166,166,166,-226,-223,166,-228,-227,]),'RBRACE':([61,97,99,119,124,132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,178,181,184,185,186,188,189,190,191,195,196,197,224,225,227,228,230,232,234,235,236,237,238,261,263,268,273,284,285,286,289,291,298,300,301,302,303,305,306,308,309,313,315,318,325,326,327,332,370,374,377,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,424,425,428,432,435,437,438,439,446,450,451,468,469,472,473,476,478,480,482,483,487,496,497,500,505,506,510,523,524,528,536,546,547,550,551,554,555,557,558,565,575,576,578,579,],[-71,-335,191,-87,-72,-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-252,-337,191,191,191,-159,-160,-156,-336,-171,191,-176,-274,-239,-337,-193,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-76,-79,-82,-75,-77,-6,-81,-215,-214,-80,-216,-5,-78,191,191,191,-157,191,191,-172,-69,191,-22,-21,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,-234,-233,-231,-217,-230,-81,-84,-218,-158,-173,-177,-240,-194,191,-196,-237,-281,-282,-290,-291,-275,-229,-232,-221,-83,-219,-68,-195,-254,191,-220,-197,-306,191,-299,-225,-224,-222,-84,-300,-226,-223,-228,-227,]),'_BOOL':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[34,-337,-113,-128,34,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,34,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,34,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,34,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,34,-131,-95,-101,-97,34,-53,-126,34,-88,34,34,-93,34,-147,-335,-146,34,-167,-166,-182,-100,-126,34,-87,-90,-94,-92,-61,-72,34,-144,-142,34,34,34,-73,34,-89,34,34,34,-149,-159,-160,-156,-336,34,-183,-30,34,34,-74,34,34,34,34,-174,-175,34,-143,-140,34,-141,-145,-76,-79,-82,-75,-77,34,-81,-215,-214,-80,-216,-78,-127,34,-153,34,-151,-148,-157,-168,-69,-36,-35,34,34,34,-234,-233,34,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,34,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LE':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,246,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,246,-262,-260,-264,246,-263,-259,-266,246,-257,-256,-265,246,246,246,246,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'SEMI':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,70,71,73,74,75,76,77,78,79,80,81,82,83,84,86,87,89,91,94,96,97,98,99,100,101,108,109,110,111,113,114,115,119,120,121,122,123,124,127,132,133,134,136,138,139,140,141,142,143,144,145,147,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,178,179,180,181,184,185,186,187,188,189,190,191,192,200,216,217,223,224,225,226,228,230,232,234,235,236,237,238,240,241,261,263,268,269,272,273,275,279,280,284,285,286,288,289,290,291,293,294,298,300,301,302,303,304,305,306,307,308,310,312,313,314,315,316,317,318,320,321,322,323,324,328,330,331,332,340,341,355,356,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,423,424,425,426,427,428,429,432,433,435,437,438,439,440,442,443,444,446,448,449,453,454,464,465,468,469,476,478,480,482,483,486,487,496,497,498,499,500,502,505,506,508,509,510,511,512,518,519,523,524,533,534,535,536,537,539,547,551,552,554,555,557,558,565,568,569,574,575,576,577,578,579,],[19,-337,-113,-128,-337,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,-337,-29,-121,-116,-62,-112,-70,-52,-123,-117,119,-337,-337,-119,-337,-114,-130,19,-118,-71,-103,-337,-9,-131,-91,-10,-96,-20,-98,-54,-179,-178,-131,-37,-134,-85,-95,-101,-97,-19,-132,-53,-126,-337,-337,-93,-147,-335,-146,188,-167,-166,-136,-100,-138,-126,-16,-86,-15,-87,-90,-94,-92,-61,-72,-55,-317,-321,-318,-303,-324,-330,-313,-319,-144,-301,-274,-314,-142,-327,-325,-304,-322,-302,-255,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-252,-178,-73,-337,188,188,188,-149,-159,-160,-156,-336,-337,-30,-38,-133,-74,-274,-239,-135,-193,-326,-280,-277,-334,-332,-331,-333,-174,-175,-298,-297,-279,-143,-235,-278,-140,-141,-145,-76,-79,-82,424,-75,425,-77,428,-14,-337,-81,-215,-214,-80,435,-216,-13,-337,-78,-312,-127,188,-153,188,-151,-148,-157,-26,-25,446,-161,-163,-168,-139,-137,-69,-36,-35,-44,-43,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,-292,-305,496,-234,-233,497,-337,-231,-337,-217,-13,-230,-81,-84,-218,-337,-152,-150,-165,-158,-170,-169,-31,-34,-39,-42,-240,-194,-237,-281,-282,-290,-291,-236,-275,-229,-232,533,-337,-221,-337,-83,-219,-162,-164,-68,-33,-32,-41,-40,-195,-254,-337,553,-337,-220,-337,-337,-306,-299,566,-225,-224,-222,-84,-300,575,-337,-337,-226,-223,-337,-228,-227,]),'_THREAD_LOCAL':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[11,11,-113,-128,11,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,11,-120,-115,-65,-102,11,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,11,11,-119,11,-114,-130,11,-118,-71,-103,11,-131,-96,-98,11,-131,-95,-101,-97,-53,11,11,-88,11,-147,-335,-146,-167,-166,-100,-126,11,-87,-61,-72,11,-73,11,-89,-149,-336,-30,11,-74,-174,-175,11,-76,-79,-82,-75,-77,11,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,11,11,11,-234,-233,11,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,11,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'LT':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,248,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,248,-262,-260,-264,248,-263,-259,-266,248,-257,-256,-265,248,248,248,248,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'COMMA':([2,3,5,6,7,10,11,12,13,18,20,22,23,26,27,30,33,34,35,36,39,42,43,44,46,48,49,50,54,56,58,60,62,68,70,71,73,74,75,76,77,78,80,81,82,84,86,96,98,100,101,103,104,105,106,108,109,110,111,113,127,132,133,134,136,138,139,140,141,142,143,144,145,147,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,177,178,179,187,191,195,196,197,198,199,200,203,210,211,212,213,215,216,217,224,225,226,228,230,232,234,235,236,237,238,240,241,261,263,268,269,270,272,273,274,275,276,277,279,280,281,283,294,310,312,314,316,317,320,323,324,325,326,327,328,330,331,340,341,343,344,345,346,347,348,355,356,374,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,414,426,442,443,444,448,449,450,451,453,454,458,461,463,464,465,468,469,473,476,478,480,482,483,486,487,489,490,492,501,503,507,508,509,511,512,518,519,523,524,525,528,529,530,531,532,544,545,546,547,551,556,559,560,564,565,570,571,],[-113,-128,-124,-110,-106,-104,-107,-125,-105,-99,-109,-120,-115,-102,-126,-108,-238,-111,-337,-122,-129,-29,-121,-116,-112,-52,-123,-117,-119,-114,-130,-118,-103,-96,126,-98,-54,-179,-178,-131,-37,-134,-95,-101,-97,-132,-53,-147,-146,-167,-166,-28,-180,-182,-27,-136,-100,-138,-126,202,-55,-317,-321,-318,-303,-324,-330,-313,-319,-144,-301,-274,-314,-142,-327,-325,-304,-322,-302,-255,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-337,-252,-178,-149,-336,-171,327,-176,-183,-181,-30,333,-186,-337,349,350,-191,-38,-133,-274,-239,-135,-193,-326,-280,-277,-334,-332,-331,-333,-174,-175,-298,-297,-279,-143,412,-235,-278,-203,-140,-204,-1,-141,-145,-2,-206,412,-312,-127,-153,-151,-148,445,-161,-163,327,327,-172,-168,-139,-137,-36,-35,-190,-204,-56,-188,-45,-189,-44,-43,472,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,412,-270,-258,-296,-295,-294,-293,412,-292,-310,484,485,-305,-205,412,-152,-150,-165,-170,-169,-173,-177,-31,-34,-57,-192,-187,-39,-42,-240,-194,-196,-237,-281,-282,-290,-291,-236,-275,-213,-207,-211,412,412,412,-162,-164,-33,-32,-41,-40,-195,-254,-311,550,-209,-208,-210,-212,-51,-50,-197,-306,-299,412,-46,-49,412,-300,-48,-47,]),'U16CHAR_CONST':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,169,-335,-28,-182,-27,169,-337,-87,-72,-337,169,-286,-285,169,169,-283,-287,-288,169,-284,169,169,169,-336,-183,169,169,-28,-337,169,-28,-337,-337,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,-337,-76,-79,-82,-75,169,-77,169,169,-81,-215,-214,-80,-216,169,-78,169,169,-69,-284,169,169,-284,169,169,-244,-247,-245,-241,-242,-246,-248,169,-250,-251,-243,-249,-12,169,169,-11,169,169,169,169,-234,-233,169,-231,169,169,-217,169,-230,169,-84,-218,169,169,169,-337,-337,-198,169,169,169,-337,-284,-229,-232,169,-221,169,-83,-219,-68,169,-28,-337,169,-11,169,169,-220,169,169,169,-284,169,169,169,-337,169,-225,-224,-222,-84,169,169,169,-226,-223,169,-228,-227,]),'OFFSETOF':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,137,146,149,150,151,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,170,-335,-28,-182,-27,170,-337,-87,-72,-337,170,-286,-285,170,170,-283,-287,-288,170,-284,170,170,170,-336,-183,170,170,-28,-337,170,-28,-337,-337,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,-337,-76,-79,-82,-75,170,-77,170,170,-81,-215,-214,-80,-216,170,-78,170,170,-69,-284,170,170,-284,170,170,-244,-247,-245,-241,-242,-246,-248,170,-250,-251,-243,-249,-12,170,170,-11,170,170,170,170,-234,-233,170,-231,170,170,-217,170,-230,170,-84,-218,170,170,170,-337,-337,-198,170,170,170,-337,-284,-229,-232,170,-221,170,-83,-219,-68,170,-28,-337,170,-11,170,170,-220,170,170,170,-284,170,170,170,-337,170,-225,-224,-222,-84,170,170,170,-226,-223,170,-228,-227,]),'_ATOMIC':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,35,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,103,105,109,111,117,118,119,120,121,122,123,124,128,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,205,206,211,214,219,220,223,229,231,233,239,240,241,267,269,275,278,279,280,282,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,459,460,496,497,500,505,506,510,511,512,514,515,536,554,555,557,558,575,576,578,579,],[29,65,-113,-128,76,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,65,-120,-115,-65,-102,65,-131,-108,-238,-111,76,-122,-63,-129,112,-29,-121,-116,-62,-112,-70,-52,-123,-117,65,65,-119,65,-114,-130,29,-118,-71,-103,65,-9,-131,-91,-10,-96,-98,65,-131,-95,-101,-97,29,-53,65,76,-88,112,65,-93,29,-147,-335,-146,29,-167,-166,76,-182,-100,-126,76,29,-87,-90,-94,-92,-61,-72,76,29,-144,-142,65,29,76,-73,65,-89,29,29,29,-149,-159,-160,-156,-336,76,-183,-30,76,76,76,112,76,76,-74,29,29,29,29,-174,-175,29,-143,-140,29,-141,-145,76,-76,-79,-82,-75,-77,65,-81,-215,-214,-80,-216,-78,-127,29,-153,29,-151,-148,-157,-168,-69,-36,-35,29,29,29,-234,-233,65,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,76,29,-229,-232,-221,-83,-219,-68,-33,-32,76,76,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'TYPEDEF':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[7,7,-113,-128,7,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,7,-120,-115,-65,-102,7,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,7,7,-119,7,-114,-130,7,-118,-71,-103,7,-131,-96,-98,7,-131,-95,-101,-97,-53,7,7,-88,7,-147,-335,-146,-167,-166,-100,-126,7,-87,-61,-72,7,-73,7,-89,-149,-336,-30,7,-74,-174,-175,7,-76,-79,-82,-75,-77,7,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,7,7,7,-234,-233,7,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,7,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'XOR':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,251,-328,-316,-329,-320,-276,-323,-312,-336,-274,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-261,251,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,251,-267,-269,251,-258,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'AUTO':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,65,68,71,75,76,80,81,82,86,87,89,90,93,96,97,98,100,101,109,111,118,119,123,124,129,180,181,182,187,191,200,211,223,240,241,278,284,285,286,289,291,298,300,301,302,303,305,308,312,314,316,317,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[26,26,-113,-128,26,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,26,-120,-115,-65,-102,26,-131,-108,-238,-111,-122,-63,-129,-29,-121,-116,-62,-112,-70,-52,-123,-117,26,26,-119,26,-114,-130,26,-118,-71,-103,26,-131,-96,-98,26,-131,-95,-101,-97,-53,26,26,-88,26,-147,-335,-146,-167,-166,-100,-126,26,-87,-61,-72,26,-73,26,-89,-149,-336,-30,26,-74,-174,-175,26,-76,-79,-82,-75,-77,26,-81,-215,-214,-80,-216,-78,-127,-153,-151,-148,-168,-69,-36,-35,26,26,26,-234,-233,26,-231,-217,-230,-81,-84,-218,-152,-150,-170,-169,-31,-34,26,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'DIVEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,357,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'TIMES':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,22,23,25,26,27,29,30,33,34,35,36,37,38,39,40,43,44,45,46,47,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,69,71,76,80,81,82,85,87,89,91,94,96,97,98,100,101,103,104,105,106,109,111,116,117,119,120,121,122,123,124,126,128,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,156,158,160,161,162,163,164,165,166,167,168,169,171,173,174,175,176,177,180,181,187,191,192,198,201,202,204,205,206,211,218,219,220,223,224,227,229,230,231,232,233,234,235,236,237,238,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,268,269,273,275,278,279,280,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,312,314,316,317,319,328,329,332,336,338,339,342,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,442,443,445,447,448,449,459,472,475,477,478,480,481,482,483,484,487,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[35,-337,-113,-128,35,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,-120,-115,-65,-102,-126,-131,-108,-238,-111,-337,-122,35,-63,-129,35,-121,-116,-62,-112,-70,-123,-117,-337,-337,-119,-337,-114,-130,35,-118,-71,-103,-337,-9,-131,-91,-10,-96,35,-98,-131,-95,-101,-97,173,-126,35,35,-93,-147,-335,-146,-167,-166,-28,35,-182,-27,-100,-126,173,-337,-87,-90,-94,-92,-61,-72,35,-337,173,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-144,-301,-274,-314,173,-142,-327,173,-283,-287,-325,-304,-322,-302,-255,-315,-289,253,-328,-316,-288,-329,-320,-276,-323,173,-284,173,173,-312,35,-73,173,-149,-336,35,-183,173,35,336,-28,-337,35,352,-28,-337,-74,-274,-337,173,-326,173,-280,173,-277,-334,-332,-331,-333,-174,-175,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,-298,-297,173,173,-279,-143,-278,-140,35,-141,-145,420,-76,-79,-82,-75,173,-77,173,173,-81,-215,-214,-80,-216,173,-78,-312,-127,-153,-151,-148,173,-168,173,-69,-284,173,173,35,-284,173,173,-244,-247,-245,-241,-242,-246,-248,173,-250,-251,-243,-249,-12,173,173,-11,253,253,253,253,253,253,253,253,253,253,-257,-256,253,253,253,253,253,-258,-296,-295,-294,-293,-292,-305,173,173,173,494,-234,-233,173,-231,173,173,-217,173,-230,173,-84,-218,173,173,-152,-150,35,173,-170,-169,-337,-337,-198,173,-281,-282,173,-290,-291,173,-275,-337,-284,-229,-232,173,-221,173,-83,-219,-68,541,-28,-337,173,-11,173,173,-220,173,173,173,-284,173,173,-306,173,-337,-299,173,-225,-224,-222,-84,-300,173,173,173,-226,-223,173,-228,-227,]),'LPAREN':([0,1,2,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,29,30,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,69,71,72,73,76,77,80,81,82,85,86,87,89,91,94,96,97,98,100,101,103,104,105,106,109,111,112,116,117,119,120,121,122,123,124,126,127,128,131,132,133,134,135,136,137,138,139,140,141,142,143,145,146,147,148,149,150,151,152,153,154,155,156,160,161,163,164,165,166,167,168,169,170,171,173,174,175,176,177,180,181,187,191,192,198,199,200,201,202,204,205,206,211,216,218,219,220,223,227,229,230,231,233,235,236,237,238,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,269,275,276,278,279,280,282,283,284,285,286,289,290,291,292,296,297,298,299,300,301,302,303,305,307,308,310,311,312,314,316,317,319,328,329,332,336,338,339,340,341,342,344,345,347,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,402,403,404,405,407,411,412,413,414,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,442,443,445,447,448,449,453,454,457,458,459,464,465,472,475,477,481,482,483,484,488,489,490,492,494,496,497,499,500,502,504,505,506,510,511,512,513,514,515,518,519,521,522,529,530,531,532,533,535,536,537,538,539,541,542,543,544,545,547,549,550,551,553,554,555,557,558,559,560,565,566,569,570,571,574,575,576,577,578,579,],[37,-337,-113,-128,69,-124,-110,-106,85,-104,-107,-125,-105,-64,37,-60,-67,-99,-66,-109,-120,-115,-65,-102,-126,95,-108,-238,-111,-337,-122,37,-63,-129,37,116,-29,-121,-116,-62,-112,-70,118,-123,-117,-337,-337,-119,-337,-114,-130,37,-118,-71,-103,-337,-9,95,-91,-10,-96,69,-98,69,129,-131,-37,-95,-101,-97,174,118,-126,69,37,-93,-147,-335,-146,-167,-166,-28,-180,-182,-27,-100,-126,95,174,-337,-87,-90,-94,-92,-61,-72,69,129,-337,229,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-144,-301,-314,231,-142,-327,233,-283,-287,-325,-304,-322,239,-302,-315,-289,-328,-316,-288,-329,-320,266,-323,267,174,-284,229,233,-312,278,-73,229,-149,-336,69,-183,-181,-30,229,69,229,-28,-337,342,-38,229,-28,-337,-74,-337,229,-326,229,229,-334,-332,-331,-333,-174,-175,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,229,174,174,-298,-297,229,229,-143,-140,278,278,-141,-145,-337,422,-76,-79,-82,-75,229,-77,427,430,174,229,434,-81,-215,-214,-80,-216,229,-78,-312,441,-127,-153,-151,-148,174,-168,174,-69,-284,229,229,-36,-35,342,342,460,-45,-284,229,229,-44,-43,-244,-247,-245,-241,-242,-246,-248,229,-250,-251,-243,-249,-12,174,229,-11,-296,-295,-294,-293,-292,-305,229,174,422,229,229,-234,-233,229,-231,229,229,-217,229,-230,229,-84,-218,229,229,-152,-150,69,174,-170,-169,-31,-34,342,460,-337,-39,-42,-337,-198,174,174,-290,-291,229,-337,-213,-207,-211,-284,-229,-232,229,-221,229,538,-83,-219,-68,-33,-32,229,-28,-337,-41,-40,229,-11,-209,-208,-210,-212,229,229,-220,229,229,229,-284,229,229,-51,-50,-306,229,-337,-299,229,-225,-224,-222,-84,-46,-49,-300,229,229,-48,-47,229,-226,-223,229,-228,-227,]),'MINUSMINUS':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,132,133,134,135,136,137,138,139,140,141,143,145,146,148,149,150,151,152,153,154,156,160,161,163,164,165,166,167,168,169,171,173,174,175,176,181,191,198,201,204,205,206,218,219,220,227,229,230,231,233,235,236,237,238,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,263,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,310,319,329,332,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,402,403,404,405,407,411,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,459,472,475,477,481,482,483,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,547,549,550,551,553,554,555,557,558,565,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,175,-335,-28,-182,-27,175,-337,-87,-72,-337,175,-317,-321,-318,-286,-303,-285,-324,-330,-313,-319,-301,-314,175,-327,175,-283,-287,-325,-304,-322,-302,-315,-289,-328,-316,-288,-329,-320,261,-323,175,-284,175,175,-312,175,-336,-183,175,175,-28,-337,175,-28,-337,-337,175,-326,175,175,-334,-332,-331,-333,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,-298,-297,175,175,-337,-76,-79,-82,-75,175,-77,175,175,-81,-215,-214,-80,-216,175,-78,-312,175,175,-69,-284,175,175,-284,175,175,-244,-247,-245,-241,-242,-246,-248,175,-250,-251,-243,-249,-12,175,175,-11,-296,-295,-294,-293,-292,-305,175,175,175,175,-234,-233,175,-231,175,175,-217,175,-230,175,-84,-218,175,175,175,-337,-337,-198,175,175,-290,-291,175,-337,-284,-229,-232,175,-221,175,-83,-219,-68,175,-28,-337,175,-11,175,175,-220,175,175,175,-284,175,175,-306,175,-337,-299,175,-225,-224,-222,-84,-300,175,175,175,-226,-223,175,-228,-227,]),'ID':([0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,43,44,45,46,47,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,69,71,72,76,80,81,82,85,87,89,91,94,96,97,98,100,101,102,103,104,105,106,109,111,116,117,118,119,120,121,122,123,124,126,128,129,131,135,137,142,146,147,149,150,151,165,171,173,174,175,180,181,187,191,192,193,194,198,199,201,202,204,205,206,211,218,219,220,223,227,229,231,233,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,262,264,265,266,269,275,279,280,282,284,285,286,287,289,290,291,297,298,300,301,302,303,305,307,308,312,314,316,317,319,327,328,329,332,336,338,339,342,344,349,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,372,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,442,443,445,447,448,449,457,459,460,472,475,477,481,484,485,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,548,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[42,-337,-113,-128,42,-124,-110,-106,-104,-107,-125,-105,-64,42,-60,-67,-99,-66,-109,-120,-115,-154,-65,-102,-126,-155,-131,-108,98,101,-238,-111,-337,-122,42,-63,-129,42,-121,-116,-62,-112,-70,-123,-117,-337,-337,-119,-337,-114,-130,42,-118,-71,-103,-337,-9,-131,-91,-10,-96,42,-98,42,-131,-95,-101,-97,176,-126,42,42,-93,-147,-335,-146,-167,-166,197,-28,-180,-182,-27,-100,-126,176,-337,176,-87,-90,-94,-92,-61,-72,42,-337,176,176,-286,-285,-144,176,-142,176,-283,-287,-288,176,-284,176,176,-73,310,-149,-336,42,197,197,-183,-181,176,42,176,-28,-337,42,176,-28,-337,-74,-337,176,176,176,-174,-175,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,403,405,176,176,-143,-140,-141,-145,-337,-76,-79,-82,423,-75,176,-77,176,310,-81,-215,-214,-80,-216,310,-78,-127,-153,-151,-148,176,197,-168,176,-69,-284,176,176,42,42,176,-284,176,176,-244,-247,-245,-241,-242,-246,-248,176,-250,-251,-243,-249,-12,176,176,176,-11,176,176,176,176,-234,-233,176,-231,310,176,-217,176,-230,310,-84,-218,310,176,-152,-150,42,176,-170,-169,42,-337,176,-337,-198,176,176,176,176,-337,-284,-229,-232,176,-221,310,-83,-219,-68,176,-28,-337,176,-11,176,310,-220,310,176,310,-284,176,176,176,176,-337,176,-225,-224,-222,-84,176,310,310,-226,-223,310,-228,-227,]),'IF':([61,97,119,124,181,191,284,285,286,289,291,298,300,301,302,303,305,307,308,332,424,425,428,429,432,435,437,438,439,440,496,497,500,502,505,506,510,535,536,537,539,554,555,557,558,569,574,575,576,577,578,579,],[-71,-335,-87,-72,311,-336,-76,-79,-82,-75,-77,311,-81,-215,-214,-80,-216,311,-78,-69,-234,-233,-231,311,-217,-230,311,-84,-218,311,-229,-232,-221,311,-83,-219,-68,311,-220,311,311,-225,-224,-222,-84,311,311,-226,-223,311,-228,-227,]),'STRING_LITERAL':([3,39,58,61,76,85,97,103,105,106,116,117,119,124,128,131,135,136,137,146,149,150,151,152,165,171,173,174,175,181,191,198,201,204,205,206,218,219,220,227,229,230,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,282,284,285,286,289,290,291,297,298,300,301,302,303,305,307,308,319,329,332,333,336,338,339,352,353,354,357,358,359,360,361,362,363,364,365,366,367,368,369,373,375,377,412,413,419,421,424,425,427,428,429,430,432,434,435,437,438,439,440,441,447,452,459,472,475,477,481,484,488,494,496,497,499,500,502,505,506,510,513,514,515,521,522,533,535,536,537,538,539,541,542,543,549,550,553,554,555,557,558,566,569,574,575,576,577,578,579,],[-128,-129,-130,-71,-131,152,-335,-28,-182,-27,152,-337,-87,-72,-337,152,-286,230,-285,152,152,-283,-287,-325,-288,152,-284,152,152,152,-336,-183,152,152,-28,-337,152,-28,-337,-337,152,-326,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,-337,-76,-79,-82,-75,152,-77,152,152,-81,-215,-214,-80,-216,152,-78,152,152,-69,152,-284,152,152,-284,152,152,-244,-247,-245,-241,-242,-246,-248,152,-250,-251,-243,-249,-12,152,152,-11,152,152,152,152,-234,-233,152,-231,152,152,-217,152,-230,152,-84,-218,152,152,152,230,-337,-337,-198,152,152,152,-337,-284,-229,-232,152,-221,152,-83,-219,-68,152,-28,-337,152,-11,152,152,-220,152,152,152,-284,152,152,152,-337,152,-225,-224,-222,-84,152,152,152,-226,-223,152,-228,-227,]),'FLOAT':([0,1,2,3,4,5,6,7,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,29,30,33,34,36,38,39,40,42,43,44,45,46,47,48,49,50,52,53,54,55,56,58,59,60,61,62,63,64,65,66,67,68,71,75,76,80,81,82,85,86,87,89,90,91,93,94,95,96,97,98,99,100,101,105,109,111,118,119,120,121,122,123,124,129,142,147,172,174,177,180,181,182,184,185,186,187,188,189,190,191,192,198,200,211,214,223,229,231,233,239,240,241,267,269,275,278,279,280,284,285,286,289,291,298,300,301,302,303,305,308,312,313,314,315,316,317,318,328,332,340,341,342,350,422,424,425,427,428,432,435,437,438,439,442,443,446,448,449,453,454,460,496,497,500,505,506,510,511,512,536,554,555,557,558,575,576,578,579,],[44,-337,-113,-128,44,-124,-110,-106,-104,-107,-125,-105,-64,-60,-67,-99,-66,-109,44,-120,-115,-65,-102,-126,-131,-108,-238,-111,-122,-63,-129,44,-29,-121,-116,-62,-112,-70,-52,-123,-117,-337,-337,-119,-337,-114,-130,44,-118,-71,-103,-337,-9,-131,-91,-10,-96,-98,44,-131,-95,-101,-97,44,-53,-126,44,-88,44,44,-93,44,-147,-335,-146,44,-167,-166,-182,-100,-126,44,-87,-90,-94,-92,-61,-72,44,-144,-142,44,44,44,-73,44,-89,44,44,44,-149,-159,-160,-156,-336,44,-183,-30,44,44,-74,44,44,44,44,-174,-175,44,-143,-140,44,-141,-145,-76,-79,-82,-75,-77,44,-81,-215,-214,-80,-216,-78,-127,44,-153,44,-151,-148,-157,-168,-69,-36,-35,44,44,44,-234,-233,44,-231,-217,-230,-81,-84,-218,-152,-150,-158,-170,-169,-31,-34,44,-229,-232,-221,-83,-219,-68,-33,-32,-220,-225,-224,-222,-84,-226,-223,-228,-227,]),'XOREQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,361,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'LSHIFTEQUAL':([132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,160,161,163,164,166,167,168,169,176,191,224,230,232,234,235,236,237,238,261,263,268,273,310,402,403,404,405,407,411,478,480,482,483,487,547,551,565,],[-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-315,-289,-328,-316,-329,-320,-276,-323,-312,-336,363,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-278,-312,-296,-295,-294,-293,-292,-305,-281,-282,-290,-291,-275,-306,-299,-300,]),'RBRACKET':([3,39,58,76,103,105,106,117,128,132,133,134,136,138,139,140,141,143,144,145,148,152,153,154,156,158,160,161,162,163,164,166,167,168,169,176,178,191,198,204,205,218,219,224,225,230,232,234,235,236,237,238,261,263,268,272,273,282,334,335,336,337,351,352,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,402,403,404,405,406,407,411,419,420,421,455,456,459,466,467,468,471,476,478,480,482,483,486,487,491,493,494,513,514,524,540,541,547,551,561,562,564,565,],[-128,-129,-130,-131,-28,-182,-27,-337,-337,-317,-321,-318,-303,-324,-330,-313,-319,-301,-274,-314,-327,-325,-304,-322,-302,-255,-315,-289,-253,-328,-316,-329,-320,-276,-323,-312,-252,-336,-183,-337,-28,-337,-28,-274,-239,-326,-280,-277,-334,-332,-331,-333,-298,-297,-279,-235,-278,-337,453,-4,454,-3,464,465,-261,-273,-262,-260,-264,-268,-263,-259,-266,-271,-257,-256,-265,-272,-267,-269,-270,-258,-296,-295,-294,-293,482,-292,-305,-337,492,-337,511,512,-337,518,519,-240,520,-237,-281,-282,-290,-291,-236,-275,529,530,531,-337,-28,-254,559,560,-306,-299,570,571,572,-300,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'expression_statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[284,284,284,284,284,284,284,284,284,284,284,284,284,]),'struct_or_union_specifier':([0,21,40,59,75,85,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,]),'init_declarator_list':([4,89,],[70,70,]),'init_declarator_list_opt':([4,89,],[79,79,]),'iteration_statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[285,285,285,285,285,285,285,285,285,285,285,285,285,]),'static_assert':([0,59,181,298,307,429,437,440,502,535,537,539,569,574,577,],[17,17,286,286,286,286,286,286,286,286,286,286,286,286,286,]),'unified_string_literal':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,333,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,452,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,]),'assignment_expression_opt':([204,218,419,421,513,],[334,351,491,493,540,]),'brace_open':([31,32,92,96,98,100,101,130,131,181,201,229,298,307,375,413,429,437,440,477,478,479,502,521,535,537,539,569,574,577,],[99,102,181,184,185,193,194,181,227,181,227,181,181,181,227,488,181,181,181,488,488,488,181,227,181,181,181,181,181,181,]),'enumerator':([102,193,194,327,],[195,195,195,450,]),'typeid_noparen_declarator':([211,],[348,]),'type_qualifier_list_opt':([35,117,128,206,220,282,459,515,],[104,204,218,339,354,419,513,543,]),'declaration_specifiers_no_type_opt':([1,27,52,53,55,63,87,],[66,94,120,121,122,94,94,]),'expression_opt':([181,298,307,427,429,437,440,499,502,533,535,537,539,553,566,569,574,577,],[288,288,288,498,288,288,288,534,288,552,288,288,288,567,573,288,288,288,]),'designation':([227,472,488,550,],[369,369,369,369,]),'parameter_list':([118,129,278,342,422,460,],[213,213,213,213,213,213,]),'alignment_specifier':([0,1,4,21,27,52,53,55,59,63,75,85,87,89,93,95,99,118,129,174,177,181,184,185,186,192,211,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[53,53,81,53,53,53,53,53,53,53,53,142,53,81,53,142,142,53,53,142,280,53,142,142,142,280,81,142,142,142,142,142,53,53,142,142,53,53,53,53,53,]),'labeled_statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[289,289,289,289,289,289,289,289,289,289,289,289,289,]),'abstract_declarator':([177,211,278,342,],[281,281,418,418,]),'translation_unit':([0,],[59,]),'init_declarator':([4,89,126,202,],[84,84,217,331,]),'direct_abstract_declarator':([177,211,276,278,342,344,457,],[283,283,414,283,283,414,414,]),'designator_list':([227,472,488,550,],[376,376,376,376,]),'identifier':([85,116,118,129,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,349,353,354,364,372,373,375,412,413,419,421,427,429,430,434,437,440,441,447,460,477,481,484,485,499,502,513,521,533,535,537,538,539,542,543,548,549,553,566,569,574,577,],[143,143,215,215,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,461,143,143,143,470,143,143,143,143,143,143,143,143,143,143,143,143,143,143,215,143,143,143,527,143,143,143,143,143,143,143,143,143,143,143,563,143,143,143,143,143,143,]),'offsetof_member_designator':([485,],[526,]),'unary_expression':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[144,144,224,232,234,144,224,273,224,224,224,224,224,224,224,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,224,144,144,224,224,224,144,224,224,144,144,224,224,224,224,224,144,224,224,144,224,224,224,224,224,224,224,224,224,144,144,144,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,]),'abstract_declarator_opt':([177,211,],[274,343,]),'initializer':([131,201,375,521,],[226,330,473,546,]),'direct_id_declarator':([0,4,15,37,40,59,69,72,89,91,126,192,202,211,342,344,445,457,],[48,48,86,48,48,48,48,86,48,48,48,48,48,48,48,86,48,86,]),'struct_declaration_list':([99,184,185,],[186,313,315,]),'pp_directive':([0,59,],[14,14,]),'declaration_list':([21,75,],[93,93,]),'id_init_declarator':([40,91,],[108,108,]),'type_specifier':([0,21,40,59,75,85,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[18,18,109,18,18,147,109,18,147,147,18,18,269,147,18,147,147,147,109,147,147,147,147,147,18,18,147,147,18,18,18,18,18,]),'compound_statement':([92,130,181,229,298,307,429,437,440,502,535,537,539,569,574,577,],[180,223,291,378,291,291,291,291,291,291,291,291,291,291,291,291,]),'pointer':([0,4,37,40,59,69,89,91,104,126,177,192,202,211,278,342,445,],[15,72,15,15,15,72,72,15,199,72,276,72,72,344,276,457,72,]),'typeid_declarator':([4,69,89,126,192,202,445,],[74,125,74,74,74,74,74,]),'id_init_declarator_list':([40,91,],[113,113,]),'declarator':([4,89,126,192,202,445,],[78,78,78,324,78,324,]),'argument_expression_list':([266,],[409,]),'struct_declarator_list_opt':([192,],[322,]),'block_item_list':([181,],[298,]),'parameter_type_list_opt':([278,342,422,],[417,417,495,]),'struct_declarator':([192,445,],[323,508,]),'type_qualifier':([0,1,4,21,27,35,52,53,55,59,63,75,85,87,89,93,95,99,103,117,118,128,129,172,174,177,181,184,185,186,192,205,206,211,219,220,229,231,233,239,267,278,282,298,313,315,342,350,422,427,459,460,514,515,],[52,52,80,52,52,105,52,52,52,52,52,52,105,52,80,52,105,105,198,105,52,105,52,198,105,279,52,105,105,105,279,198,105,80,198,105,105,105,105,105,105,52,105,52,105,105,52,52,52,52,105,52,198,105,]),'assignment_operator':([224,],[364,]),'expression':([174,181,229,231,233,258,265,290,298,307,427,429,430,434,437,440,441,499,502,533,535,537,538,539,549,553,566,569,574,577,],[270,294,270,270,270,399,406,426,294,294,294,294,501,503,294,294,507,294,294,294,294,294,556,294,564,294,294,294,294,294,]),'storage_class_specifier':([0,1,4,21,27,52,53,55,59,63,75,87,89,93,118,129,181,211,278,298,342,350,422,427,460,],[1,1,68,1,1,1,1,1,1,1,1,1,68,1,1,1,1,68,1,1,1,1,1,1,1,]),'unified_wstring_literal':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,]),'translation_unit_or_empty':([0,],[9,]),'initializer_list_opt':([227,],[370,]),'brace_close':([99,184,185,186,196,309,313,315,325,326,370,472,528,550,],[187,314,316,317,328,439,442,443,448,449,469,523,551,565,]),'direct_typeid_declarator':([4,69,72,89,126,192,202,445,],[73,73,127,73,73,73,73,73,]),'external_declaration':([0,59,],[16,123,]),'pragmacomp_or_statement':([307,429,440,502,535,537,539,569,574,577,],[436,500,506,536,554,555,557,576,578,579,]),'type_name':([85,95,174,229,231,233,239,267,],[157,183,271,379,380,381,382,410,]),'typedef_name':([0,21,40,59,75,85,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,]),'pppragma_directive':([0,59,99,181,184,185,186,298,307,313,315,429,437,440,502,535,537,539,569,574,577,],[25,25,189,300,189,189,189,300,437,189,189,437,300,437,437,437,437,437,437,437,437,]),'statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[301,301,438,438,505,438,438,438,438,558,438,438,438,]),'cast_expression':([85,116,131,171,174,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[158,158,158,268,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,487,158,158,158,158,158,158,158,158,158,158,487,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,]),'atomic_specifier':([0,1,21,27,40,52,53,55,59,63,75,85,87,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[27,63,87,63,111,63,63,63,27,63,87,111,63,111,87,111,111,27,27,111,111,87,111,111,111,111,111,111,111,111,111,27,87,111,111,27,27,27,87,27,]),'struct_declarator_list':([192,],[320,]),'empty':([0,1,4,21,27,35,40,52,53,55,63,75,87,89,91,117,118,128,129,177,181,192,204,206,211,218,220,227,278,282,298,307,342,419,421,422,427,429,437,440,459,460,472,488,499,502,513,515,533,535,537,539,550,553,566,569,574,577,],[57,64,83,88,64,106,115,64,64,64,64,88,64,83,115,106,208,106,208,277,306,321,337,106,277,337,106,377,415,106,433,433,415,337,337,415,433,433,433,433,106,208,522,522,433,433,337,106,433,433,433,433,522,433,433,433,433,433,]),'parameter_declaration':([118,129,278,342,350,422,460,],[210,210,210,210,463,210,210,]),'primary_expression':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,]),'declaration':([0,21,59,75,93,181,298,427,],[38,90,38,90,182,302,302,499,]),'declaration_specifiers_no_type':([0,1,21,27,52,53,55,59,63,75,87,93,118,129,181,278,298,342,350,422,427,460,],[40,67,91,67,67,67,67,40,67,91,67,91,214,214,91,214,91,214,214,214,91,214,]),'jump_statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[303,303,303,303,303,303,303,303,303,303,303,303,303,]),'enumerator_list':([102,193,194,],[196,325,326,]),'block_item':([181,298,],[305,432,]),'constant_expression':([85,116,297,319,329,373,447,],[159,203,431,444,451,471,509,]),'identifier_list_opt':([118,129,460,],[207,221,516,]),'constant':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,]),'type_specifier_no_typeid':([0,4,21,40,59,75,85,89,91,93,95,99,118,129,172,174,177,181,184,185,186,192,211,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[12,71,12,12,12,12,12,71,12,12,12,12,12,12,12,12,275,12,12,12,12,275,71,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,]),'struct_declaration':([99,184,185,186,313,315,],[190,190,190,318,318,318,]),'direct_typeid_noparen_declarator':([211,344,],[345,458,]),'id_declarator':([0,4,37,40,59,69,89,91,126,192,202,211,342,445,],[21,75,107,110,21,107,179,110,179,179,179,346,107,179,]),'selection_statement':([181,298,307,429,437,440,502,535,537,539,569,574,577,],[308,308,308,308,308,308,308,308,308,308,308,308,308,]),'postfix_expression':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,]),'initializer_list':([227,488,],[374,528,]),'unary_operator':([85,116,131,146,149,171,174,175,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,413,419,421,427,429,430,434,437,440,441,447,477,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,]),'struct_or_union':([0,21,40,59,75,85,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,]),'block_item_list_opt':([181,],[309,]),'assignment_expression':([131,174,181,201,204,218,229,231,233,258,265,266,290,298,307,338,339,353,354,364,375,412,419,421,427,429,430,434,437,440,441,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[228,272,272,228,335,335,272,272,272,272,272,408,272,272,272,455,456,466,467,468,228,486,335,335,272,272,272,272,272,272,272,525,272,272,335,228,272,272,272,272,272,561,562,272,272,272,272,272,272,]),'designation_opt':([227,472,488,550,],[375,521,375,521,]),'parameter_type_list':([118,129,278,342,422,460,],[209,222,416,416,416,517,]),'type_qualifier_list':([35,85,95,99,117,128,174,184,185,186,206,220,229,231,233,239,267,282,313,315,459,515,],[103,172,172,172,205,219,172,172,172,172,103,103,172,172,172,172,172,103,172,172,514,103,]),'designator':([227,376,472,488,550,],[371,474,371,371,371,]),'id_init_declarator_list_opt':([40,91,],[114,114,]),'declaration_specifiers':([0,21,59,75,93,118,129,181,278,298,342,350,422,427,460,],[4,89,4,89,89,211,211,89,211,89,211,211,211,89,211,]),'identifier_list':([118,129,460,],[212,212,212,]),'declaration_list_opt':([21,75,],[92,130,]),'function_definition':([0,59,],[45,45,]),'binary_expression':([85,116,131,174,181,201,204,218,229,231,233,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,419,421,427,429,430,434,437,440,441,447,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[162,162,162,162,162,162,162,162,162,162,162,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,162,400,401,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,]),'enum_specifier':([0,21,40,59,75,85,91,93,95,99,118,129,172,174,181,184,185,186,214,229,231,233,239,267,278,298,313,315,342,350,422,427,460,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'decl_body':([0,21,59,75,93,181,298,427,],[51,51,51,51,51,51,51,51,]),'function_specifier':([0,1,4,21,27,52,53,55,59,63,75,87,89,93,118,129,181,211,278,298,342,350,422,427,460,],[55,55,82,55,55,55,55,55,55,55,55,55,82,55,55,55,55,82,55,55,55,55,55,55,55,]),'specifier_qualifier_list':([85,95,99,174,184,185,186,229,231,233,239,267,313,315,],[177,177,192,177,192,192,192,177,177,177,177,177,192,192,]),'conditional_expression':([85,116,131,174,181,201,204,218,229,231,233,258,265,266,290,297,298,307,319,329,338,339,353,354,364,373,375,412,419,421,427,429,430,434,437,440,441,447,481,484,499,502,513,521,533,535,537,538,539,542,543,549,553,566,569,574,577,],[178,178,225,225,225,225,225,225,225,225,225,225,225,225,225,178,225,225,178,178,225,225,225,225,225,178,225,225,225,225,225,225,225,225,225,225,225,178,524,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> translation_unit_or_empty","S'",1,None,None,None), + ('abstract_declarator_opt -> empty','abstract_declarator_opt',1,'p_abstract_declarator_opt','plyparser.py',43), + ('abstract_declarator_opt -> abstract_declarator','abstract_declarator_opt',1,'p_abstract_declarator_opt','plyparser.py',44), + ('assignment_expression_opt -> empty','assignment_expression_opt',1,'p_assignment_expression_opt','plyparser.py',43), + ('assignment_expression_opt -> assignment_expression','assignment_expression_opt',1,'p_assignment_expression_opt','plyparser.py',44), + ('block_item_list_opt -> empty','block_item_list_opt',1,'p_block_item_list_opt','plyparser.py',43), + ('block_item_list_opt -> block_item_list','block_item_list_opt',1,'p_block_item_list_opt','plyparser.py',44), + ('declaration_list_opt -> empty','declaration_list_opt',1,'p_declaration_list_opt','plyparser.py',43), + ('declaration_list_opt -> declaration_list','declaration_list_opt',1,'p_declaration_list_opt','plyparser.py',44), + ('declaration_specifiers_no_type_opt -> empty','declaration_specifiers_no_type_opt',1,'p_declaration_specifiers_no_type_opt','plyparser.py',43), + ('declaration_specifiers_no_type_opt -> declaration_specifiers_no_type','declaration_specifiers_no_type_opt',1,'p_declaration_specifiers_no_type_opt','plyparser.py',44), + ('designation_opt -> empty','designation_opt',1,'p_designation_opt','plyparser.py',43), + ('designation_opt -> designation','designation_opt',1,'p_designation_opt','plyparser.py',44), + ('expression_opt -> empty','expression_opt',1,'p_expression_opt','plyparser.py',43), + ('expression_opt -> expression','expression_opt',1,'p_expression_opt','plyparser.py',44), + ('id_init_declarator_list_opt -> empty','id_init_declarator_list_opt',1,'p_id_init_declarator_list_opt','plyparser.py',43), + ('id_init_declarator_list_opt -> id_init_declarator_list','id_init_declarator_list_opt',1,'p_id_init_declarator_list_opt','plyparser.py',44), + ('identifier_list_opt -> empty','identifier_list_opt',1,'p_identifier_list_opt','plyparser.py',43), + ('identifier_list_opt -> identifier_list','identifier_list_opt',1,'p_identifier_list_opt','plyparser.py',44), + ('init_declarator_list_opt -> empty','init_declarator_list_opt',1,'p_init_declarator_list_opt','plyparser.py',43), + ('init_declarator_list_opt -> init_declarator_list','init_declarator_list_opt',1,'p_init_declarator_list_opt','plyparser.py',44), + ('initializer_list_opt -> empty','initializer_list_opt',1,'p_initializer_list_opt','plyparser.py',43), + ('initializer_list_opt -> initializer_list','initializer_list_opt',1,'p_initializer_list_opt','plyparser.py',44), + ('parameter_type_list_opt -> empty','parameter_type_list_opt',1,'p_parameter_type_list_opt','plyparser.py',43), + ('parameter_type_list_opt -> parameter_type_list','parameter_type_list_opt',1,'p_parameter_type_list_opt','plyparser.py',44), + ('struct_declarator_list_opt -> empty','struct_declarator_list_opt',1,'p_struct_declarator_list_opt','plyparser.py',43), + ('struct_declarator_list_opt -> struct_declarator_list','struct_declarator_list_opt',1,'p_struct_declarator_list_opt','plyparser.py',44), + ('type_qualifier_list_opt -> empty','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','plyparser.py',43), + ('type_qualifier_list_opt -> type_qualifier_list','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','plyparser.py',44), + ('direct_id_declarator -> ID','direct_id_declarator',1,'p_direct_id_declarator_1','plyparser.py',126), + ('direct_id_declarator -> LPAREN id_declarator RPAREN','direct_id_declarator',3,'p_direct_id_declarator_2','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_id_declarator',5,'p_direct_id_declarator_3','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_id_declarator',6,'p_direct_id_declarator_4','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_id_declarator',6,'p_direct_id_declarator_4','plyparser.py',127), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_id_declarator',5,'p_direct_id_declarator_5','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LPAREN parameter_type_list RPAREN','direct_id_declarator',4,'p_direct_id_declarator_6','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LPAREN identifier_list_opt RPAREN','direct_id_declarator',4,'p_direct_id_declarator_6','plyparser.py',127), + ('direct_typeid_declarator -> TYPEID','direct_typeid_declarator',1,'p_direct_typeid_declarator_1','plyparser.py',126), + ('direct_typeid_declarator -> LPAREN typeid_declarator RPAREN','direct_typeid_declarator',3,'p_direct_typeid_declarator_2','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_typeid_declarator',5,'p_direct_typeid_declarator_3','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_typeid_declarator',6,'p_direct_typeid_declarator_4','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_typeid_declarator',6,'p_direct_typeid_declarator_4','plyparser.py',127), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_typeid_declarator',5,'p_direct_typeid_declarator_5','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LPAREN parameter_type_list RPAREN','direct_typeid_declarator',4,'p_direct_typeid_declarator_6','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LPAREN identifier_list_opt RPAREN','direct_typeid_declarator',4,'p_direct_typeid_declarator_6','plyparser.py',127), + ('direct_typeid_noparen_declarator -> TYPEID','direct_typeid_noparen_declarator',1,'p_direct_typeid_noparen_declarator_1','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_typeid_noparen_declarator',5,'p_direct_typeid_noparen_declarator_3','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_typeid_noparen_declarator',6,'p_direct_typeid_noparen_declarator_4','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_typeid_noparen_declarator',6,'p_direct_typeid_noparen_declarator_4','plyparser.py',127), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_typeid_noparen_declarator',5,'p_direct_typeid_noparen_declarator_5','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LPAREN parameter_type_list RPAREN','direct_typeid_noparen_declarator',4,'p_direct_typeid_noparen_declarator_6','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LPAREN identifier_list_opt RPAREN','direct_typeid_noparen_declarator',4,'p_direct_typeid_noparen_declarator_6','plyparser.py',127), + ('id_declarator -> direct_id_declarator','id_declarator',1,'p_id_declarator_1','plyparser.py',126), + ('id_declarator -> pointer direct_id_declarator','id_declarator',2,'p_id_declarator_2','plyparser.py',126), + ('typeid_declarator -> direct_typeid_declarator','typeid_declarator',1,'p_typeid_declarator_1','plyparser.py',126), + ('typeid_declarator -> pointer direct_typeid_declarator','typeid_declarator',2,'p_typeid_declarator_2','plyparser.py',126), + ('typeid_noparen_declarator -> direct_typeid_noparen_declarator','typeid_noparen_declarator',1,'p_typeid_noparen_declarator_1','plyparser.py',126), + ('typeid_noparen_declarator -> pointer direct_typeid_noparen_declarator','typeid_noparen_declarator',2,'p_typeid_noparen_declarator_2','plyparser.py',126), + ('translation_unit_or_empty -> translation_unit','translation_unit_or_empty',1,'p_translation_unit_or_empty','c_parser.py',509), + ('translation_unit_or_empty -> empty','translation_unit_or_empty',1,'p_translation_unit_or_empty','c_parser.py',510), + ('translation_unit -> external_declaration','translation_unit',1,'p_translation_unit_1','c_parser.py',518), + ('translation_unit -> translation_unit external_declaration','translation_unit',2,'p_translation_unit_2','c_parser.py',524), + ('external_declaration -> function_definition','external_declaration',1,'p_external_declaration_1','c_parser.py',534), + ('external_declaration -> declaration','external_declaration',1,'p_external_declaration_2','c_parser.py',539), + ('external_declaration -> pp_directive','external_declaration',1,'p_external_declaration_3','c_parser.py',544), + ('external_declaration -> pppragma_directive','external_declaration',1,'p_external_declaration_3','c_parser.py',545), + ('external_declaration -> SEMI','external_declaration',1,'p_external_declaration_4','c_parser.py',550), + ('external_declaration -> static_assert','external_declaration',1,'p_external_declaration_5','c_parser.py',555), + ('static_assert -> _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN','static_assert',6,'p_static_assert_declaration','c_parser.py',560), + ('static_assert -> _STATIC_ASSERT LPAREN constant_expression RPAREN','static_assert',4,'p_static_assert_declaration','c_parser.py',561), + ('pp_directive -> PPHASH','pp_directive',1,'p_pp_directive','c_parser.py',569), + ('pppragma_directive -> PPPRAGMA','pppragma_directive',1,'p_pppragma_directive','c_parser.py',575), + ('pppragma_directive -> PPPRAGMA PPPRAGMASTR','pppragma_directive',2,'p_pppragma_directive','c_parser.py',576), + ('function_definition -> id_declarator declaration_list_opt compound_statement','function_definition',3,'p_function_definition_1','c_parser.py',586), + ('function_definition -> declaration_specifiers id_declarator declaration_list_opt compound_statement','function_definition',4,'p_function_definition_2','c_parser.py',604), + ('statement -> labeled_statement','statement',1,'p_statement','c_parser.py',619), + ('statement -> expression_statement','statement',1,'p_statement','c_parser.py',620), + ('statement -> compound_statement','statement',1,'p_statement','c_parser.py',621), + ('statement -> selection_statement','statement',1,'p_statement','c_parser.py',622), + ('statement -> iteration_statement','statement',1,'p_statement','c_parser.py',623), + ('statement -> jump_statement','statement',1,'p_statement','c_parser.py',624), + ('statement -> pppragma_directive','statement',1,'p_statement','c_parser.py',625), + ('statement -> static_assert','statement',1,'p_statement','c_parser.py',626), + ('pragmacomp_or_statement -> pppragma_directive statement','pragmacomp_or_statement',2,'p_pragmacomp_or_statement','c_parser.py',674), + ('pragmacomp_or_statement -> statement','pragmacomp_or_statement',1,'p_pragmacomp_or_statement','c_parser.py',675), + ('decl_body -> declaration_specifiers init_declarator_list_opt','decl_body',2,'p_decl_body','c_parser.py',694), + ('decl_body -> declaration_specifiers_no_type id_init_declarator_list_opt','decl_body',2,'p_decl_body','c_parser.py',695), + ('declaration -> decl_body SEMI','declaration',2,'p_declaration','c_parser.py',755), + ('declaration_list -> declaration','declaration_list',1,'p_declaration_list','c_parser.py',764), + ('declaration_list -> declaration_list declaration','declaration_list',2,'p_declaration_list','c_parser.py',765), + ('declaration_specifiers_no_type -> type_qualifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_1','c_parser.py',775), + ('declaration_specifiers_no_type -> storage_class_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_2','c_parser.py',780), + ('declaration_specifiers_no_type -> function_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_3','c_parser.py',785), + ('declaration_specifiers_no_type -> atomic_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_4','c_parser.py',792), + ('declaration_specifiers_no_type -> alignment_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_5','c_parser.py',797), + ('declaration_specifiers -> declaration_specifiers type_qualifier','declaration_specifiers',2,'p_declaration_specifiers_1','c_parser.py',802), + ('declaration_specifiers -> declaration_specifiers storage_class_specifier','declaration_specifiers',2,'p_declaration_specifiers_2','c_parser.py',807), + ('declaration_specifiers -> declaration_specifiers function_specifier','declaration_specifiers',2,'p_declaration_specifiers_3','c_parser.py',812), + ('declaration_specifiers -> declaration_specifiers type_specifier_no_typeid','declaration_specifiers',2,'p_declaration_specifiers_4','c_parser.py',817), + ('declaration_specifiers -> type_specifier','declaration_specifiers',1,'p_declaration_specifiers_5','c_parser.py',822), + ('declaration_specifiers -> declaration_specifiers_no_type type_specifier','declaration_specifiers',2,'p_declaration_specifiers_6','c_parser.py',827), + ('declaration_specifiers -> declaration_specifiers alignment_specifier','declaration_specifiers',2,'p_declaration_specifiers_7','c_parser.py',832), + ('storage_class_specifier -> AUTO','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',837), + ('storage_class_specifier -> REGISTER','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',838), + ('storage_class_specifier -> STATIC','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',839), + ('storage_class_specifier -> EXTERN','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',840), + ('storage_class_specifier -> TYPEDEF','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',841), + ('storage_class_specifier -> _THREAD_LOCAL','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',842), + ('function_specifier -> INLINE','function_specifier',1,'p_function_specifier','c_parser.py',847), + ('function_specifier -> _NORETURN','function_specifier',1,'p_function_specifier','c_parser.py',848), + ('type_specifier_no_typeid -> VOID','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',853), + ('type_specifier_no_typeid -> _BOOL','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',854), + ('type_specifier_no_typeid -> CHAR','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',855), + ('type_specifier_no_typeid -> SHORT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',856), + ('type_specifier_no_typeid -> INT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',857), + ('type_specifier_no_typeid -> LONG','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',858), + ('type_specifier_no_typeid -> FLOAT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',859), + ('type_specifier_no_typeid -> DOUBLE','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',860), + ('type_specifier_no_typeid -> _COMPLEX','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',861), + ('type_specifier_no_typeid -> SIGNED','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',862), + ('type_specifier_no_typeid -> UNSIGNED','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',863), + ('type_specifier_no_typeid -> __INT128','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',864), + ('type_specifier -> typedef_name','type_specifier',1,'p_type_specifier','c_parser.py',869), + ('type_specifier -> enum_specifier','type_specifier',1,'p_type_specifier','c_parser.py',870), + ('type_specifier -> struct_or_union_specifier','type_specifier',1,'p_type_specifier','c_parser.py',871), + ('type_specifier -> type_specifier_no_typeid','type_specifier',1,'p_type_specifier','c_parser.py',872), + ('type_specifier -> atomic_specifier','type_specifier',1,'p_type_specifier','c_parser.py',873), + ('atomic_specifier -> _ATOMIC LPAREN type_name RPAREN','atomic_specifier',4,'p_atomic_specifier','c_parser.py',879), + ('type_qualifier -> CONST','type_qualifier',1,'p_type_qualifier','c_parser.py',886), + ('type_qualifier -> RESTRICT','type_qualifier',1,'p_type_qualifier','c_parser.py',887), + ('type_qualifier -> VOLATILE','type_qualifier',1,'p_type_qualifier','c_parser.py',888), + ('type_qualifier -> _ATOMIC','type_qualifier',1,'p_type_qualifier','c_parser.py',889), + ('init_declarator_list -> init_declarator','init_declarator_list',1,'p_init_declarator_list','c_parser.py',894), + ('init_declarator_list -> init_declarator_list COMMA init_declarator','init_declarator_list',3,'p_init_declarator_list','c_parser.py',895), + ('init_declarator -> declarator','init_declarator',1,'p_init_declarator','c_parser.py',903), + ('init_declarator -> declarator EQUALS initializer','init_declarator',3,'p_init_declarator','c_parser.py',904), + ('id_init_declarator_list -> id_init_declarator','id_init_declarator_list',1,'p_id_init_declarator_list','c_parser.py',909), + ('id_init_declarator_list -> id_init_declarator_list COMMA init_declarator','id_init_declarator_list',3,'p_id_init_declarator_list','c_parser.py',910), + ('id_init_declarator -> id_declarator','id_init_declarator',1,'p_id_init_declarator','c_parser.py',915), + ('id_init_declarator -> id_declarator EQUALS initializer','id_init_declarator',3,'p_id_init_declarator','c_parser.py',916), + ('specifier_qualifier_list -> specifier_qualifier_list type_specifier_no_typeid','specifier_qualifier_list',2,'p_specifier_qualifier_list_1','c_parser.py',923), + ('specifier_qualifier_list -> specifier_qualifier_list type_qualifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_2','c_parser.py',928), + ('specifier_qualifier_list -> type_specifier','specifier_qualifier_list',1,'p_specifier_qualifier_list_3','c_parser.py',933), + ('specifier_qualifier_list -> type_qualifier_list type_specifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_4','c_parser.py',938), + ('specifier_qualifier_list -> alignment_specifier','specifier_qualifier_list',1,'p_specifier_qualifier_list_5','c_parser.py',943), + ('specifier_qualifier_list -> specifier_qualifier_list alignment_specifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_6','c_parser.py',948), + ('struct_or_union_specifier -> struct_or_union ID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','c_parser.py',956), + ('struct_or_union_specifier -> struct_or_union TYPEID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','c_parser.py',957), + ('struct_or_union_specifier -> struct_or_union brace_open struct_declaration_list brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_2','c_parser.py',967), + ('struct_or_union_specifier -> struct_or_union brace_open brace_close','struct_or_union_specifier',3,'p_struct_or_union_specifier_2','c_parser.py',968), + ('struct_or_union_specifier -> struct_or_union ID brace_open struct_declaration_list brace_close','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','c_parser.py',985), + ('struct_or_union_specifier -> struct_or_union ID brace_open brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_3','c_parser.py',986), + ('struct_or_union_specifier -> struct_or_union TYPEID brace_open struct_declaration_list brace_close','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','c_parser.py',987), + ('struct_or_union_specifier -> struct_or_union TYPEID brace_open brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_3','c_parser.py',988), + ('struct_or_union -> STRUCT','struct_or_union',1,'p_struct_or_union','c_parser.py',1004), + ('struct_or_union -> UNION','struct_or_union',1,'p_struct_or_union','c_parser.py',1005), + ('struct_declaration_list -> struct_declaration','struct_declaration_list',1,'p_struct_declaration_list','c_parser.py',1012), + ('struct_declaration_list -> struct_declaration_list struct_declaration','struct_declaration_list',2,'p_struct_declaration_list','c_parser.py',1013), + ('struct_declaration -> specifier_qualifier_list struct_declarator_list_opt SEMI','struct_declaration',3,'p_struct_declaration_1','c_parser.py',1021), + ('struct_declaration -> SEMI','struct_declaration',1,'p_struct_declaration_2','c_parser.py',1059), + ('struct_declaration -> pppragma_directive','struct_declaration',1,'p_struct_declaration_3','c_parser.py',1064), + ('struct_declarator_list -> struct_declarator','struct_declarator_list',1,'p_struct_declarator_list','c_parser.py',1069), + ('struct_declarator_list -> struct_declarator_list COMMA struct_declarator','struct_declarator_list',3,'p_struct_declarator_list','c_parser.py',1070), + ('struct_declarator -> declarator','struct_declarator',1,'p_struct_declarator_1','c_parser.py',1078), + ('struct_declarator -> declarator COLON constant_expression','struct_declarator',3,'p_struct_declarator_2','c_parser.py',1083), + ('struct_declarator -> COLON constant_expression','struct_declarator',2,'p_struct_declarator_2','c_parser.py',1084), + ('enum_specifier -> ENUM ID','enum_specifier',2,'p_enum_specifier_1','c_parser.py',1092), + ('enum_specifier -> ENUM TYPEID','enum_specifier',2,'p_enum_specifier_1','c_parser.py',1093), + ('enum_specifier -> ENUM brace_open enumerator_list brace_close','enum_specifier',4,'p_enum_specifier_2','c_parser.py',1098), + ('enum_specifier -> ENUM ID brace_open enumerator_list brace_close','enum_specifier',5,'p_enum_specifier_3','c_parser.py',1103), + ('enum_specifier -> ENUM TYPEID brace_open enumerator_list brace_close','enum_specifier',5,'p_enum_specifier_3','c_parser.py',1104), + ('enumerator_list -> enumerator','enumerator_list',1,'p_enumerator_list','c_parser.py',1109), + ('enumerator_list -> enumerator_list COMMA','enumerator_list',2,'p_enumerator_list','c_parser.py',1110), + ('enumerator_list -> enumerator_list COMMA enumerator','enumerator_list',3,'p_enumerator_list','c_parser.py',1111), + ('alignment_specifier -> _ALIGNAS LPAREN type_name RPAREN','alignment_specifier',4,'p_alignment_specifier','c_parser.py',1122), + ('alignment_specifier -> _ALIGNAS LPAREN constant_expression RPAREN','alignment_specifier',4,'p_alignment_specifier','c_parser.py',1123), + ('enumerator -> ID','enumerator',1,'p_enumerator','c_parser.py',1128), + ('enumerator -> ID EQUALS constant_expression','enumerator',3,'p_enumerator','c_parser.py',1129), + ('declarator -> id_declarator','declarator',1,'p_declarator','c_parser.py',1144), + ('declarator -> typeid_declarator','declarator',1,'p_declarator','c_parser.py',1145), + ('pointer -> TIMES type_qualifier_list_opt','pointer',2,'p_pointer','c_parser.py',1257), + ('pointer -> TIMES type_qualifier_list_opt pointer','pointer',3,'p_pointer','c_parser.py',1258), + ('type_qualifier_list -> type_qualifier','type_qualifier_list',1,'p_type_qualifier_list','c_parser.py',1287), + ('type_qualifier_list -> type_qualifier_list type_qualifier','type_qualifier_list',2,'p_type_qualifier_list','c_parser.py',1288), + ('parameter_type_list -> parameter_list','parameter_type_list',1,'p_parameter_type_list','c_parser.py',1293), + ('parameter_type_list -> parameter_list COMMA ELLIPSIS','parameter_type_list',3,'p_parameter_type_list','c_parser.py',1294), + ('parameter_list -> parameter_declaration','parameter_list',1,'p_parameter_list','c_parser.py',1302), + ('parameter_list -> parameter_list COMMA parameter_declaration','parameter_list',3,'p_parameter_list','c_parser.py',1303), + ('parameter_declaration -> declaration_specifiers id_declarator','parameter_declaration',2,'p_parameter_declaration_1','c_parser.py',1322), + ('parameter_declaration -> declaration_specifiers typeid_noparen_declarator','parameter_declaration',2,'p_parameter_declaration_1','c_parser.py',1323), + ('parameter_declaration -> declaration_specifiers abstract_declarator_opt','parameter_declaration',2,'p_parameter_declaration_2','c_parser.py',1334), + ('identifier_list -> identifier','identifier_list',1,'p_identifier_list','c_parser.py',1366), + ('identifier_list -> identifier_list COMMA identifier','identifier_list',3,'p_identifier_list','c_parser.py',1367), + ('initializer -> assignment_expression','initializer',1,'p_initializer_1','c_parser.py',1376), + ('initializer -> brace_open initializer_list_opt brace_close','initializer',3,'p_initializer_2','c_parser.py',1381), + ('initializer -> brace_open initializer_list COMMA brace_close','initializer',4,'p_initializer_2','c_parser.py',1382), + ('initializer_list -> designation_opt initializer','initializer_list',2,'p_initializer_list','c_parser.py',1390), + ('initializer_list -> initializer_list COMMA designation_opt initializer','initializer_list',4,'p_initializer_list','c_parser.py',1391), + ('designation -> designator_list EQUALS','designation',2,'p_designation','c_parser.py',1402), + ('designator_list -> designator','designator_list',1,'p_designator_list','c_parser.py',1410), + ('designator_list -> designator_list designator','designator_list',2,'p_designator_list','c_parser.py',1411), + ('designator -> LBRACKET constant_expression RBRACKET','designator',3,'p_designator','c_parser.py',1416), + ('designator -> PERIOD identifier','designator',2,'p_designator','c_parser.py',1417), + ('type_name -> specifier_qualifier_list abstract_declarator_opt','type_name',2,'p_type_name','c_parser.py',1422), + ('abstract_declarator -> pointer','abstract_declarator',1,'p_abstract_declarator_1','c_parser.py',1434), + ('abstract_declarator -> pointer direct_abstract_declarator','abstract_declarator',2,'p_abstract_declarator_2','c_parser.py',1442), + ('abstract_declarator -> direct_abstract_declarator','abstract_declarator',1,'p_abstract_declarator_3','c_parser.py',1447), + ('direct_abstract_declarator -> LPAREN abstract_declarator RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_1','c_parser.py',1457), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_2','c_parser.py',1461), + ('direct_abstract_declarator -> LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_3','c_parser.py',1472), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET TIMES RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_4','c_parser.py',1482), + ('direct_abstract_declarator -> LBRACKET TIMES RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator_5','c_parser.py',1493), + ('direct_abstract_declarator -> direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator_6','c_parser.py',1502), + ('direct_abstract_declarator -> LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_7','c_parser.py',1512), + ('block_item -> declaration','block_item',1,'p_block_item','c_parser.py',1523), + ('block_item -> statement','block_item',1,'p_block_item','c_parser.py',1524), + ('block_item_list -> block_item','block_item_list',1,'p_block_item_list','c_parser.py',1531), + ('block_item_list -> block_item_list block_item','block_item_list',2,'p_block_item_list','c_parser.py',1532), + ('compound_statement -> brace_open block_item_list_opt brace_close','compound_statement',3,'p_compound_statement_1','c_parser.py',1538), + ('labeled_statement -> ID COLON pragmacomp_or_statement','labeled_statement',3,'p_labeled_statement_1','c_parser.py',1544), + ('labeled_statement -> CASE constant_expression COLON pragmacomp_or_statement','labeled_statement',4,'p_labeled_statement_2','c_parser.py',1548), + ('labeled_statement -> DEFAULT COLON pragmacomp_or_statement','labeled_statement',3,'p_labeled_statement_3','c_parser.py',1552), + ('selection_statement -> IF LPAREN expression RPAREN pragmacomp_or_statement','selection_statement',5,'p_selection_statement_1','c_parser.py',1556), + ('selection_statement -> IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement','selection_statement',7,'p_selection_statement_2','c_parser.py',1560), + ('selection_statement -> SWITCH LPAREN expression RPAREN pragmacomp_or_statement','selection_statement',5,'p_selection_statement_3','c_parser.py',1564), + ('iteration_statement -> WHILE LPAREN expression RPAREN pragmacomp_or_statement','iteration_statement',5,'p_iteration_statement_1','c_parser.py',1569), + ('iteration_statement -> DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI','iteration_statement',7,'p_iteration_statement_2','c_parser.py',1573), + ('iteration_statement -> FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement','iteration_statement',9,'p_iteration_statement_3','c_parser.py',1577), + ('iteration_statement -> FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement','iteration_statement',8,'p_iteration_statement_4','c_parser.py',1581), + ('jump_statement -> GOTO ID SEMI','jump_statement',3,'p_jump_statement_1','c_parser.py',1586), + ('jump_statement -> BREAK SEMI','jump_statement',2,'p_jump_statement_2','c_parser.py',1590), + ('jump_statement -> CONTINUE SEMI','jump_statement',2,'p_jump_statement_3','c_parser.py',1594), + ('jump_statement -> RETURN expression SEMI','jump_statement',3,'p_jump_statement_4','c_parser.py',1598), + ('jump_statement -> RETURN SEMI','jump_statement',2,'p_jump_statement_4','c_parser.py',1599), + ('expression_statement -> expression_opt SEMI','expression_statement',2,'p_expression_statement','c_parser.py',1604), + ('expression -> assignment_expression','expression',1,'p_expression','c_parser.py',1611), + ('expression -> expression COMMA assignment_expression','expression',3,'p_expression','c_parser.py',1612), + ('assignment_expression -> LPAREN compound_statement RPAREN','assignment_expression',3,'p_parenthesized_compound_expression','c_parser.py',1624), + ('typedef_name -> TYPEID','typedef_name',1,'p_typedef_name','c_parser.py',1628), + ('assignment_expression -> conditional_expression','assignment_expression',1,'p_assignment_expression','c_parser.py',1632), + ('assignment_expression -> unary_expression assignment_operator assignment_expression','assignment_expression',3,'p_assignment_expression','c_parser.py',1633), + ('assignment_operator -> EQUALS','assignment_operator',1,'p_assignment_operator','c_parser.py',1646), + ('assignment_operator -> XOREQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1647), + ('assignment_operator -> TIMESEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1648), + ('assignment_operator -> DIVEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1649), + ('assignment_operator -> MODEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1650), + ('assignment_operator -> PLUSEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1651), + ('assignment_operator -> MINUSEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1652), + ('assignment_operator -> LSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1653), + ('assignment_operator -> RSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1654), + ('assignment_operator -> ANDEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1655), + ('assignment_operator -> OREQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1656), + ('constant_expression -> conditional_expression','constant_expression',1,'p_constant_expression','c_parser.py',1661), + ('conditional_expression -> binary_expression','conditional_expression',1,'p_conditional_expression','c_parser.py',1665), + ('conditional_expression -> binary_expression CONDOP expression COLON conditional_expression','conditional_expression',5,'p_conditional_expression','c_parser.py',1666), + ('binary_expression -> cast_expression','binary_expression',1,'p_binary_expression','c_parser.py',1674), + ('binary_expression -> binary_expression TIMES binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1675), + ('binary_expression -> binary_expression DIVIDE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1676), + ('binary_expression -> binary_expression MOD binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1677), + ('binary_expression -> binary_expression PLUS binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1678), + ('binary_expression -> binary_expression MINUS binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1679), + ('binary_expression -> binary_expression RSHIFT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1680), + ('binary_expression -> binary_expression LSHIFT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1681), + ('binary_expression -> binary_expression LT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1682), + ('binary_expression -> binary_expression LE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1683), + ('binary_expression -> binary_expression GE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1684), + ('binary_expression -> binary_expression GT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1685), + ('binary_expression -> binary_expression EQ binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1686), + ('binary_expression -> binary_expression NE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1687), + ('binary_expression -> binary_expression AND binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1688), + ('binary_expression -> binary_expression OR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1689), + ('binary_expression -> binary_expression XOR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1690), + ('binary_expression -> binary_expression LAND binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1691), + ('binary_expression -> binary_expression LOR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1692), + ('cast_expression -> unary_expression','cast_expression',1,'p_cast_expression_1','c_parser.py',1700), + ('cast_expression -> LPAREN type_name RPAREN cast_expression','cast_expression',4,'p_cast_expression_2','c_parser.py',1704), + ('unary_expression -> postfix_expression','unary_expression',1,'p_unary_expression_1','c_parser.py',1708), + ('unary_expression -> PLUSPLUS unary_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1712), + ('unary_expression -> MINUSMINUS unary_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1713), + ('unary_expression -> unary_operator cast_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1714), + ('unary_expression -> SIZEOF unary_expression','unary_expression',2,'p_unary_expression_3','c_parser.py',1719), + ('unary_expression -> SIZEOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression_3','c_parser.py',1720), + ('unary_expression -> _ALIGNOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression_3','c_parser.py',1721), + ('unary_operator -> AND','unary_operator',1,'p_unary_operator','c_parser.py',1729), + ('unary_operator -> TIMES','unary_operator',1,'p_unary_operator','c_parser.py',1730), + ('unary_operator -> PLUS','unary_operator',1,'p_unary_operator','c_parser.py',1731), + ('unary_operator -> MINUS','unary_operator',1,'p_unary_operator','c_parser.py',1732), + ('unary_operator -> NOT','unary_operator',1,'p_unary_operator','c_parser.py',1733), + ('unary_operator -> LNOT','unary_operator',1,'p_unary_operator','c_parser.py',1734), + ('postfix_expression -> primary_expression','postfix_expression',1,'p_postfix_expression_1','c_parser.py',1739), + ('postfix_expression -> postfix_expression LBRACKET expression RBRACKET','postfix_expression',4,'p_postfix_expression_2','c_parser.py',1743), + ('postfix_expression -> postfix_expression LPAREN argument_expression_list RPAREN','postfix_expression',4,'p_postfix_expression_3','c_parser.py',1747), + ('postfix_expression -> postfix_expression LPAREN RPAREN','postfix_expression',3,'p_postfix_expression_3','c_parser.py',1748), + ('postfix_expression -> postfix_expression PERIOD ID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1753), + ('postfix_expression -> postfix_expression PERIOD TYPEID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1754), + ('postfix_expression -> postfix_expression ARROW ID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1755), + ('postfix_expression -> postfix_expression ARROW TYPEID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1756), + ('postfix_expression -> postfix_expression PLUSPLUS','postfix_expression',2,'p_postfix_expression_5','c_parser.py',1762), + ('postfix_expression -> postfix_expression MINUSMINUS','postfix_expression',2,'p_postfix_expression_5','c_parser.py',1763), + ('postfix_expression -> LPAREN type_name RPAREN brace_open initializer_list brace_close','postfix_expression',6,'p_postfix_expression_6','c_parser.py',1768), + ('postfix_expression -> LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close','postfix_expression',7,'p_postfix_expression_6','c_parser.py',1769), + ('primary_expression -> identifier','primary_expression',1,'p_primary_expression_1','c_parser.py',1774), + ('primary_expression -> constant','primary_expression',1,'p_primary_expression_2','c_parser.py',1778), + ('primary_expression -> unified_string_literal','primary_expression',1,'p_primary_expression_3','c_parser.py',1782), + ('primary_expression -> unified_wstring_literal','primary_expression',1,'p_primary_expression_3','c_parser.py',1783), + ('primary_expression -> LPAREN expression RPAREN','primary_expression',3,'p_primary_expression_4','c_parser.py',1788), + ('primary_expression -> OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN','primary_expression',6,'p_primary_expression_5','c_parser.py',1792), + ('offsetof_member_designator -> identifier','offsetof_member_designator',1,'p_offsetof_member_designator','c_parser.py',1800), + ('offsetof_member_designator -> offsetof_member_designator PERIOD identifier','offsetof_member_designator',3,'p_offsetof_member_designator','c_parser.py',1801), + ('offsetof_member_designator -> offsetof_member_designator LBRACKET expression RBRACKET','offsetof_member_designator',4,'p_offsetof_member_designator','c_parser.py',1802), + ('argument_expression_list -> assignment_expression','argument_expression_list',1,'p_argument_expression_list','c_parser.py',1814), + ('argument_expression_list -> argument_expression_list COMMA assignment_expression','argument_expression_list',3,'p_argument_expression_list','c_parser.py',1815), + ('identifier -> ID','identifier',1,'p_identifier','c_parser.py',1824), + ('constant -> INT_CONST_DEC','constant',1,'p_constant_1','c_parser.py',1828), + ('constant -> INT_CONST_OCT','constant',1,'p_constant_1','c_parser.py',1829), + ('constant -> INT_CONST_HEX','constant',1,'p_constant_1','c_parser.py',1830), + ('constant -> INT_CONST_BIN','constant',1,'p_constant_1','c_parser.py',1831), + ('constant -> INT_CONST_CHAR','constant',1,'p_constant_1','c_parser.py',1832), + ('constant -> FLOAT_CONST','constant',1,'p_constant_2','c_parser.py',1851), + ('constant -> HEX_FLOAT_CONST','constant',1,'p_constant_2','c_parser.py',1852), + ('constant -> CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1868), + ('constant -> WCHAR_CONST','constant',1,'p_constant_3','c_parser.py',1869), + ('constant -> U8CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1870), + ('constant -> U16CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1871), + ('constant -> U32CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1872), + ('unified_string_literal -> STRING_LITERAL','unified_string_literal',1,'p_unified_string_literal','c_parser.py',1883), + ('unified_string_literal -> unified_string_literal STRING_LITERAL','unified_string_literal',2,'p_unified_string_literal','c_parser.py',1884), + ('unified_wstring_literal -> WSTRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1894), + ('unified_wstring_literal -> U8STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1895), + ('unified_wstring_literal -> U16STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1896), + ('unified_wstring_literal -> U32STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1897), + ('unified_wstring_literal -> unified_wstring_literal WSTRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1898), + ('unified_wstring_literal -> unified_wstring_literal U8STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1899), + ('unified_wstring_literal -> unified_wstring_literal U16STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1900), + ('unified_wstring_literal -> unified_wstring_literal U32STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1901), + ('brace_open -> LBRACE','brace_open',1,'p_brace_open','c_parser.py',1911), + ('brace_close -> RBRACE','brace_close',1,'p_brace_close','c_parser.py',1917), + ('empty -> <empty>','empty',0,'p_empty','c_parser.py',1923), +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..8cf666ffd3713069eb720cd7089a900b05ba674c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/METADATA @@ -0,0 +1,35 @@ +Metadata-Version: 2.1 +Name: python3-openid +Version: 3.2.0 +Summary: OpenID support for modern servers and consumers. +Home-page: http://github.com/necaris/python3-openid +Author: Rami Chowdhury +Author-email: rami.chowdhury@gmail.com +Maintainer: Rami Chowdhury +Maintainer-email: rami.chowdhury@gmail.com +License: UNKNOWN +Download-URL: http://github.com/necaris/python3-openid/tarball/v3.2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Systems Administration :: Authentication/Directory +Requires-Dist: defusedxml +Provides-Extra: mysql +Requires-Dist: mysql-connector-python ; extra == 'mysql' +Provides-Extra: postgresql +Requires-Dist: psycopg2 ; extra == 'postgresql' + +This is a set of Python packages to support use of +the OpenID decentralized identity system in your application, update to Python +3. Want to enable single sign-on for your web site? Use the openid.consumer +package. Want to run your own OpenID server? Check out openid.server. +Includes example code and support for a variety of storage back-ends. + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..7034e91078e4548d644781fc73c67ee7ec8f3145 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/RECORD @@ -0,0 +1,90 @@ +openid/__init__.py,sha256=9L08LPKwSLBoPCuialypPgFCXtifpT4ZiWq625Z8R5M,1372 +openid/__pycache__/__init__.cpython-310.pyc,, +openid/__pycache__/association.cpython-310.pyc,, +openid/__pycache__/codecutil.cpython-310.pyc,, +openid/__pycache__/cryptutil.cpython-310.pyc,, +openid/__pycache__/dh.cpython-310.pyc,, +openid/__pycache__/extension.cpython-310.pyc,, +openid/__pycache__/fetchers.cpython-310.pyc,, +openid/__pycache__/kvform.cpython-310.pyc,, +openid/__pycache__/message.cpython-310.pyc,, +openid/__pycache__/oidutil.cpython-310.pyc,, +openid/__pycache__/sreg.cpython-310.pyc,, +openid/__pycache__/urinorm.cpython-310.pyc,, +openid/association.py,sha256=EtzgGrDU9ZXdKFQ0Eaz0UnjQqUhXij4jMAxmHfUKUSQ,18302 +openid/codecutil.py,sha256=bWgdiLm5OgQieZaUQmjGMo4hQfmqnSGQJG6CE6m4biA,2280 +openid/consumer/__init__.py,sha256=TW-dGFLas2ZO41A9JGvb0vSrU6z5UO7Sq2xr37pGSlo,142 +openid/consumer/__pycache__/__init__.cpython-310.pyc,, +openid/consumer/__pycache__/consumer.cpython-310.pyc,, +openid/consumer/__pycache__/discover.cpython-310.pyc,, +openid/consumer/__pycache__/html_parse.cpython-310.pyc,, +openid/consumer/consumer.py,sha256=3rOmiGntpz4vp2lLJDnEyWv1Br-epQHTXDznQpG1z2A,76766 +openid/consumer/discover.py,sha256=L1nH008dDY_fuL0hO_zhdBemfvDmIlcgncz1g_2EGnA,16174 +openid/consumer/html_parse.py,sha256=oqics5256UlovEJoblMr1Z2ZjGihDkh5LgdOn42Gjyw,7996 +openid/cryptutil.py,sha256=7Ihf8WZgEHsk_LXnc4220Fcv6YfwCabTH31E0aDUnWk,3722 +openid/dh.py,sha256=GbGSU1O7ANSG-YThasrCpk92n6zKY-4Wife24RTCFpQ,1657 +openid/extension.py,sha256=IA8_5rzFhT9QepV5Me30U_DTDdsTV8iiXtvao34wlAk,1696 +openid/extensions/__init__.py,sha256=vkdH77CGmBqhefhsLbq0VYQMZRcYcA8U9IYNxlYVgPA,117 +openid/extensions/__pycache__/__init__.cpython-310.pyc,, +openid/extensions/__pycache__/ax.cpython-310.pyc,, +openid/extensions/__pycache__/sreg.cpython-310.pyc,, +openid/extensions/ax.py,sha256=xZzE5s_Zwrvc53FUwsabA0zlfUyqEL_zxCDLyxFs9_k,26629 +openid/extensions/draft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +openid/extensions/draft/__pycache__/__init__.cpython-310.pyc,, +openid/extensions/draft/__pycache__/pape2.cpython-310.pyc,, +openid/extensions/draft/__pycache__/pape5.cpython-310.pyc,, +openid/extensions/draft/pape2.py,sha256=TDjmQZ_1CyTJ_fbo3vJo1Y3YP4XKMyFTNLwtKQCA-bM,9485 +openid/extensions/draft/pape5.py,sha256=oIrAXznl64_MXIeI-j9QkbfMx_akYFPlXRkJGKooqdU,16509 +openid/extensions/sreg.py,sha256=sMhwXq8PMpoCLqY-tgJi65ghc6dmQFvDy0W6aG6AzsM,17876 +openid/fetchers.py,sha256=vbn5Y-n6hp8F4mcRPajBCWK75CrUhnkDK4QjpaA2078,15881 +openid/kvform.py,sha256=MYp5fWtBVzNsIjogvCXchahblr1XHP-3L96rxYhW04k,3332 +openid/message.py,sha256=jdtlE43Jc-1oKMiAai5IxNjr6S_BPFEDg_b_qG5u580,22680 +openid/oidutil.py,sha256=lpm_c0ZaCgqUJQpoycCLzeD3aKv_d9jYs2KyJXBi_C0,6601 +openid/server/__init__.py,sha256=KpYvxlPdF0VZoaDO85sFUjRYt3xeMZKiMO20WdPoOZ4,169 +openid/server/__pycache__/__init__.cpython-310.pyc,, +openid/server/__pycache__/server.cpython-310.pyc,, +openid/server/__pycache__/trustroot.cpython-310.pyc,, +openid/server/server.py,sha256=jZiAX2Ietw4Fc33FVWNLbl_wjo0BCBO-GAHFNwTyidQ,65609 +openid/server/trustroot.py,sha256=KfCeNS1yd8WOEKKbc8aLRIqq-pgvDLrgn4T56hv-k4U,14423 +openid/sreg.py,sha256=rM-x49cP8eA2mXDmmby43oIjT4bmY5LoS9zkmQAkdrk,195 +openid/store/__init__.py,sha256=ZX1xkoa8XahEYQkUJNIdowhorpaeBlj33aILTfXOUYY,215 +openid/store/__pycache__/__init__.cpython-310.pyc,, +openid/store/__pycache__/filestore.cpython-310.pyc,, +openid/store/__pycache__/interface.cpython-310.pyc,, +openid/store/__pycache__/memstore.cpython-310.pyc,, +openid/store/__pycache__/nonce.cpython-310.pyc,, +openid/store/__pycache__/sqlstore.cpython-310.pyc,, +openid/store/filestore.py,sha256=mlakkwaZ1Rbav1mEKtNBQALbCKwl8rABPk37y5GcJ6Y,12673 +openid/store/interface.py,sha256=yzIDYOFD6RW5rF8GiDq_5LUo_R0wn2SDltBSr5K96pw,7084 +openid/store/memstore.py,sha256=TKm5NgPxnZvj837v77M8u4BJCYqBmkRufoV36WT06_8,3587 +openid/store/nonce.py,sha256=AzsJfqEsjs7bypH2R5UVMTO-4l14SbXMxdXFnITKY9M,2843 +openid/store/sqlstore.py,sha256=o2YTwNnh4pn0V4i-zmSOeWSwhvD90nDYg7RSGlp5m9E,16652 +openid/urinorm.py,sha256=H8xPmiZkYjpRHkBZd0-hhoMgSz8Vn8PaYy1zB4UwEq4,4440 +openid/yadis/__init__.py,sha256=1iKQS1NpTLN5twvh_8ARwvTRC7SNIk0xrpJ8uBJz6Ns,252 +openid/yadis/__pycache__/__init__.cpython-310.pyc,, +openid/yadis/__pycache__/accept.cpython-310.pyc,, +openid/yadis/__pycache__/constants.cpython-310.pyc,, +openid/yadis/__pycache__/discover.cpython-310.pyc,, +openid/yadis/__pycache__/etxrd.cpython-310.pyc,, +openid/yadis/__pycache__/filters.cpython-310.pyc,, +openid/yadis/__pycache__/manager.cpython-310.pyc,, +openid/yadis/__pycache__/parsehtml.cpython-310.pyc,, +openid/yadis/__pycache__/services.cpython-310.pyc,, +openid/yadis/__pycache__/xri.cpython-310.pyc,, +openid/yadis/__pycache__/xrires.cpython-310.pyc,, +openid/yadis/accept.py,sha256=pduXjMLe9Ly-aB82k5rEDUNgM8BthbesU1EvWa_wxco,3747 +openid/yadis/constants.py,sha256=lVqo0FXIPyBUx2x2BB9D_Ly3g6qGm6tlpB-ZixwJY6Y,483 +openid/yadis/discover.py,sha256=qXyysYnxvfV6WVrYyHxoeyFHFwKISzLf5AA5WbEc-sY,6062 +openid/yadis/etxrd.py,sha256=RbO1MAPs9qrVmVN8--EdjV1qxVSMfvd8phxIKYbt45Q,8325 +openid/yadis/filters.py,sha256=R3klTS7HJtJ9oAVlIDRnqibqWycqB6GJLYTZnA9AMHM,7259 +openid/yadis/manager.py,sha256=R1thXogdBwbk2hkXWQRdWlbVubzaEa9RRbfkH_dhFkw,6085 +openid/yadis/parsehtml.py,sha256=-fNQ2WCS1r9uQtUfSL7ZzgyHzvayPcxczgRCrLr6E_Q,6061 +openid/yadis/services.py,sha256=u3SKE_1-y6HS8bme07klbMx2PZuojwjNgsOpUNdiRP4,1842 +openid/yadis/xri.py,sha256=kpvumvdKHG6zxIZFcMc74N0hgrohnDviEGXI669F2Vs,3476 +openid/yadis/xrires.py,sha256=N_QE7wz4QWACY9qSg5zl6x4YeO7y4GbFEJp1NIuy7pE,4276 +python3_openid-3.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +python3_openid-3.2.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 +python3_openid-3.2.0.dist-info/METADATA,sha256=RG753qgO5_YnVX25bzS-RXvDO3wyYbrAoLgKshBLQrs,1552 +python3_openid-3.2.0.dist-info/RECORD,, +python3_openid-3.2.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +python3_openid-3.2.0.dist-info/top_level.txt,sha256=PZKYepgDgIpDlWmOt8aR7aenHJBBVPvrlOmDE_0uOpA,7 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..b552003ff90e66227ec90d1b159324f140d46001 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2f7f6396d52c4c7297a5b2c05879bbba550ae60 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/python3_openid-3.2.0.dist-info/top_level.txt @@ -0,0 +1 @@ +openid diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/LICENSE.txt b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f1c11289f6a54cb07ebdbf31d02e8e81b18b07f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2003-2019 Stuart Bishop <stuart@stuartbishop.net> + +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/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..1ccd338f278ca103decc5802cbc7b2f1c728be93 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/METADATA @@ -0,0 +1,637 @@ +Metadata-Version: 2.1 +Name: pytz +Version: 2023.2 +Summary: World timezone definitions, modern and historical +Home-page: http://pythonhosted.org/pytz +Author: Stuart Bishop +Author-email: stuart@stuartbishop.net +Maintainer: Stuart Bishop +Maintainer-email: stuart@stuartbishop.net +License: MIT +Download-URL: https://pypi.org/project/pytz/ +Keywords: timezone,tzinfo,datetime,olson,time +Platform: Independent +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.4 +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.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: Topic :: Software Development :: Libraries :: Python Modules + +pytz - World Timezone Definitions for Python +============================================ + +:Author: Stuart Bishop <stuart@stuartbishop.net> + +Introduction +~~~~~~~~~~~~ + +pytz brings the Olson tz database into Python. This library allows +accurate and cross platform timezone calculations using Python 2.4 +or higher. It also solves the issue of ambiguous times at the end +of daylight saving time, which you can read more about in the Python +Library Reference (``datetime.tzinfo``). + +Almost all of the Olson timezones are supported. + +.. note:: + + This library differs from the documented Python API for + tzinfo implementations; if you want to create local wallclock + times you need to use the ``localize()`` method documented in this + document. In addition, if you perform date arithmetic on local + times that cross DST boundaries, the result may be in an incorrect + timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get + 2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A + ``normalize()`` method is provided to correct this. Unfortunately these + issues cannot be resolved without modifying the Python datetime + implementation (see PEP-431). + + +Installation +~~~~~~~~~~~~ + +This package can either be installed using ``pip`` or from a tarball using the +standard Python distutils. + +If you are installing using ``pip``, you don't need to download anything as the +latest version will be downloaded for you from PyPI:: + + pip install pytz + +If you are installing from a tarball, run the following command as an +administrative user:: + + python setup.py install + + +pytz for Enterprise +~~~~~~~~~~~~~~~~~~~ + +Available as part of the Tidelift Subscription. + +The maintainers of pytz and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. `Learn more. <https://tidelift.com/subscription/pkg/pypi-pytz?utm_source=pypi-pytz&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_. + + +Example & Usage +~~~~~~~~~~~~~~~ + +Localized times and date arithmetic +----------------------------------- + +>>> from datetime import datetime, timedelta +>>> from pytz import timezone +>>> import pytz +>>> utc = pytz.utc +>>> utc.zone +'UTC' +>>> eastern = timezone('US/Eastern') +>>> eastern.zone +'US/Eastern' +>>> amsterdam = timezone('Europe/Amsterdam') +>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z' + +This library only supports two ways of building a localized time. The +first is to use the ``localize()`` method provided by the pytz library. +This is used to localize a naive datetime (datetime with no timezone +information): + +>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0)) +>>> print(loc_dt.strftime(fmt)) +2002-10-27 06:00:00 EST-0500 + +The second way of building a localized time is by converting an existing +localized time using the standard ``astimezone()`` method: + +>>> ams_dt = loc_dt.astimezone(amsterdam) +>>> ams_dt.strftime(fmt) +'2002-10-27 12:00:00 CET+0100' + +Unfortunately using the tzinfo argument of the standard datetime +constructors ''does not work'' with pytz for many timezones. + +>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) # /!\ Does not work this way! +'2002-10-27 12:00:00 LMT+0018' + +It is safe for timezones without daylight saving transitions though, such +as UTC: + +>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) # /!\ Not recommended except for UTC +'2002-10-27 12:00:00 UTC+0000' + +The preferred way of dealing with times is to always work in UTC, +converting to localtime only when generating output to be read +by humans. + +>>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) +>>> loc_dt = utc_dt.astimezone(eastern) +>>> loc_dt.strftime(fmt) +'2002-10-27 01:00:00 EST-0500' + +This library also allows you to do date arithmetic using local +times, although it is more complicated than working in UTC as you +need to use the ``normalize()`` method to handle daylight saving time +and other timezone transitions. In this example, ``loc_dt`` is set +to the instant when daylight saving time ends in the US/Eastern +timezone. + +>>> before = loc_dt - timedelta(minutes=10) +>>> before.strftime(fmt) +'2002-10-27 00:50:00 EST-0500' +>>> eastern.normalize(before).strftime(fmt) +'2002-10-27 01:50:00 EDT-0400' +>>> after = eastern.normalize(before + timedelta(minutes=20)) +>>> after.strftime(fmt) +'2002-10-27 01:10:00 EST-0500' + +Creating local times is also tricky, and the reason why working with +local times is not recommended. Unfortunately, you cannot just pass +a ``tzinfo`` argument when constructing a datetime (see the next +section for more details) + +>>> dt = datetime(2002, 10, 27, 1, 30, 0) +>>> dt1 = eastern.localize(dt, is_dst=True) +>>> dt1.strftime(fmt) +'2002-10-27 01:30:00 EDT-0400' +>>> dt2 = eastern.localize(dt, is_dst=False) +>>> dt2.strftime(fmt) +'2002-10-27 01:30:00 EST-0500' + +Converting between timezones is more easily done, using the +standard astimezone method. + +>>> utc_dt = utc.localize(datetime.utcfromtimestamp(1143408899)) +>>> utc_dt.strftime(fmt) +'2006-03-26 21:34:59 UTC+0000' +>>> au_tz = timezone('Australia/Sydney') +>>> au_dt = utc_dt.astimezone(au_tz) +>>> au_dt.strftime(fmt) +'2006-03-27 08:34:59 AEDT+1100' +>>> utc_dt2 = au_dt.astimezone(utc) +>>> utc_dt2.strftime(fmt) +'2006-03-26 21:34:59 UTC+0000' +>>> utc_dt == utc_dt2 +True + +You can take shortcuts when dealing with the UTC side of timezone +conversions. ``normalize()`` and ``localize()`` are not really +necessary when there are no daylight saving time transitions to +deal with. + +>>> utc_dt = datetime.utcfromtimestamp(1143408899).replace(tzinfo=utc) +>>> utc_dt.strftime(fmt) +'2006-03-26 21:34:59 UTC+0000' +>>> au_tz = timezone('Australia/Sydney') +>>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz)) +>>> au_dt.strftime(fmt) +'2006-03-27 08:34:59 AEDT+1100' +>>> utc_dt2 = au_dt.astimezone(utc) +>>> utc_dt2.strftime(fmt) +'2006-03-26 21:34:59 UTC+0000' + + +``tzinfo`` API +-------------- + +The ``tzinfo`` instances returned by the ``timezone()`` function have +been extended to cope with ambiguous times by adding an ``is_dst`` +parameter to the ``utcoffset()``, ``dst()`` && ``tzname()`` methods. + +>>> tz = timezone('America/St_Johns') + +>>> normal = datetime(2009, 9, 1) +>>> ambiguous = datetime(2009, 10, 31, 23, 30) + +The ``is_dst`` parameter is ignored for most timestamps. It is only used +during DST transition ambiguous periods to resolve that ambiguity. + +>>> print(tz.utcoffset(normal, is_dst=True)) +-1 day, 21:30:00 +>>> print(tz.dst(normal, is_dst=True)) +1:00:00 +>>> tz.tzname(normal, is_dst=True) +'NDT' + +>>> print(tz.utcoffset(ambiguous, is_dst=True)) +-1 day, 21:30:00 +>>> print(tz.dst(ambiguous, is_dst=True)) +1:00:00 +>>> tz.tzname(ambiguous, is_dst=True) +'NDT' + +>>> print(tz.utcoffset(normal, is_dst=False)) +-1 day, 21:30:00 +>>> tz.dst(normal, is_dst=False).seconds +3600 +>>> tz.tzname(normal, is_dst=False) +'NDT' + +>>> print(tz.utcoffset(ambiguous, is_dst=False)) +-1 day, 20:30:00 +>>> tz.dst(ambiguous, is_dst=False) +datetime.timedelta(0) +>>> tz.tzname(ambiguous, is_dst=False) +'NST' + +If ``is_dst`` is not specified, ambiguous timestamps will raise +an ``pytz.exceptions.AmbiguousTimeError`` exception. + +>>> print(tz.utcoffset(normal)) +-1 day, 21:30:00 +>>> print(tz.dst(normal)) +1:00:00 +>>> tz.tzname(normal) +'NDT' + +>>> import pytz.exceptions +>>> try: +... tz.utcoffset(ambiguous) +... except pytz.exceptions.AmbiguousTimeError: +... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) +pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 +>>> try: +... tz.dst(ambiguous) +... except pytz.exceptions.AmbiguousTimeError: +... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) +pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 +>>> try: +... tz.tzname(ambiguous) +... except pytz.exceptions.AmbiguousTimeError: +... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) +pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 + + +Problems with Localtime +~~~~~~~~~~~~~~~~~~~~~~~ + +The major problem we have to deal with is that certain datetimes +may occur twice in a year. For example, in the US/Eastern timezone +on the last Sunday morning in October, the following sequence +happens: + + - 01:00 EDT occurs + - 1 hour later, instead of 2:00am the clock is turned back 1 hour + and 01:00 happens again (this time 01:00 EST) + +In fact, every instant between 01:00 and 02:00 occurs twice. This means +that if you try and create a time in the 'US/Eastern' timezone +the standard datetime syntax, there is no way to specify if you meant +before of after the end-of-daylight-saving-time transition. Using the +pytz custom syntax, the best you can do is make an educated guess: + +>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 1, 30, 00)) +>>> loc_dt.strftime(fmt) +'2002-10-27 01:30:00 EST-0500' + +As you can see, the system has chosen one for you and there is a 50% +chance of it being out by one hour. For some applications, this does +not matter. However, if you are trying to schedule meetings with people +in different timezones or analyze log files it is not acceptable. + +The best and simplest solution is to stick with using UTC. The pytz +package encourages using UTC for internal timezone representation by +including a special UTC implementation based on the standard Python +reference implementation in the Python documentation. + +The UTC timezone unpickles to be the same instance, and pickles to a +smaller size than other pytz tzinfo instances. The UTC implementation +can be obtained as pytz.utc, pytz.UTC, or pytz.timezone('UTC'). + +>>> import pickle, pytz +>>> dt = datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) +>>> naive = dt.replace(tzinfo=None) +>>> p = pickle.dumps(dt, 1) +>>> naive_p = pickle.dumps(naive, 1) +>>> len(p) - len(naive_p) +17 +>>> new = pickle.loads(p) +>>> new == dt +True +>>> new is dt +False +>>> new.tzinfo is dt.tzinfo +True +>>> pytz.utc is pytz.UTC is pytz.timezone('UTC') +True + +Note that some other timezones are commonly thought of as the same (GMT, +Greenwich, Universal, etc.). The definition of UTC is distinct from these +other timezones, and they are not equivalent. For this reason, they will +not compare the same in Python. + +>>> utc == pytz.timezone('GMT') +False + +See the section `What is UTC`_, below. + +If you insist on working with local times, this library provides a +facility for constructing them unambiguously: + +>>> loc_dt = datetime(2002, 10, 27, 1, 30, 00) +>>> est_dt = eastern.localize(loc_dt, is_dst=True) +>>> edt_dt = eastern.localize(loc_dt, is_dst=False) +>>> print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt)) +2002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500 + +If you pass None as the is_dst flag to localize(), pytz will refuse to +guess and raise exceptions if you try to build ambiguous or non-existent +times. + +For example, 1:30am on 27th Oct 2002 happened twice in the US/Eastern +timezone when the clocks where put back at the end of Daylight Saving +Time: + +>>> dt = datetime(2002, 10, 27, 1, 30, 00) +>>> try: +... eastern.localize(dt, is_dst=None) +... except pytz.exceptions.AmbiguousTimeError: +... print('pytz.exceptions.AmbiguousTimeError: %s' % dt) +pytz.exceptions.AmbiguousTimeError: 2002-10-27 01:30:00 + +Similarly, 2:30am on 7th April 2002 never happened at all in the +US/Eastern timezone, as the clocks where put forward at 2:00am skipping +the entire hour: + +>>> dt = datetime(2002, 4, 7, 2, 30, 00) +>>> try: +... eastern.localize(dt, is_dst=None) +... except pytz.exceptions.NonExistentTimeError: +... print('pytz.exceptions.NonExistentTimeError: %s' % dt) +pytz.exceptions.NonExistentTimeError: 2002-04-07 02:30:00 + +Both of these exceptions share a common base class to make error handling +easier: + +>>> isinstance(pytz.AmbiguousTimeError(), pytz.InvalidTimeError) +True +>>> isinstance(pytz.NonExistentTimeError(), pytz.InvalidTimeError) +True + + +A special case is where countries change their timezone definitions +with no daylight savings time switch. For example, in 1915 Warsaw +switched from Warsaw time to Central European time with no daylight savings +transition. So at the stroke of midnight on August 5th 1915 the clocks +were wound back 24 minutes creating an ambiguous time period that cannot +be specified without referring to the timezone abbreviation or the +actual UTC offset. In this case midnight happened twice, neither time +during a daylight saving time period. pytz handles this transition by +treating the ambiguous period before the switch as daylight savings +time, and the ambiguous period after as standard time. + + +>>> warsaw = pytz.timezone('Europe/Warsaw') +>>> amb_dt1 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=True) +>>> amb_dt1.strftime(fmt) +'1915-08-04 23:59:59 WMT+0124' +>>> amb_dt2 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=False) +>>> amb_dt2.strftime(fmt) +'1915-08-04 23:59:59 CET+0100' +>>> switch_dt = warsaw.localize(datetime(1915, 8, 5, 00, 00, 00), is_dst=False) +>>> switch_dt.strftime(fmt) +'1915-08-05 00:00:00 CET+0100' +>>> str(switch_dt - amb_dt1) +'0:24:01' +>>> str(switch_dt - amb_dt2) +'0:00:01' + +The best way of creating a time during an ambiguous time period is +by converting from another timezone such as UTC: + +>>> utc_dt = datetime(1915, 8, 4, 22, 36, tzinfo=pytz.utc) +>>> utc_dt.astimezone(warsaw).strftime(fmt) +'1915-08-04 23:36:00 CET+0100' + +The standard Python way of handling all these ambiguities is not to +handle them, such as demonstrated in this example using the US/Eastern +timezone definition from the Python documentation (Note that this +implementation only works for dates between 1987 and 2006 - it is +included for tests only!): + +>>> from pytz.reference import Eastern # pytz.reference only for tests +>>> dt = datetime(2002, 10, 27, 0, 30, tzinfo=Eastern) +>>> str(dt) +'2002-10-27 00:30:00-04:00' +>>> str(dt + timedelta(hours=1)) +'2002-10-27 01:30:00-05:00' +>>> str(dt + timedelta(hours=2)) +'2002-10-27 02:30:00-05:00' +>>> str(dt + timedelta(hours=3)) +'2002-10-27 03:30:00-05:00' + +Notice the first two results? At first glance you might think they are +correct, but taking the UTC offset into account you find that they are +actually two hours appart instead of the 1 hour we asked for. + +>>> from pytz.reference import UTC # pytz.reference only for tests +>>> str(dt.astimezone(UTC)) +'2002-10-27 04:30:00+00:00' +>>> str((dt + timedelta(hours=1)).astimezone(UTC)) +'2002-10-27 06:30:00+00:00' + + +Country Information +~~~~~~~~~~~~~~~~~~~ + +A mechanism is provided to access the timezones commonly in use +for a particular country, looked up using the ISO 3166 country code. +It returns a list of strings that can be used to retrieve the relevant +tzinfo instance using ``pytz.timezone()``: + +>>> print(' '.join(pytz.country_timezones['nz'])) +Pacific/Auckland Pacific/Chatham + +The Olson database comes with a ISO 3166 country code to English country +name mapping that pytz exposes as a dictionary: + +>>> print(pytz.country_names['nz']) +New Zealand + + +What is UTC +~~~~~~~~~~~ + +'UTC' is `Coordinated Universal Time`_. It is a successor to, but distinct +from, Greenwich Mean Time (GMT) and the various definitions of Universal +Time. UTC is now the worldwide standard for regulating clocks and time +measurement. + +All other timezones are defined relative to UTC, and include offsets like +UTC+0800 - hours to add or subtract from UTC to derive the local time. No +daylight saving time occurs in UTC, making it a useful timezone to perform +date arithmetic without worrying about the confusion and ambiguities caused +by daylight saving time transitions, your country changing its timezone, or +mobile computers that roam through multiple timezones. + +.. _Coordinated Universal Time: https://en.wikipedia.org/wiki/Coordinated_Universal_Time + + +Helpers +~~~~~~~ + +There are two lists of timezones provided. + +``all_timezones`` is the exhaustive list of the timezone names that can +be used. + +>>> from pytz import all_timezones +>>> len(all_timezones) >= 500 +True +>>> 'Etc/Greenwich' in all_timezones +True + +``common_timezones`` is a list of useful, current timezones. It doesn't +contain deprecated zones or historical zones, except for a few I've +deemed in common usage, such as US/Eastern (open a bug report if you +think other timezones are deserving of being included here). It is also +a sequence of strings. + +>>> from pytz import common_timezones +>>> len(common_timezones) < len(all_timezones) +True +>>> 'Etc/Greenwich' in common_timezones +False +>>> 'Australia/Melbourne' in common_timezones +True +>>> 'US/Eastern' in common_timezones +True +>>> 'Canada/Eastern' in common_timezones +True +>>> 'Australia/Yancowinna' in all_timezones +True +>>> 'Australia/Yancowinna' in common_timezones +False + +Both ``common_timezones`` and ``all_timezones`` are alphabetically +sorted: + +>>> common_timezones_dupe = common_timezones[:] +>>> common_timezones_dupe.sort() +>>> common_timezones == common_timezones_dupe +True +>>> all_timezones_dupe = all_timezones[:] +>>> all_timezones_dupe.sort() +>>> all_timezones == all_timezones_dupe +True + +``all_timezones`` and ``common_timezones`` are also available as sets. + +>>> from pytz import all_timezones_set, common_timezones_set +>>> 'US/Eastern' in all_timezones_set +True +>>> 'US/Eastern' in common_timezones_set +True +>>> 'Australia/Victoria' in common_timezones_set +False + +You can also retrieve lists of timezones used by particular countries +using the ``country_timezones()`` function. It requires an ISO-3166 +two letter country code. + +>>> from pytz import country_timezones +>>> print(' '.join(country_timezones('ch'))) +Europe/Zurich +>>> print(' '.join(country_timezones('CH'))) +Europe/Zurich + + +Internationalization - i18n/l10n +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pytz is an interface to the IANA database, which uses ASCII names. The `Unicode Consortium's Unicode Locales (CLDR) <http://cldr.unicode.org>`_ +project provides translations. Python packages such as +`Babel <https://babel.pocoo.org/en/latest/api/dates.html#timezone-functionality>`_ +and Thomas Khyn's `l18n <https://pypi.org/project/l18n/>`_ package can be used +to access these translations from Python. + + +License +~~~~~~~ + +MIT license. + +This code is also available as part of Zope 3 under the Zope Public +License, Version 2.1 (ZPL). + +I'm happy to relicense this code if necessary for inclusion in other +open source projects. + + +Latest Versions +~~~~~~~~~~~~~~~ + +This package will be updated after releases of the Olson timezone +database. The latest version can be downloaded from the `Python Package +Index <https://pypi.org/project/pytz/>`_. The code that is used +to generate this distribution is hosted on launchpad.net and available +using git:: + + git clone https://git.launchpad.net/pytz + +A mirror on github is also available at https://github.com/stub42/pytz + +Announcements of new releases are made on +`Launchpad <https://launchpad.net/pytz>`_, and the +`Atom feed <http://feeds.launchpad.net/pytz/announcements.atom>`_ +hosted there. + + +Bugs, Feature Requests & Patches +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bugs can be reported using `Launchpad Bugs <https://bugs.launchpad.net/pytz>`_. + + +Security Issues +~~~~~~~~~~~~~~~ + +Reports about security issues can be made via `Tidelift <https://tidelift.com/security>`_. + + +Issues & Limitations +~~~~~~~~~~~~~~~~~~~~ + +- Offsets from UTC are rounded to the nearest whole minute, so timezones + such as Europe/Amsterdam pre 1937 will be up to 30 seconds out. This + is a limitation of the Python datetime library. + +- If you think a timezone definition is incorrect, I probably can't fix + it. pytz is a direct translation of the Olson timezone database, and + changes to the timezone definitions need to be made to this source. + If you find errors they should be reported to the time zone mailing + list, linked from http://www.iana.org/time-zones. + + +Further Reading +~~~~~~~~~~~~~~~ + +More info than you want to know about timezones: +https://data.iana.org/time-zones/tz-link.html + + +Contact +~~~~~~~ + +Stuart Bishop <stuart@stuartbishop.net> + + + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..07505e2359bd9654b2b904034787de29c6008d10 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/RECORD @@ -0,0 +1,621 @@ +pytz-2023.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pytz-2023.2.dist-info/LICENSE.txt,sha256=vosaN-vibFkqkPbA6zMQOn84POL010mMCvmlJpkKB7g,1088 +pytz-2023.2.dist-info/METADATA,sha256=ZKPCT3E_kZXtNTR6-WE6_UKyJZoJIuHpG4Dw8j6Pz4E,21618 +pytz-2023.2.dist-info/RECORD,, +pytz-2023.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +pytz-2023.2.dist-info/top_level.txt,sha256=6xRYlt934v1yHb1JIrXgHyGxn3cqACvd-yE8ski_kcc,5 +pytz-2023.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +pytz/__init__.py,sha256=udzzMsYj7MfyEuZLjCzKPDxFfeifUKJQgqx3tQf3E58,35101 +pytz/__pycache__/__init__.cpython-310.pyc,, +pytz/__pycache__/exceptions.cpython-310.pyc,, +pytz/__pycache__/lazy.cpython-310.pyc,, +pytz/__pycache__/reference.cpython-310.pyc,, +pytz/__pycache__/tzfile.cpython-310.pyc,, +pytz/__pycache__/tzinfo.cpython-310.pyc,, +pytz/exceptions.py,sha256=434ZcuLlpLQY9mWoGq7zJMV1TyiYvVgpKBU1qZkbDjM,1571 +pytz/lazy.py,sha256=toeR5uDWKBj6ezsUZ4elNP6CEMtK7CO2jS9A30nsFbo,5404 +pytz/reference.py,sha256=zUtCki7JFEmrzrjNsfMD7YL0lWDxynKc1Ubo4iXSs74,3778 +pytz/tzfile.py,sha256=K2y7pZs4vydpZVftrfAA_-hgw17y1Szc7z_QCse6udU,4723 +pytz/tzinfo.py,sha256=-5UjW-yqHbtO5NtSaWope7EbSdf2oTES26Kdlxjqdk0,19272 +pytz/zoneinfo/Africa/Abidjan,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Accra,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Addis_Ababa,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Algiers,sha256=vaFpjNVCwObnbfu82rOQzdJvN6nVgmpXpQ1aqzfzsqY,735 +pytz/zoneinfo/Africa/Asmara,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Asmera,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Bamako,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Bangui,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Banjul,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Bissau,sha256=IjuxDP6EZiDHFvl_bHS6NN7sdRxLKXllooBC829poak,194 +pytz/zoneinfo/Africa/Blantyre,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Brazzaville,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Bujumbura,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Cairo,sha256=Lft-GCLQhaSJm9VqUmsEFoHIS1Vhfa7pFJn9GZCpifs,2399 +pytz/zoneinfo/Africa/Casablanca,sha256=4RqVbw_F3ZucopIC2ivAJ8WDwj5wRODAB67tBpdXcgA,2429 +pytz/zoneinfo/Africa/Ceuta,sha256=Cw-2_nFDGbN8WqIsVpcauyZooWX8j3Kmx2PnC0fHut8,2052 +pytz/zoneinfo/Africa/Conakry,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Dakar,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Dar_es_Salaam,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Djibouti,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Douala,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/El_Aaiun,sha256=UWCCqQLJxd8qsTYw82kz9W1suwW5TRgnZw31sDWDz20,2295 +pytz/zoneinfo/Africa/Freetown,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Gaborone,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Harare,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Johannesburg,sha256=bBvMdSZo53WFowiuhUO9C8zY6BOGViboCb-U8_49l34,246 +pytz/zoneinfo/Africa/Juba,sha256=UVnIqEPJwHLTMC-r5qZQHNv9opoYVsKdq-ta_5XUw_Q,679 +pytz/zoneinfo/Africa/Kampala,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Khartoum,sha256=MYWDoJ3AcCItZdApoeOgtWWDDxquwTon5v5TOGP70-o,679 +pytz/zoneinfo/Africa/Kigali,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Kinshasa,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Lagos,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Libreville,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Lome,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Luanda,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Lubumbashi,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Lusaka,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Malabo,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Maputo,sha256=k_GelVHViGiuWCB1LSyTpIYSTDZEY9yclInQRY-LxoI,149 +pytz/zoneinfo/Africa/Maseru,sha256=bBvMdSZo53WFowiuhUO9C8zY6BOGViboCb-U8_49l34,246 +pytz/zoneinfo/Africa/Mbabane,sha256=bBvMdSZo53WFowiuhUO9C8zY6BOGViboCb-U8_49l34,246 +pytz/zoneinfo/Africa/Mogadishu,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Monrovia,sha256=-VsJW5cU4KdvfgYaQVv4lcuzmaKIVFMd42nO6RXOBdU,208 +pytz/zoneinfo/Africa/Nairobi,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Africa/Ndjamena,sha256=8T3A0Zm9Gj0Bvm6rd88t3GAXKiKdGUfHlIqYlkYI0KM,199 +pytz/zoneinfo/Africa/Niamey,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Nouakchott,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Ouagadougou,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Porto-Novo,sha256=z_6wKCzL1_ug5JP_hneh5abdUZeIUELkN_ladz-ESEY,235 +pytz/zoneinfo/Africa/Sao_Tome,sha256=MdjxpQ268uzJ7Zx1ZroFUtRUwqsJ6F_yY3AYV9FXw1I,254 +pytz/zoneinfo/Africa/Timbuktu,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Africa/Tripoli,sha256=W1dptGD70T7ppGoo0fczFQeDiIp0nultLNPV66MwB2c,625 +pytz/zoneinfo/Africa/Tunis,sha256=OFVMEM4eYT2Ez0beuhEUCTSIpcFldWxsV2uEoTZIUNI,689 +pytz/zoneinfo/Africa/Windhoek,sha256=xuhvudrMH4alnVmouSTQI8YL8F_HbgsF2EQ7AZKzuHs,955 +pytz/zoneinfo/America/Adak,sha256=IB1DhwJQAKbhPJ9jHLf8zW5Dad7HIkBS-dhv64E1OlM,2356 +pytz/zoneinfo/America/Anchorage,sha256=oZA1NSPS2BWdymYpnCHFO8BlYVS-ll5KLg2Ez9CbETs,2371 +pytz/zoneinfo/America/Anguilla,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Antigua,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Araguaina,sha256=G6v9wYFZ8EB4WQfIsqRbbiiKd2b27j7Zt5dFjBbzx2o,870 +pytz/zoneinfo/America/Argentina/Buenos_Aires,sha256=JmU8lBwmy29gR6OmeytvFdMRx6ObJKnYNHmLyMmXX2M,1062 +pytz/zoneinfo/America/Argentina/Catamarca,sha256=uMCJXXGYmNESHVvj5RYBZ0McrOdE14hwm17l25MgRW0,1062 +pytz/zoneinfo/America/Argentina/ComodRivadavia,sha256=uMCJXXGYmNESHVvj5RYBZ0McrOdE14hwm17l25MgRW0,1062 +pytz/zoneinfo/America/Argentina/Cordoba,sha256=uniNihhMHnr4XK4WpwiPUnrAT0YPmvzqB6f0hRLtXvY,1062 +pytz/zoneinfo/America/Argentina/Jujuy,sha256=PGmAehypCxj0XCenCSWqylDIPbKLK0DlrwJK_24D590,1034 +pytz/zoneinfo/America/Argentina/La_Rioja,sha256=Um6XoVXhsr62ad1mWuebe6NY0ZHauBdR9tMGDgqCOHg,1076 +pytz/zoneinfo/America/Argentina/Mendoza,sha256=xcOVtvRyVYFAU90y2QYwpyQhpMLyAp7-Fxvku4kgl0c,1062 +pytz/zoneinfo/America/Argentina/Rio_Gallegos,sha256=F9ZKR4o8gLHX7QBuIjMapGIdmzJxpqwbouPgZ5MqDpY,1062 +pytz/zoneinfo/America/Argentina/Salta,sha256=h1KYrDNIapvDkYhi1PaB8WD1qWOe4vhhgDJWDCGV4jc,1034 +pytz/zoneinfo/America/Argentina/San_Juan,sha256=AI2GltA80mPNzhHxYycuEwIbO1ANXyIqBQZMpjqKqdQ,1076 +pytz/zoneinfo/America/Argentina/San_Luis,sha256=2ItGRcLVK2wx8MyJsHbIBBeAkU4B-MN5x1ZxNyZ7UJE,1088 +pytz/zoneinfo/America/Argentina/Tucuman,sha256=twO-FqtNJV8XOzWTvFQ-xnEcWCoDUHY3gpVIG0Mzbf8,1090 +pytz/zoneinfo/America/Argentina/Ushuaia,sha256=A6IbpVlY9IIPoSKMFRR9DMROdwXUSDc2HsASueOSnqo,1062 +pytz/zoneinfo/America/Aruba,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Asuncion,sha256=V8wwkUoNqyj0C-fUSADpU7HU8H3Qkr3jNPJ4SLsGUIc,2030 +pytz/zoneinfo/America/Atikokan,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Atka,sha256=IB1DhwJQAKbhPJ9jHLf8zW5Dad7HIkBS-dhv64E1OlM,2356 +pytz/zoneinfo/America/Bahia,sha256=qi7dA6FofDhLxVMmd2L8bK3HeaQnc9X-jiijwyfhs3g,1010 +pytz/zoneinfo/America/Bahia_Banderas,sha256=L6iHYbA1Us1pljllFLEIAHW4ZaZhFKoG2Zr8TT5aY38,1152 +pytz/zoneinfo/America/Barbados,sha256=ima-Qrrhazu4Qfvu2Z0-e6E-GTiYknuJBu6c2yVG9LE,436 +pytz/zoneinfo/America/Belem,sha256=aZMUgtFDdHNISpqyQRYbmS2IBD-BAS3CaJnhu6onLCY,562 +pytz/zoneinfo/America/Belize,sha256=pkfLY2KfPchbeJa1pWcXmWAwp4ZlRvxWLVezXnrbkws,1614 +pytz/zoneinfo/America/Blanc-Sablon,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Boa_Vista,sha256=dMtaG11kGlJrgJJgGWEDZZAmnO_HfT3L4X8pI72LLFY,618 +pytz/zoneinfo/America/Bogota,sha256=Z1ernZZGQxulE8KFWHYWcM3SV1jn2_QEc1Q0OJzHRak,232 +pytz/zoneinfo/America/Boise,sha256=7HQsNPJiUheQgFz5kVLvTnf5xhXAYaeANqDskxKz2Vs,2410 +pytz/zoneinfo/America/Buenos_Aires,sha256=JmU8lBwmy29gR6OmeytvFdMRx6ObJKnYNHmLyMmXX2M,1062 +pytz/zoneinfo/America/Cambridge_Bay,sha256=_4xRlX3WdVpEcqoT6myD7NeTCXnn9OYk_iH006bwULo,2254 +pytz/zoneinfo/America/Campo_Grande,sha256=gINiXg5i2e6Rh2Nbo2bFqhPAJL4F4cAqGnBankXTDXw,1430 +pytz/zoneinfo/America/Cancun,sha256=lI4ZtiBtxKqNHvU47vRSwc5-GDl8JOdC2A6oc9s8iIo,834 +pytz/zoneinfo/America/Caracas,sha256=mUNMFdDzZLav_ePA1ocBdmqVBierkeEszTIFpNCm5J0,250 +pytz/zoneinfo/America/Catamarca,sha256=uMCJXXGYmNESHVvj5RYBZ0McrOdE14hwm17l25MgRW0,1062 +pytz/zoneinfo/America/Cayenne,sha256=4k7Iv1woX4atqePKrcvMQD2Vk9Tmma7rW_AW_R62pCc,184 +pytz/zoneinfo/America/Cayman,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Chicago,sha256=_roybr6I6sIAF6cYdIxGxoRpoef153Fty48dQ6bm9oY,3592 +pytz/zoneinfo/America/Chihuahua,sha256=ZAlPSsUfT3VGp1VdibnHIf-QsdEIqHuzX15wu2P2YQk,1102 +pytz/zoneinfo/America/Ciudad_Juarez,sha256=OQstyPrMxx3nNEbzgDhq_W0mK49-ApNMK7_6p-6dJ64,1538 +pytz/zoneinfo/America/Coral_Harbour,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Cordoba,sha256=uniNihhMHnr4XK4WpwiPUnrAT0YPmvzqB6f0hRLtXvY,1062 +pytz/zoneinfo/America/Costa_Rica,sha256=74rYa6lrgIkyls9PkHo8SCYl9oOqiuG5S7MWdnJelP4,316 +pytz/zoneinfo/America/Creston,sha256=illz0sYuLL8lIPK0Tkou6dL0Vck_D0W_3rRTOvFYRmQ,360 +pytz/zoneinfo/America/Cuiaba,sha256=GRJqkhRXNsOUcgjZddQxRIJdRYaw9pM_YLWbun88dkg,1402 +pytz/zoneinfo/America/Curacao,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Danmarkshavn,sha256=YRZAfUCoVtaL1L-MYMYMH1wyOaVQnfUo_gFnvMXSuzw,698 +pytz/zoneinfo/America/Dawson,sha256=rAHhyuMuyjf_eyA2SBG76MRBf_fj_xi5FAuiWVQgJhw,1614 +pytz/zoneinfo/America/Dawson_Creek,sha256=aJXCyP4j3ggE4wGCN-LrS9hpD_5zWHzQTeSAKTWEPUM,1050 +pytz/zoneinfo/America/Denver,sha256=MugZwApDs8NI9TnXANQlUE8guNBowWQY0m-ptpPndck,2460 +pytz/zoneinfo/America/Detroit,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 +pytz/zoneinfo/America/Dominica,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Edmonton,sha256=-TkIfc3QlvaCf0p8COZ43Y1HRBAl-nARUi-JdXeK1vE,2332 +pytz/zoneinfo/America/Eirunepe,sha256=j5eExkjFaqtC-D8XK0rGzoF9yEgbSlTbPqVG9WKhEa8,642 +pytz/zoneinfo/America/El_Salvador,sha256=gvGN8Lkj-sGm2_rs8OUjAMf1oMtKp2Xes6UfWT0WqgU,224 +pytz/zoneinfo/America/Ensenada,sha256=57-Q9LSTNuTidz-lOTwDysmlCoeFUXSecvVVqNWburQ,2374 +pytz/zoneinfo/America/Fort_Nelson,sha256=erfODr3DrSpz65kAdO7Ts2dGbZxvddEP6gx4BX3y2J0,2240 +pytz/zoneinfo/America/Fort_Wayne,sha256=kNKy9Kj9ICsiYYfCCbAggzMA7exf-GpGPMxoXocHUyw,1682 +pytz/zoneinfo/America/Fortaleza,sha256=rjiSB0q1cBuMDOM9orW_uwe5UOLBwTlfjFotwOYe1mU,702 +pytz/zoneinfo/America/Glace_Bay,sha256=G8DGLGCapH_aYCF_OhaL5Qonf7FOAgAPwelO5htCWBc,2192 +pytz/zoneinfo/America/Godthab,sha256=p4VrrdFjfh-Mps7HERGP0lfhVgxEw34e5Kq8FySV_O0,1903 +pytz/zoneinfo/America/Goose_Bay,sha256=JgaLueghSvX2g725FOfIgpgvsqxZGykWOhAZWGpQZRY,3210 +pytz/zoneinfo/America/Grand_Turk,sha256=4YOFEPK60Bel2_fCsY6vSZxUcMJKjiKtyOf_Q0khEwU,1834 +pytz/zoneinfo/America/Grenada,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Guadeloupe,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Guatemala,sha256=dugUgCd6QY52yHkHuUP4jRWzo5x439IQigaYCvEF46Q,280 +pytz/zoneinfo/America/Guayaquil,sha256=j2UuIo-4RgSOlTNfu77mhZ92waNTeKFSvmoVemJooT0,232 +pytz/zoneinfo/America/Guyana,sha256=R0bOvCRDC8SRIexmhsduPdHbbRPwI2GviD9otExiUrk,248 +pytz/zoneinfo/America/Halifax,sha256=TZpmc5PwWoLfTfQoQ_b3U17BE2iVKSeNkR0Ho8mbTn8,3424 +pytz/zoneinfo/America/Havana,sha256=HUQeAuKBsEkI5SLZjqynXICOUVOajkKzKH5r-Ov5Odc,2416 +pytz/zoneinfo/America/Hermosillo,sha256=WnlVBpVBG8ONnz0wpxteXmuvSzOGwSlAisvDd1GtKYA,456 +pytz/zoneinfo/America/Indiana/Indianapolis,sha256=kNKy9Kj9ICsiYYfCCbAggzMA7exf-GpGPMxoXocHUyw,1682 +pytz/zoneinfo/America/Indiana/Knox,sha256=CsvZ5BKw2qVav3x_F8CU9taJdDk7jX41Cfsqms6jXV8,2444 +pytz/zoneinfo/America/Indiana/Marengo,sha256=f3tQ-lgMSUA7nvn64pXhKtJL7mWzGajoCega5MEJSbI,1738 +pytz/zoneinfo/America/Indiana/Petersburg,sha256=A88OHuM0Rg3iMLHjKgXq_d2jZCdVSytUQs-9W0KcFyQ,1920 +pytz/zoneinfo/America/Indiana/Tell_City,sha256=4dWqAr9Y2BXfL4pAQk-81c3gGl2cNdHXOD7_wJhhhn8,1700 +pytz/zoneinfo/America/Indiana/Vevay,sha256=H7VR2G-_sD_C5Rm4P3g1iRC1FWCPg4m0MGD3P1PLzsk,1430 +pytz/zoneinfo/America/Indiana/Vincennes,sha256=62mAxT7APFCaoygflnEzdOpe-fuW1yObI6m6EUUcS7A,1710 +pytz/zoneinfo/America/Indiana/Winamac,sha256=aZGM2jR8CH9BHSUq7XygiweDd6dorXLPXg246XsbR6s,1794 +pytz/zoneinfo/America/Indianapolis,sha256=kNKy9Kj9ICsiYYfCCbAggzMA7exf-GpGPMxoXocHUyw,1682 +pytz/zoneinfo/America/Inuvik,sha256=6J-mapDnrk9A1LtswoE34tqSy_ufedcEBNxixkrEjIo,2074 +pytz/zoneinfo/America/Iqaluit,sha256=feOnxAN0N0r-M1qlkrA4JMyawoc0tqae0iiBCPDAs4k,2202 +pytz/zoneinfo/America/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 +pytz/zoneinfo/America/Jujuy,sha256=PGmAehypCxj0XCenCSWqylDIPbKLK0DlrwJK_24D590,1034 +pytz/zoneinfo/America/Juneau,sha256=k7hxb0aGRnfnE-DBi3LkcjAzRPyAf0_Hw0vVFfjGeb0,2353 +pytz/zoneinfo/America/Kentucky/Louisville,sha256=tP072xV_n_vIQjxxcJ77AGeGj6yL1KPpn3fwids9g1U,2788 +pytz/zoneinfo/America/Kentucky/Monticello,sha256=LtdyCo85BrXQs6rlH61Ym-8KqWHH6PwAOjD0QxhIdzM,2368 +pytz/zoneinfo/America/Knox_IN,sha256=CsvZ5BKw2qVav3x_F8CU9taJdDk7jX41Cfsqms6jXV8,2444 +pytz/zoneinfo/America/Kralendijk,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/La_Paz,sha256=hqfD8LQHupdZhji2e93_9pOQAT-R7muzzjP0nyfbFXY,218 +pytz/zoneinfo/America/Lima,sha256=HHgTnDUnCZzibvL0MrG8qyOuvjmYYw3e3R5VbnxMZs8,392 +pytz/zoneinfo/America/Los_Angeles,sha256=aJd7ua1tGG_vxser02AQpm4wAI3LLTdgh6QcSYYecmg,2852 +pytz/zoneinfo/America/Louisville,sha256=tP072xV_n_vIQjxxcJ77AGeGj6yL1KPpn3fwids9g1U,2788 +pytz/zoneinfo/America/Lower_Princes,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Maceio,sha256=3R5DlSe32kQDmoSVIWpcyk2o7qohr-rliwqDSGFIMyQ,730 +pytz/zoneinfo/America/Managua,sha256=xBzF01AHn2E2fD8Qdy-DHFe36UqoeNpKPfChduBKWdk,430 +pytz/zoneinfo/America/Manaus,sha256=F6RLOOeOi9lymZiQmQ9pR8tFpPZ6EguNdPfOc6BhXDE,590 +pytz/zoneinfo/America/Marigot,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Martinique,sha256=fMs80kOU2YFvC0f9y2eje97JeAtTYBamXrnlTunNLzQ,232 +pytz/zoneinfo/America/Matamoros,sha256=fq-PqdmZrQ98UsFmHA9ivjBZv5GEBRTOuLQ5Cu5ajW8,1418 +pytz/zoneinfo/America/Mazatlan,sha256=RQQVwlEVHRp2X-c_0hJ46y54abTlqUuLkyrUUicyc5g,1128 +pytz/zoneinfo/America/Mendoza,sha256=xcOVtvRyVYFAU90y2QYwpyQhpMLyAp7-Fxvku4kgl0c,1062 +pytz/zoneinfo/America/Menominee,sha256=Arv9WLbfhNcpRsUjHDU757BEdwlp08Gt30AixG3gZ04,2274 +pytz/zoneinfo/America/Merida,sha256=ORJCGiO2mXG-kk5ZZGro1MNuKqRnJx6HJlvoezTMM90,1004 +pytz/zoneinfo/America/Metlakatla,sha256=twmieGTVY2V-U8nFxqvx7asYv8GVjeWdLtrOI7UApVI,1423 +pytz/zoneinfo/America/Mexico_City,sha256=A5MlfDUZ4O1-jMTRt0WPem7qqcW0Nrslls1hlc8C4-Q,1222 +pytz/zoneinfo/America/Miquelon,sha256=E9KCH4ZHWe40w_3nZR1EFF4LVpEuGWRdKDm5UUgYydw,1652 +pytz/zoneinfo/America/Moncton,sha256=Wmv-bk9aKKcWWzOpc1UFu67HOfwaIk2Wmh3LgqGctys,3154 +pytz/zoneinfo/America/Monterrey,sha256=vKBLVjG0bNVDI07M4WwOVv2KbrYJVNTLmc19iM2CvTU,980 +pytz/zoneinfo/America/Montevideo,sha256=dQEBE4mjZPtyRjKXK6Z-bMHJdFqpwhIzxDH4x04rKYk,1496 +pytz/zoneinfo/America/Montreal,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Montserrat,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Nassau,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/New_York,sha256=6e0H177gx2qdRC0JHvHwFmj-58TyYBTAqGixn-bBipU,3552 +pytz/zoneinfo/America/Nipigon,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Nome,sha256=2izM3-P-PqJ9za6MdhzFfMvPFNq7Gim69tAvEwPeY2s,2367 +pytz/zoneinfo/America/Noronha,sha256=feeRAijQqKylZgqe84nKhsFLycT5zIBm7mLIvdyGw4w,702 +pytz/zoneinfo/America/North_Dakota/Beulah,sha256=qtgbqNu8M3AkHF2n-_oSps1pYT4SxgclbkkPKbXaBHs,2396 +pytz/zoneinfo/America/North_Dakota/Center,sha256=9ZWbK9YKkquULyBUFS3Lr_idxbt7V7y4W4EO0Kn20sw,2396 +pytz/zoneinfo/America/North_Dakota/New_Salem,sha256=DH_bsQfuUnK2obdb06KgisO4XLqht12BXdrgUsZZveg,2396 +pytz/zoneinfo/America/Nuuk,sha256=p4VrrdFjfh-Mps7HERGP0lfhVgxEw34e5Kq8FySV_O0,1903 +pytz/zoneinfo/America/Ojinaga,sha256=9catgEQ2SD7qfuvTMxs15Cdd9SKaUy-svEzPBFw2Q3Q,1524 +pytz/zoneinfo/America/Panama,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Pangnirtung,sha256=feOnxAN0N0r-M1qlkrA4JMyawoc0tqae0iiBCPDAs4k,2202 +pytz/zoneinfo/America/Paramaribo,sha256=Z7UZvNlgd-qEUHjEPYXIkLNTgjMcCzk9EfUUEmUyd7M,248 +pytz/zoneinfo/America/Phoenix,sha256=illz0sYuLL8lIPK0Tkou6dL0Vck_D0W_3rRTOvFYRmQ,360 +pytz/zoneinfo/America/Port-au-Prince,sha256=09ZAJd4IOiMpfdpUuF1U44R_hRt6BvpAkFXOnYO9yOM,1434 +pytz/zoneinfo/America/Port_of_Spain,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Porto_Acre,sha256=0gpJUl46hQbp0P6Xj1S0NArIWeAryuuDXjsldvB5GHE,614 +pytz/zoneinfo/America/Porto_Velho,sha256=uSMV2hZWj-VyBhFBwC950wcThfN3jq6KlycESmQTLOA,562 +pytz/zoneinfo/America/Puerto_Rico,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Punta_Arenas,sha256=tR5uIf1351AWFqrqNtmXnhQWnKREmJaZqKBzaWRVMTQ,1902 +pytz/zoneinfo/America/Rainy_River,sha256=7P-_YQrneFcon7QKSTOnkiGjEppFDn3Z48MJ1qq8VBw,2868 +pytz/zoneinfo/America/Rankin_Inlet,sha256=nXgqjL3O2BV0em-Xk8qVRRZb_X0yQmHE6vmSSvI9Kzc,2066 +pytz/zoneinfo/America/Recife,sha256=bJ_HE0-JFio4-owpZ0pLO8U3ai0fiGu8QHL0DexLiLc,702 +pytz/zoneinfo/America/Regina,sha256=yjqT08pHbICYe83H8JmtaDBvCFqRv7Tfze3Y8xuXukw,980 +pytz/zoneinfo/America/Resolute,sha256=CnMU2dBI-63vt8-J0Q1Ropx-8b9pRCLjhvrycMIedGg,2066 +pytz/zoneinfo/America/Rio_Branco,sha256=0gpJUl46hQbp0P6Xj1S0NArIWeAryuuDXjsldvB5GHE,614 +pytz/zoneinfo/America/Rosario,sha256=uniNihhMHnr4XK4WpwiPUnrAT0YPmvzqB6f0hRLtXvY,1062 +pytz/zoneinfo/America/Santa_Isabel,sha256=57-Q9LSTNuTidz-lOTwDysmlCoeFUXSecvVVqNWburQ,2374 +pytz/zoneinfo/America/Santarem,sha256=VmZP9S5pPucFxyqAOV908EmWXQZvgCgWLmlJJTUl0LE,588 +pytz/zoneinfo/America/Santiago,sha256=0CDw13dCMUsoquMupoJgupkzAUNhDK6E0lVxURA7osA,2515 +pytz/zoneinfo/America/Santo_Domingo,sha256=DKtaEj8fQ92ybITTWU4Bm160S9pzJmUVbjaWRnenxU4,458 +pytz/zoneinfo/America/Sao_Paulo,sha256=BMBnRO4_4HjvO4t3njjrMGZr-ZPmegkvyvL8KPY6ZM4,1430 +pytz/zoneinfo/America/Scoresbysund,sha256=q-FbdTBuFYnig3J6l39kNjRIr3cCiRKeRENSz5h9qrg,1902 +pytz/zoneinfo/America/Shiprock,sha256=MugZwApDs8NI9TnXANQlUE8guNBowWQY0m-ptpPndck,2460 +pytz/zoneinfo/America/Sitka,sha256=aiS7Fk37hZpzZ9VkeJQeF-BqTLRC1QOTCgMAJwT8UxA,2329 +pytz/zoneinfo/America/St_Barthelemy,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/St_Johns,sha256=r1-17uKv27eZ3JsVkw_DLZQbo6wvjuuVu7C2pDsmOgI,3655 +pytz/zoneinfo/America/St_Kitts,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/St_Lucia,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/St_Thomas,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/St_Vincent,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Swift_Current,sha256=RRKOF7vZC8VvYxD8PP4J1_hUPayKBP7Lu80avRkfPDY,560 +pytz/zoneinfo/America/Tegucigalpa,sha256=EzOz7ntTlreMq69JZ2CcAb8Ps98V9bUMN480tpPIyw4,252 +pytz/zoneinfo/America/Thule,sha256=8xuPRaZU8RgO5ECqFYHYmnHioc81sBOailkVu8Y02i8,1502 +pytz/zoneinfo/America/Thunder_Bay,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Tijuana,sha256=57-Q9LSTNuTidz-lOTwDysmlCoeFUXSecvVVqNWburQ,2374 +pytz/zoneinfo/America/Toronto,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Tortola,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Vancouver,sha256=sknKH0jSPWam-DHfM35qXs8Nam7d5TFlkUI9Sgxryyg,2892 +pytz/zoneinfo/America/Virgin,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Whitehorse,sha256=TrR6PCnYG-mSClBMohqlP8qnYhXMUsydI-L-quXFxyM,1614 +pytz/zoneinfo/America/Winnipeg,sha256=7P-_YQrneFcon7QKSTOnkiGjEppFDn3Z48MJ1qq8VBw,2868 +pytz/zoneinfo/America/Yakutat,sha256=tFwnKbvwhyyn4LNTAn5ye_JWDdxjCerNDt7oOwUwO2M,2305 +pytz/zoneinfo/America/Yellowknife,sha256=-TkIfc3QlvaCf0p8COZ43Y1HRBAl-nARUi-JdXeK1vE,2332 +pytz/zoneinfo/Antarctica/Casey,sha256=3iBKp9lS8u7Sc9yhlcFUtWEcVIl8vLf9IJBJF6m1F58,370 +pytz/zoneinfo/Antarctica/Davis,sha256=XB12dEq0Q-3XkzBNTNC7G1fzH-WxxctIuZqI3zp8ypI,283 +pytz/zoneinfo/Antarctica/DumontDUrville,sha256=nB36HBWZTdh3TlP0DLFNz1KRQ0aHIfHbp7LC4Urp9fA,172 +pytz/zoneinfo/Antarctica/Macquarie,sha256=ie7RlaU8RHTorVVj-MX8StKMqx_oXf4UH2PUqpzcwe0,2260 +pytz/zoneinfo/Antarctica/Mawson,sha256=EjIFbqRdr2ZJBaI1XvoWRptnnW1LFrlhydxDDuIQjSI,185 +pytz/zoneinfo/Antarctica/McMurdo,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Antarctica/Palmer,sha256=HTZY0M8td7oUx5REPgRCHuqKg5V3fjJEi4lYBNL4Etg,1404 +pytz/zoneinfo/Antarctica/Rothera,sha256=_9NY-f8vkozQYrjbUHP5YjcICg0-LuyA9PnIeK123RU,150 +pytz/zoneinfo/Antarctica/South_Pole,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Antarctica/Syowa,sha256=oCKH7uafN8R1o-ijXGoT5U1JZxwvoLzJu_2Cqyi2hUM,151 +pytz/zoneinfo/Antarctica/Troll,sha256=fjcYppwr1FnjEssee-RLgGOANzoUyfjse-RGK46PR2E,1148 +pytz/zoneinfo/Antarctica/Vostok,sha256=F1ZOdZZDsVHwDJinksR-hjcqPzqOljvdreZIWFulJxY,151 +pytz/zoneinfo/Arctic/Longyearbyen,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Asia/Aden,sha256=oCKH7uafN8R1o-ijXGoT5U1JZxwvoLzJu_2Cqyi2hUM,151 +pytz/zoneinfo/Asia/Almaty,sha256=EEs-tB6Fo-eyUID5WZqe2KLIEQgKa_qZZXmwYH9BFCc,983 +pytz/zoneinfo/Asia/Amman,sha256=Qv4cXXw7KBQWE882cgj0kjQ3wh1vpV1orJ2v2Jjxr2U,1433 +pytz/zoneinfo/Asia/Anadyr,sha256=WqKnHo5IHSWZ08d2sS5ytHtv0MQMoczP3W9zbDDrbYU,1174 +pytz/zoneinfo/Asia/Aqtau,sha256=4n654FZtDssXSfhQszjZG5OmtbE2zo1KbiWcYrFJg00,969 +pytz/zoneinfo/Asia/Aqtobe,sha256=1oFHTb-ybcTqLXm0r1ZOVgdYMTHlGoNs-Pgvux50d3E,997 +pytz/zoneinfo/Asia/Ashgabat,sha256=-sfGnRumio7_Bs8w9YH4xRDWgjB3wBeW7c0C56Qqk64,605 +pytz/zoneinfo/Asia/Ashkhabad,sha256=-sfGnRumio7_Bs8w9YH4xRDWgjB3wBeW7c0C56Qqk64,605 +pytz/zoneinfo/Asia/Atyrau,sha256=_U8COUIE9nG_HKddZE1Q0sPuz3rMwfjwmfnVDY_vSmg,977 +pytz/zoneinfo/Asia/Baghdad,sha256=S-plKI4zCLqI0idGABEk3oRTazNyrIj2T98-EtWtZD8,969 +pytz/zoneinfo/Asia/Bahrain,sha256=wklGY3WPGp-z1OUwb_KOHzRTwBndt1RfDg9Uttt36G4,185 +pytz/zoneinfo/Asia/Baku,sha256=6_hq98SGG0j0JA8qYx96WcIMZSLW4w460QXh_OM_ccg,1213 +pytz/zoneinfo/Asia/Bangkok,sha256=hf_5PVegQcFSS60CjS80C7h-TGOrfQ4ncm83N8VmZkk,185 +pytz/zoneinfo/Asia/Barnaul,sha256=3zeUimLTMrIZE0vX6XHFvB3MoqExoVbE5CSm6GV0zf0,1207 +pytz/zoneinfo/Asia/Beirut,sha256=j4R3x7SSMs-yvrskcz9-3Wi1dQyuiBps1VwN13DR1Jc,2154 +pytz/zoneinfo/Asia/Bishkek,sha256=IOoUyjABILCkXu1rjCIqSwAufRYFklc5YAC4jdhVw6Q,969 +pytz/zoneinfo/Asia/Brunei,sha256=D5qtyWJ_SM8bTQeJJIYhqqojxlVKbrFC1EYMDU9GzXQ,469 +pytz/zoneinfo/Asia/Calcutta,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 +pytz/zoneinfo/Asia/Chita,sha256=LbSlS23swFkANUScg8zkNR0imANWNfOIaYd39HbLdIQ,1207 +pytz/zoneinfo/Asia/Choibalsan,sha256=atm7FmPwZGsftLM7vS1LltjcdaDC-DSg1cIdP2MF17I,935 +pytz/zoneinfo/Asia/Chongqing,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Chungking,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Colombo,sha256=w52L7bgT4m5hcgRuevIPY83xytfkBmkLhnKMwp16KsY,358 +pytz/zoneinfo/Asia/Dacca,sha256=-xulJ2KVhvKp6rlZLMydpw7oXVirk-riEH-181xPE54,323 +pytz/zoneinfo/Asia/Damascus,sha256=EthGheaHWmy5IrLCc9NmM3jvASQFHt8TsBF07I1tgbg,1873 +pytz/zoneinfo/Asia/Dhaka,sha256=-xulJ2KVhvKp6rlZLMydpw7oXVirk-riEH-181xPE54,323 +pytz/zoneinfo/Asia/Dili,sha256=0mUs0Utk-uW9deZV3cBUTpfWMgFvl0DyN29JuKvKMyw,213 +pytz/zoneinfo/Asia/Dubai,sha256=pmdhPhaJRwKwONvxiZNGeFSICjlWzyY9JlFHv-H9upY,151 +pytz/zoneinfo/Asia/Dushanbe,sha256=koYnnYWuFsBXd1vJfZsGdpwnbFHEwvkGBmSrrx3KIss,577 +pytz/zoneinfo/Asia/Famagusta,sha256=CFrcygd8ude5x6OEtfM_Dw0KYHoxpPPzq46KoHVxjjc,2028 +pytz/zoneinfo/Asia/Gaza,sha256=QyYf4BNHSVs8LgbaHLDNs_2sHwl_o4eaPu6JNFSpf_I,3808 +pytz/zoneinfo/Asia/Harbin,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Hebron,sha256=g2qdVa2qOen9PWC70Pr1Hln1Uh23ROAOaDhKl40hvjU,3836 +pytz/zoneinfo/Asia/Ho_Chi_Minh,sha256=bvC8fvT-K9BpW4a3g4js-HJsIHc9YNaYKwAw7Vbm9Hs,337 +pytz/zoneinfo/Asia/Hong_Kong,sha256=al_O4kPlq5JpgkLYjEaZzrcgiiLul9NC0R5B69JVWhc,1233 +pytz/zoneinfo/Asia/Hovd,sha256=Zn4PLGlD-URJDsbChor5bqWTzuAil2tbrGJW0j5TLbs,877 +pytz/zoneinfo/Asia/Irkutsk,sha256=IVuoXCwdeI-KIUfFkEt6yBjqYP3V9GTrF-_WLnffFzk,1229 +pytz/zoneinfo/Asia/Istanbul,sha256=Jk4wjndDta_uLWc8W1dWdjbavJJbsL5ROTmZboVnGKU,1933 +pytz/zoneinfo/Asia/Jakarta,sha256=TvEzBvSzfzFCdOsMAZ0QgR95JA5xf3kAZONhy5gEXRE,383 +pytz/zoneinfo/Asia/Jayapura,sha256=ihzUd-L8HUVqG-Na10MyPE-YYwjVFj-xerqjTN4EJZs,221 +pytz/zoneinfo/Asia/Jerusalem,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Asia/Kabul,sha256=JZEbo8bSj_L7HnXUm2gAUlNlCvJlRJhFkSHCg5o3ggk,194 +pytz/zoneinfo/Asia/Kamchatka,sha256=KY1PlJvRSNkY_5hyJBxj5DDweeYVQaBK05ZgL3kdcCY,1152 +pytz/zoneinfo/Asia/Karachi,sha256=iB-mWMTXUyfBwAkZdz8_UmEw0xsgxIub-KNI7akzhkk,379 +pytz/zoneinfo/Asia/Kashgar,sha256=F1ZOdZZDsVHwDJinksR-hjcqPzqOljvdreZIWFulJxY,151 +pytz/zoneinfo/Asia/Kathmandu,sha256=_RsfeSWbCr8kM4YRJi7Xv6hAEiHW14IFhsXsfhbPjoM,198 +pytz/zoneinfo/Asia/Katmandu,sha256=_RsfeSWbCr8kM4YRJi7Xv6hAEiHW14IFhsXsfhbPjoM,198 +pytz/zoneinfo/Asia/Khandyga,sha256=bKfmw6k5qYDQsEHG3Mv-VYis3YhCeV7qijDxfxQNn_g,1257 +pytz/zoneinfo/Asia/Kolkata,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 +pytz/zoneinfo/Asia/Krasnoyarsk,sha256=D5KE_1wWSD2YdixDy8n3LBNaAlE1_y3TWXw6NrxFKKA,1193 +pytz/zoneinfo/Asia/Kuala_Lumpur,sha256=XmeVImeqcJ8hJzm7TjAti1nWJAxawOqq7jIzDnHX2hI,401 +pytz/zoneinfo/Asia/Kuching,sha256=D5qtyWJ_SM8bTQeJJIYhqqojxlVKbrFC1EYMDU9GzXQ,469 +pytz/zoneinfo/Asia/Kuwait,sha256=oCKH7uafN8R1o-ijXGoT5U1JZxwvoLzJu_2Cqyi2hUM,151 +pytz/zoneinfo/Asia/Macao,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 +pytz/zoneinfo/Asia/Macau,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 +pytz/zoneinfo/Asia/Magadan,sha256=HccEEXBQvMmLoC_JE-zP_MlLAZ1WmNLQLfM3tJt55M4,1208 +pytz/zoneinfo/Asia/Makassar,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 +pytz/zoneinfo/Asia/Manila,sha256=ujfq0kl1EhxcYSOrG-FS750aNaYUt1TT4bFuK4EcL_c,328 +pytz/zoneinfo/Asia/Muscat,sha256=pmdhPhaJRwKwONvxiZNGeFSICjlWzyY9JlFHv-H9upY,151 +pytz/zoneinfo/Asia/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 +pytz/zoneinfo/Asia/Novokuznetsk,sha256=pyxxtSUtYDeVmFk0Cg-F33laZS0iKtde9_GJnL9f0KM,1151 +pytz/zoneinfo/Asia/Novosibirsk,sha256=5K2-Gx15ThlHfolyW85S5zREtAcMjeHBYWK4E8x2LdY,1207 +pytz/zoneinfo/Asia/Omsk,sha256=HyXIWItJXBKVHUzWcQPi1Mmd6ZLmZk-QhRUo9Kv2XOI,1193 +pytz/zoneinfo/Asia/Oral,sha256=WQT4qRmC9RI_ll8zB9FvkAL8ezGb8qoqWd75GTlC7kQ,991 +pytz/zoneinfo/Asia/Phnom_Penh,sha256=hf_5PVegQcFSS60CjS80C7h-TGOrfQ4ncm83N8VmZkk,185 +pytz/zoneinfo/Asia/Pontianak,sha256=inOXwuKtjKv1z_eliPZSIqjSt6whtuxhPeG1YpjU_BQ,353 +pytz/zoneinfo/Asia/Pyongyang,sha256=_-g3GnDAtfDX4XAktXH9jFouLUDmOovnjoOfvRpUDsE,237 +pytz/zoneinfo/Asia/Qatar,sha256=wklGY3WPGp-z1OUwb_KOHzRTwBndt1RfDg9Uttt36G4,185 +pytz/zoneinfo/Asia/Qostanay,sha256=Hlgrz7n7Ohgju_zXjTr8mOhzjUW9CzDInSNXLm2NwA0,997 +pytz/zoneinfo/Asia/Qyzylorda,sha256=JZLNN6NuLkqaWEeVaCZiW_gL6BrIFL9lr65iK7myVPg,1011 +pytz/zoneinfo/Asia/Rangoon,sha256=_YHASq4Z5YcUILIdhEzg27CGLzarUHPDHs1Dj0QgNGM,254 +pytz/zoneinfo/Asia/Riyadh,sha256=oCKH7uafN8R1o-ijXGoT5U1JZxwvoLzJu_2Cqyi2hUM,151 +pytz/zoneinfo/Asia/Saigon,sha256=bvC8fvT-K9BpW4a3g4js-HJsIHc9YNaYKwAw7Vbm9Hs,337 +pytz/zoneinfo/Asia/Sakhalin,sha256=xzAor82ihAe-yXEwC6OWiMzo9b6Z-oQl39NIkU5Hhbs,1188 +pytz/zoneinfo/Asia/Samarkand,sha256=zJKSRt3lEvd6Qvg9b49QAyO4cTJyVnTKyPYcyudpHxk,563 +pytz/zoneinfo/Asia/Seoul,sha256=LI9LsV3XcJC0l-KoQf8zI-y7rk-du57erS-N2Ptdi7Q,617 +pytz/zoneinfo/Asia/Shanghai,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Singapore,sha256=XmeVImeqcJ8hJzm7TjAti1nWJAxawOqq7jIzDnHX2hI,401 +pytz/zoneinfo/Asia/Srednekolymsk,sha256=efaaT8iFHrcccp-VZKNMvtTuPLNjG5V9JH5KKHhH3SI,1194 +pytz/zoneinfo/Asia/Taipei,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 +pytz/zoneinfo/Asia/Tashkent,sha256=apRPy251fSRy_ixsg3BOZNmUbHdO86P5-PdgC1Xws7U,577 +pytz/zoneinfo/Asia/Tbilisi,sha256=zQ-2bVq5_USUSbwN6q0qvWjD-HXkKaH4ifMVq1lEeIM,1021 +pytz/zoneinfo/Asia/Tehran,sha256=LQMch2TMA4wI23SQzoIrlZh0_KceXQegurwxCZ5YDlY,1248 +pytz/zoneinfo/Asia/Tel_Aviv,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Asia/Thimbu,sha256=G2nTQVEMmKlWt0B74_fUAL7KQ3YAu__J6HciiYs2IyU,189 +pytz/zoneinfo/Asia/Thimphu,sha256=G2nTQVEMmKlWt0B74_fUAL7KQ3YAu__J6HciiYs2IyU,189 +pytz/zoneinfo/Asia/Tokyo,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 +pytz/zoneinfo/Asia/Tomsk,sha256=cr0ULZgWBnQfzDiJeYmqpA7Xo5QRzurvrHsrbZsnhOQ,1207 +pytz/zoneinfo/Asia/Ujung_Pandang,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 +pytz/zoneinfo/Asia/Ulaanbaatar,sha256=qUkXRsTc_u7B90JxULSu7yzKbGtGfKcfEFIasGPC2ec,877 +pytz/zoneinfo/Asia/Ulan_Bator,sha256=qUkXRsTc_u7B90JxULSu7yzKbGtGfKcfEFIasGPC2ec,877 +pytz/zoneinfo/Asia/Urumqi,sha256=F1ZOdZZDsVHwDJinksR-hjcqPzqOljvdreZIWFulJxY,151 +pytz/zoneinfo/Asia/Ust-Nera,sha256=zsG8kgnw0Fcs5N2WwNTVmvWkTlpwf7Oo8y68HcXjYyw,1238 +pytz/zoneinfo/Asia/Vientiane,sha256=hf_5PVegQcFSS60CjS80C7h-TGOrfQ4ncm83N8VmZkk,185 +pytz/zoneinfo/Asia/Vladivostok,sha256=XMQLMh5SPbI6C4R3UO4KhbnG4hWVkHNedzCQeqxFk6A,1194 +pytz/zoneinfo/Asia/Yakutsk,sha256=PPNrRGgg9jefOUM-6M8XqaIm-ElfmRZSWAtSGKLzNXQ,1193 +pytz/zoneinfo/Asia/Yangon,sha256=_YHASq4Z5YcUILIdhEzg27CGLzarUHPDHs1Dj0QgNGM,254 +pytz/zoneinfo/Asia/Yekaterinburg,sha256=4NyEW6Xjr4UsWPh63HIPI4G6GT_tVG1Xkgc2xbwGjzA,1229 +pytz/zoneinfo/Asia/Yerevan,sha256=FM0pUA4NbTWBb_CsJ5KCLVrLoNmad7njBKqFrJBDoxE,1137 +pytz/zoneinfo/Atlantic/Azores,sha256=NyNrE2YIwL9yVddpECcYWwci5JzrfjxiIXP7RP0MrL8,3498 +pytz/zoneinfo/Atlantic/Bermuda,sha256=LNGKfMsnYvwImjTyzXrLhMOHHDu7qI67RbYNKvvI15I,2396 +pytz/zoneinfo/Atlantic/Canary,sha256=ymK9ufqphvNjDK3hzikN4GfkcR3QeCBiPKyVc6FjlbA,1897 +pytz/zoneinfo/Atlantic/Cape_Verde,sha256=o92pLdLFX_b9vUiq3rNpca4tupIO3dx9rNrnPcA8474,256 +pytz/zoneinfo/Atlantic/Faeroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 +pytz/zoneinfo/Atlantic/Faroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 +pytz/zoneinfo/Atlantic/Jan_Mayen,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Atlantic/Madeira,sha256=21Zcy0xRqDN3oY8jmjjO-LI7aC3G9mcS9ytaYg0g7ik,3503 +pytz/zoneinfo/Atlantic/Reykjavik,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Atlantic/South_Georgia,sha256=I9SAcPPumy6Xf9P7dg2aE16oxwDIqyKFqinJTC-XsgM,150 +pytz/zoneinfo/Atlantic/St_Helena,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Atlantic/Stanley,sha256=siEjXTAuTum_4XGtS98MBE34XW_5xgXShEX5OMnSFjo,1200 +pytz/zoneinfo/Australia/ACT,sha256=QsOFdYWxbbL4_9R7oZ-qYPRzNA3o1P6TIOp76GFgWQY,2190 +pytz/zoneinfo/Australia/Adelaide,sha256=ld2EbxU75oVgmPe703z-I6aqLg0Kmv62ZcCGzkT5R20,2208 +pytz/zoneinfo/Australia/Brisbane,sha256=eW6Qzze2t0-speJmmvt1JMzbkSadIKdE84XHc7JUtGc,419 +pytz/zoneinfo/Australia/Broken_Hill,sha256=3k_3ljTvS5GSfo7Xh6w71UgR3aAwYPBsnCJ-mlEYCqQ,2229 +pytz/zoneinfo/Australia/Canberra,sha256=QsOFdYWxbbL4_9R7oZ-qYPRzNA3o1P6TIOp76GFgWQY,2190 +pytz/zoneinfo/Australia/Currie,sha256=GLQSzgIfsWxOvmKOrhpfofWqINQf6h36NYy3mcq6gcg,2358 +pytz/zoneinfo/Australia/Darwin,sha256=fn0IZhIW98FAnzLig-_GBtW5LA54jajdeeUzg4tCGvo,325 +pytz/zoneinfo/Australia/Eucla,sha256=i1-XGG8I6E0dXIdWGF4DlkfDLWhiAxJ_3gMpt-nm_u4,456 +pytz/zoneinfo/Australia/Hobart,sha256=GLQSzgIfsWxOvmKOrhpfofWqINQf6h36NYy3mcq6gcg,2358 +pytz/zoneinfo/Australia/LHI,sha256=oyPFQzmRqWPrSXt9pNHQmEi_PvX11k2clknziOS6ud8,1846 +pytz/zoneinfo/Australia/Lindeman,sha256=xM6Udx22oLNoLR1Y7GQhHOYov8nw3xQNqgc_NVQ2JK4,475 +pytz/zoneinfo/Australia/Lord_Howe,sha256=oyPFQzmRqWPrSXt9pNHQmEi_PvX11k2clknziOS6ud8,1846 +pytz/zoneinfo/Australia/Melbourne,sha256=lvx_MQcunMc6u2smIrl8X427bLsXvjkgpCSdjYCTNBM,2190 +pytz/zoneinfo/Australia/NSW,sha256=QsOFdYWxbbL4_9R7oZ-qYPRzNA3o1P6TIOp76GFgWQY,2190 +pytz/zoneinfo/Australia/North,sha256=fn0IZhIW98FAnzLig-_GBtW5LA54jajdeeUzg4tCGvo,325 +pytz/zoneinfo/Australia/Perth,sha256=Al1DOUh4U_ofMUQSeVlzSyD3x7SUjP9dchSaBUGmeWg,446 +pytz/zoneinfo/Australia/Queensland,sha256=eW6Qzze2t0-speJmmvt1JMzbkSadIKdE84XHc7JUtGc,419 +pytz/zoneinfo/Australia/South,sha256=ld2EbxU75oVgmPe703z-I6aqLg0Kmv62ZcCGzkT5R20,2208 +pytz/zoneinfo/Australia/Sydney,sha256=QsOFdYWxbbL4_9R7oZ-qYPRzNA3o1P6TIOp76GFgWQY,2190 +pytz/zoneinfo/Australia/Tasmania,sha256=GLQSzgIfsWxOvmKOrhpfofWqINQf6h36NYy3mcq6gcg,2358 +pytz/zoneinfo/Australia/Victoria,sha256=lvx_MQcunMc6u2smIrl8X427bLsXvjkgpCSdjYCTNBM,2190 +pytz/zoneinfo/Australia/West,sha256=Al1DOUh4U_ofMUQSeVlzSyD3x7SUjP9dchSaBUGmeWg,446 +pytz/zoneinfo/Australia/Yancowinna,sha256=3k_3ljTvS5GSfo7Xh6w71UgR3aAwYPBsnCJ-mlEYCqQ,2229 +pytz/zoneinfo/Brazil/Acre,sha256=0gpJUl46hQbp0P6Xj1S0NArIWeAryuuDXjsldvB5GHE,614 +pytz/zoneinfo/Brazil/DeNoronha,sha256=feeRAijQqKylZgqe84nKhsFLycT5zIBm7mLIvdyGw4w,702 +pytz/zoneinfo/Brazil/East,sha256=BMBnRO4_4HjvO4t3njjrMGZr-ZPmegkvyvL8KPY6ZM4,1430 +pytz/zoneinfo/Brazil/West,sha256=F6RLOOeOi9lymZiQmQ9pR8tFpPZ6EguNdPfOc6BhXDE,590 +pytz/zoneinfo/CET,sha256=o4omkrM_IsITxooUo8krM921XfBdvRs9JhwGXGd-Ypg,2094 +pytz/zoneinfo/CST6CDT,sha256=WGbtZ1FwjRX6Jeo_TCXKsfeDs4V9uhXGJfcnLJhk3s0,2310 +pytz/zoneinfo/Canada/Atlantic,sha256=TZpmc5PwWoLfTfQoQ_b3U17BE2iVKSeNkR0Ho8mbTn8,3424 +pytz/zoneinfo/Canada/Central,sha256=7P-_YQrneFcon7QKSTOnkiGjEppFDn3Z48MJ1qq8VBw,2868 +pytz/zoneinfo/Canada/Eastern,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/Canada/Mountain,sha256=-TkIfc3QlvaCf0p8COZ43Y1HRBAl-nARUi-JdXeK1vE,2332 +pytz/zoneinfo/Canada/Newfoundland,sha256=r1-17uKv27eZ3JsVkw_DLZQbo6wvjuuVu7C2pDsmOgI,3655 +pytz/zoneinfo/Canada/Pacific,sha256=sknKH0jSPWam-DHfM35qXs8Nam7d5TFlkUI9Sgxryyg,2892 +pytz/zoneinfo/Canada/Saskatchewan,sha256=yjqT08pHbICYe83H8JmtaDBvCFqRv7Tfze3Y8xuXukw,980 +pytz/zoneinfo/Canada/Yukon,sha256=TrR6PCnYG-mSClBMohqlP8qnYhXMUsydI-L-quXFxyM,1614 +pytz/zoneinfo/Chile/Continental,sha256=0CDw13dCMUsoquMupoJgupkzAUNhDK6E0lVxURA7osA,2515 +pytz/zoneinfo/Chile/EasterIsland,sha256=QbubBs_xQlvKweAnurhyHjIK4ji77Gh4G-usXul6XVM,2219 +pytz/zoneinfo/Cuba,sha256=HUQeAuKBsEkI5SLZjqynXICOUVOajkKzKH5r-Ov5Odc,2416 +pytz/zoneinfo/EET,sha256=gGVsW5-qnI7ty8vqVK1ADWhunrvAT8kUC79GUf-_7G8,1908 +pytz/zoneinfo/EST,sha256=uKE_VPKfxGyYEsyqV_DdE2MW55vs_qUioOdIn5Goobc,114 +pytz/zoneinfo/EST5EDT,sha256=fwzEMT1jgnY2dDjd0EqDl26_7LC-oF48Bd4ng5311H0,2310 +pytz/zoneinfo/Egypt,sha256=Lft-GCLQhaSJm9VqUmsEFoHIS1Vhfa7pFJn9GZCpifs,2399 +pytz/zoneinfo/Eire,sha256=QOjSocO1cihNo59vQkWxvIFPRSxE9apz0KARVx1czEM,3492 +pytz/zoneinfo/Etc/GMT,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Etc/GMT+0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Etc/GMT+1,sha256=1Qzl2X9rQ_RXEf11yH09wQZCr_ph6UdFP7E0yu9s-IQ,116 +pytz/zoneinfo/Etc/GMT+10,sha256=JEQyQyQlkC0o6ZTdeVjZhCIOh6cK5TF7H00Pkls-sUI,117 +pytz/zoneinfo/Etc/GMT+11,sha256=tWvcvYMFCaE60nJVvDrrov7stJvs1KQYOyrhl3dzcUs,117 +pytz/zoneinfo/Etc/GMT+12,sha256=b70HEhErq8IJmq8x7cOZy4eR__3fq5uHHpjvPBEHqMA,117 +pytz/zoneinfo/Etc/GMT+2,sha256=T6Ep5zhslBKbYaECFUB6gUKh3iTZPyMoW1kjhonxrUo,116 +pytz/zoneinfo/Etc/GMT+3,sha256=QGoYrE04bUJ-OzL37dt2MZT5FxWNLpJDPVXgJbstYZA,116 +pytz/zoneinfo/Etc/GMT+4,sha256=RWrkNki-wV7X-coe0VvufBe6LrWVpkPJgia5QQYEnBo,116 +pytz/zoneinfo/Etc/GMT+5,sha256=oRmeC41dgYXT-zzyZIRKXN9IvdL2Da5nTuwmG2_prIA,116 +pytz/zoneinfo/Etc/GMT+6,sha256=d6dAnwiejyFI2n7AzFlFW0aFAT6zYNEjBIEG0uu0sbQ,116 +pytz/zoneinfo/Etc/GMT+7,sha256=TqjYbzd0YHpx1wisFg08J19wTpg6ztJLLongZY_lozs,116 +pytz/zoneinfo/Etc/GMT+8,sha256=th_8bIMmYgRPCesBrbmBhRr0jQO7whd70LiY9HfwJyk,116 +pytz/zoneinfo/Etc/GMT+9,sha256=Qq5E6iUS7JMJIymT7YoqlI8MtqtVy0mr9t6zWFtWc9Y,116 +pytz/zoneinfo/Etc/GMT-0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Etc/GMT-1,sha256=73F1eU8uAQGP3mcoB2q99CjfManGFHk3fefljp9pYC4,117 +pytz/zoneinfo/Etc/GMT-10,sha256=fKWWNwLBOp1OkKjtc1w9LIXJR1mTTD-JdvYflRy1IrU,118 +pytz/zoneinfo/Etc/GMT-11,sha256=D2S79n6psa9t9_2vj5wIrFpHH2OJLcCKP6vtwzFZINY,118 +pytz/zoneinfo/Etc/GMT-12,sha256=me4V6lmWI8gSr8H7N41WAD0Eww1anh_EF34Qr9UoSnI,118 +pytz/zoneinfo/Etc/GMT-13,sha256=xbmbG1BQA6Dlpa_iUwEGyJxW4a3t6lmawdPKAE8vbR8,118 +pytz/zoneinfo/Etc/GMT-14,sha256=PpXoREBh02qFpvxVMj2pV9IAzSQvBE7XPvnN9qSZ-Kc,118 +pytz/zoneinfo/Etc/GMT-2,sha256=ve6hWLdeuiLhqagaWLqMD6HNybS1chRwjudfTZ2bYBE,117 +pytz/zoneinfo/Etc/GMT-3,sha256=N77jILanuLDVkLsdujXZSu-dsHiwN5MIpwh7fMUifso,117 +pytz/zoneinfo/Etc/GMT-4,sha256=LSko5fVHqPl5zfwjGqkbMa_OFnvtpT6o_4xYxNz9n5o,117 +pytz/zoneinfo/Etc/GMT-5,sha256=uLaSR5Mb18HRTsAA5SveY9PAJ97dO8QzIWqNXe3wZb4,117 +pytz/zoneinfo/Etc/GMT-6,sha256=JSN-RUAphJ50fpIv7cYC6unrtrz9S1Wma-piDHlGe7c,117 +pytz/zoneinfo/Etc/GMT-7,sha256=vVAOF8xU9T9ESnw68c0SFXpcvkoopaiwTR0zbefHHSU,117 +pytz/zoneinfo/Etc/GMT-8,sha256=S7xFQbFMpiDZy4v5L4D9fCrjRIzzoLC5p8Se23xi7us,117 +pytz/zoneinfo/Etc/GMT-9,sha256=I5vHNmUK-Yyg_S1skFN44VGVzBgktjFgVQiDIKO4aMI,117 +pytz/zoneinfo/Etc/GMT0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Etc/Greenwich,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Etc/UCT,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/Etc/UTC,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/Etc/Universal,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/Etc/Zulu,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/Europe/Amsterdam,sha256=gS9Vrrbozend9HhuFetCVrIegs9fXSjaG60X2UVwysA,2933 +pytz/zoneinfo/Europe/Andorra,sha256=gTB5jCQmvIw3JJi1_vAcOYuhtzPBR6RXUx9gVV6p6ug,1742 +pytz/zoneinfo/Europe/Astrakhan,sha256=ZeGDZjwVVRoeR-J642zEnN26BPL58ViTJLbwnk7pLXk,1151 +pytz/zoneinfo/Europe/Athens,sha256=XDY-FBUddRyQHN8GxQLZ4awjuOlWlzlUdjv7OdXFNzA,2262 +pytz/zoneinfo/Europe/Belfast,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/Europe/Belgrade,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Berlin,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Europe/Bratislava,sha256=G9fdhUXmzx651BnyZ6V7AOYIV9EV5aMJMm44eJaLLZw,2301 +pytz/zoneinfo/Europe/Brussels,sha256=gS9Vrrbozend9HhuFetCVrIegs9fXSjaG60X2UVwysA,2933 +pytz/zoneinfo/Europe/Bucharest,sha256=nfg6-bU2D6DMEWb9EMIBR5kxnNsbDSx0UKfHH_ZzqFc,2184 +pytz/zoneinfo/Europe/Budapest,sha256=lNwqxWciBvw9ei81VQwIKHbC_ZDJjpgHU6HFg4wCUkY,2368 +pytz/zoneinfo/Europe/Busingen,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 +pytz/zoneinfo/Europe/Chisinau,sha256=p1J_rqFE13pL8cpBRrEFe-teCI8f0fKK4uTUy_4diF4,2390 +pytz/zoneinfo/Europe/Copenhagen,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Europe/Dublin,sha256=QOjSocO1cihNo59vQkWxvIFPRSxE9apz0KARVx1czEM,3492 +pytz/zoneinfo/Europe/Gibraltar,sha256=a87WpaBlvxI4gAU9OpQOkN8VUJbirVWYf-VfFLTIoS4,3068 +pytz/zoneinfo/Europe/Guernsey,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/Europe/Helsinki,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 +pytz/zoneinfo/Europe/Isle_of_Man,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/Europe/Istanbul,sha256=Jk4wjndDta_uLWc8W1dWdjbavJJbsL5ROTmZboVnGKU,1933 +pytz/zoneinfo/Europe/Jersey,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/Europe/Kaliningrad,sha256=s7GXSe1YvMcs7AiUhHNTA6I4nAOQn_Kmz_ZqJYO-LMM,1493 +pytz/zoneinfo/Europe/Kiev,sha256=-wrpG9jPuIKFP1NgBVvnxsMRf9L_h5z3J6Q3jj1AwNM,2120 +pytz/zoneinfo/Europe/Kirov,sha256=P7T2Zf5Eo6o4L4Dbg_BfiFjUgTj0dQXlrwY-QZ1eBVk,1185 +pytz/zoneinfo/Europe/Kyiv,sha256=-wrpG9jPuIKFP1NgBVvnxsMRf9L_h5z3J6Q3jj1AwNM,2120 +pytz/zoneinfo/Europe/Lisbon,sha256=mpUpxGexMhbOBImDLSQs5-GAk7pm7tg4qYW044Kkle0,3497 +pytz/zoneinfo/Europe/Ljubljana,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/London,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/Europe/Luxembourg,sha256=gS9Vrrbozend9HhuFetCVrIegs9fXSjaG60X2UVwysA,2933 +pytz/zoneinfo/Europe/Madrid,sha256=mkLX03rW3t0tmzKBIPe_noUvaFDErwC6_5ZPZZsWHOo,2614 +pytz/zoneinfo/Europe/Malta,sha256=EhKcbPL47765tWAiQ57cusaK2TaIQqZCgtJoEZs3Ud0,2620 +pytz/zoneinfo/Europe/Mariehamn,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 +pytz/zoneinfo/Europe/Minsk,sha256=KgPm0fHycntgd3xbTmmDl4O13Xh_9e2zUnd8XFSU29o,1307 +pytz/zoneinfo/Europe/Monaco,sha256=q3ehSIot1GZ6TyMHIjbg0oRf4ghAXuwbSDSYVim6evg,2962 +pytz/zoneinfo/Europe/Moscow,sha256=KmkofRcj6T8Ph28PJChm8JVp13uRvef6TZ0GuPzUiDw,1535 +pytz/zoneinfo/Europe/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 +pytz/zoneinfo/Europe/Oslo,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Europe/Paris,sha256=q3ehSIot1GZ6TyMHIjbg0oRf4ghAXuwbSDSYVim6evg,2962 +pytz/zoneinfo/Europe/Podgorica,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Prague,sha256=G9fdhUXmzx651BnyZ6V7AOYIV9EV5aMJMm44eJaLLZw,2301 +pytz/zoneinfo/Europe/Riga,sha256=hJ2_0m1taW9IuA-hMyP5n-WX7YOrR0heKszJhgljRWk,2198 +pytz/zoneinfo/Europe/Rome,sha256=1a3oLMSiMpSbh9QxV8hLLDVbZqash89iUO1urYC1AY8,2641 +pytz/zoneinfo/Europe/Samara,sha256=nXL0IxbT6qu10CNuaDHxx4W1OaAnaaKTtIJ9N9URMoU,1201 +pytz/zoneinfo/Europe/San_Marino,sha256=1a3oLMSiMpSbh9QxV8hLLDVbZqash89iUO1urYC1AY8,2641 +pytz/zoneinfo/Europe/Sarajevo,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Saratov,sha256=ygwjvXN13TgaWxjg6ysWEnHWNxwrVtkEbrk8t9bzVVw,1169 +pytz/zoneinfo/Europe/Simferopol,sha256=tzl7xdNVSZprNCul4YE5LSpoR9JoujmOq8VbbB8wHic,1469 +pytz/zoneinfo/Europe/Skopje,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Sofia,sha256=hCQKXfMNrnA5xHNw_uzTjKzVw4-Bvsq5oGO4yUCv5tY,2077 +pytz/zoneinfo/Europe/Stockholm,sha256=XuR19xoPwaMvrrhJ-MOcbnqmbW1B7HQrl7OnQ2s7BwE,2298 +pytz/zoneinfo/Europe/Tallinn,sha256=4a6JC0aIpMzqIV7O35zoG0LLJwkQq5AoXZ2ivkic6-w,2148 +pytz/zoneinfo/Europe/Tirane,sha256=ztlZyCS9WCXeVW8nBun3Tyi5HUY0EtFbiBbEc1gucuw,2084 +pytz/zoneinfo/Europe/Tiraspol,sha256=p1J_rqFE13pL8cpBRrEFe-teCI8f0fKK4uTUy_4diF4,2390 +pytz/zoneinfo/Europe/Ulyanovsk,sha256=c8Ad5p7CKj_1cCA7lVRpcPqbQXGYaX83cuu6uIFx-Bg,1253 +pytz/zoneinfo/Europe/Uzhgorod,sha256=-wrpG9jPuIKFP1NgBVvnxsMRf9L_h5z3J6Q3jj1AwNM,2120 +pytz/zoneinfo/Europe/Vaduz,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 +pytz/zoneinfo/Europe/Vatican,sha256=1a3oLMSiMpSbh9QxV8hLLDVbZqash89iUO1urYC1AY8,2641 +pytz/zoneinfo/Europe/Vienna,sha256=ZmI3kADE6bnrJEccqh73XXBY36L1G4DkpiTQImtNrUk,2200 +pytz/zoneinfo/Europe/Vilnius,sha256=UFzRX3orCTB8d9IzlxJPy5eUA2oBPuCu1UJl-2D7C3U,2162 +pytz/zoneinfo/Europe/Volgograd,sha256=RgFvt7mzZ-TtIKL9BVHmoNZLIeLIuiDdXeY10g2_vks,1193 +pytz/zoneinfo/Europe/Warsaw,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 +pytz/zoneinfo/Europe/Zagreb,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Zaporozhye,sha256=-wrpG9jPuIKFP1NgBVvnxsMRf9L_h5z3J6Q3jj1AwNM,2120 +pytz/zoneinfo/Europe/Zurich,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 +pytz/zoneinfo/Factory,sha256=aFFlKx93HXoJoF4SSuTlD8cZtJA-ne5oKzAa6eX2V4k,116 +pytz/zoneinfo/GB,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/GB-Eire,sha256=yFSVBw3KQmh99qHD7ngKJ8vLgvGER1Dqb2QoM6RNKbQ,3664 +pytz/zoneinfo/GMT,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/GMT+0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/GMT-0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/GMT0,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/Greenwich,sha256=bZ83iIPAefhsA4elVHqSxEmGnYBuB94QCEqwTwJJAY0,114 +pytz/zoneinfo/HST,sha256=1YkCncvgL9Z5CmUo4Vk8VbQmgA7ZAQ0PtE37j1yOli8,115 +pytz/zoneinfo/Hongkong,sha256=al_O4kPlq5JpgkLYjEaZzrcgiiLul9NC0R5B69JVWhc,1233 +pytz/zoneinfo/Iceland,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Indian/Antananarivo,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Chagos,sha256=2errXzKdFIcpU0L-XRhSHxhNabIzbI5lXV3Pq6lt40Y,185 +pytz/zoneinfo/Indian/Christmas,sha256=hf_5PVegQcFSS60CjS80C7h-TGOrfQ4ncm83N8VmZkk,185 +pytz/zoneinfo/Indian/Cocos,sha256=_YHASq4Z5YcUILIdhEzg27CGLzarUHPDHs1Dj0QgNGM,254 +pytz/zoneinfo/Indian/Comoro,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Kerguelen,sha256=F73ffVfBoUoHre0-DwsiQrYJcLpPOW-JJGk3n88lM5U,185 +pytz/zoneinfo/Indian/Mahe,sha256=pmdhPhaJRwKwONvxiZNGeFSICjlWzyY9JlFHv-H9upY,151 +pytz/zoneinfo/Indian/Maldives,sha256=F73ffVfBoUoHre0-DwsiQrYJcLpPOW-JJGk3n88lM5U,185 +pytz/zoneinfo/Indian/Mauritius,sha256=Znqrc1chimlciJsYBOl0NvIHnrNdCxncGxWczq1PBeI,227 +pytz/zoneinfo/Indian/Mayotte,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Reunion,sha256=pmdhPhaJRwKwONvxiZNGeFSICjlWzyY9JlFHv-H9upY,151 +pytz/zoneinfo/Iran,sha256=LQMch2TMA4wI23SQzoIrlZh0_KceXQegurwxCZ5YDlY,1248 +pytz/zoneinfo/Israel,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 +pytz/zoneinfo/Japan,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 +pytz/zoneinfo/Kwajalein,sha256=TmZ_0f-ySQ-saBAlRXV0f49Itwne51VBXn6rWcrWqHQ,302 +pytz/zoneinfo/Libya,sha256=W1dptGD70T7ppGoo0fczFQeDiIp0nultLNPV66MwB2c,625 +pytz/zoneinfo/MET,sha256=i3CKSuP4N_PAj7o-Cbk8zPEdFs0CWWBCAfg2JXDx5V8,2094 +pytz/zoneinfo/MST,sha256=6IQwvtT12Bz1pTiqFuoVxNY-4ViS7ZrYHo5nPWwzKPw,114 +pytz/zoneinfo/MST7MDT,sha256=910Ek32FKoSyZWY_H19VHaVvqb-JsvnWTOOHvhrKsE0,2310 +pytz/zoneinfo/Mexico/BajaNorte,sha256=57-Q9LSTNuTidz-lOTwDysmlCoeFUXSecvVVqNWburQ,2374 +pytz/zoneinfo/Mexico/BajaSur,sha256=RQQVwlEVHRp2X-c_0hJ46y54abTlqUuLkyrUUicyc5g,1128 +pytz/zoneinfo/Mexico/General,sha256=A5MlfDUZ4O1-jMTRt0WPem7qqcW0Nrslls1hlc8C4-Q,1222 +pytz/zoneinfo/NZ,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/NZ-CHAT,sha256=xhexVc5lfJ_qAv2d3HrII6lfRSxKZYBAjY2zpYkCGE8,2054 +pytz/zoneinfo/Navajo,sha256=MugZwApDs8NI9TnXANQlUE8guNBowWQY0m-ptpPndck,2460 +pytz/zoneinfo/PRC,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/PST8PDT,sha256=Q7TCLkE69a6g7mPoPAkqhg-0dStyiAC0jVlM72KG_R8,2310 +pytz/zoneinfo/Pacific/Apia,sha256=M3QKsp75Q7H1X3aeE_9ZqQli9aEkNCCQctZQ5sEKu00,598 +pytz/zoneinfo/Pacific/Auckland,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Pacific/Bougainville,sha256=hWE86eXnNx-vABbp7-YSIqWyecHPMIWLftVloAoPhL8,254 +pytz/zoneinfo/Pacific/Chatham,sha256=xhexVc5lfJ_qAv2d3HrII6lfRSxKZYBAjY2zpYkCGE8,2054 +pytz/zoneinfo/Pacific/Chuuk,sha256=nB36HBWZTdh3TlP0DLFNz1KRQ0aHIfHbp7LC4Urp9fA,172 +pytz/zoneinfo/Pacific/Easter,sha256=QbubBs_xQlvKweAnurhyHjIK4ji77Gh4G-usXul6XVM,2219 +pytz/zoneinfo/Pacific/Efate,sha256=oSxNcQYx5-1FU2_yHzHI-hT-dMJcPxzy4XmdI1UxXAo,524 +pytz/zoneinfo/Pacific/Enderbury,sha256=HNTAKrsH_R2W3QRlKcmNld5KcXdP0ygXCjEovc1i-6Q,220 +pytz/zoneinfo/Pacific/Fakaofo,sha256=qOodpTMKjztvZIXVLe_f_kZ6WcHl9fCLE9ZsyvdFKLI,186 +pytz/zoneinfo/Pacific/Fiji,sha256=jB5FbOsCnHVQQ2ohPiWEQUPhG6JybB3Nog3qT6WJQ0I,564 +pytz/zoneinfo/Pacific/Funafuti,sha256=UyaKimsR8LjgL8Z2g65I0HTvr3tMZuA2wUeBB6_Zp9c,152 +pytz/zoneinfo/Pacific/Galapagos,sha256=_GJUYOjSiIjoNBO2qdq23isLMJ4NCVk3DKIRGeDc8BA,224 +pytz/zoneinfo/Pacific/Gambier,sha256=gAS7gr1HH_re0uYnL6eWo5KGJ-B5QaiM8mV2cY5mQxE,150 +pytz/zoneinfo/Pacific/Guadalcanal,sha256=M4kTWqaSQaV1AMhyLSvmwoBJF7X9icrILbvQJwp940g,152 +pytz/zoneinfo/Pacific/Guam,sha256=Ex9znmf6rNfGze6gNpZJCMr1TT4rkl2SnrhecrdJufI,494 +pytz/zoneinfo/Pacific/Honolulu,sha256=fwPRv1Jk56sCOi75uZfd_Iy2k2aSQHx3B2K5xUlSPzM,329 +pytz/zoneinfo/Pacific/Johnston,sha256=fwPRv1Jk56sCOi75uZfd_Iy2k2aSQHx3B2K5xUlSPzM,329 +pytz/zoneinfo/Pacific/Kanton,sha256=HNTAKrsH_R2W3QRlKcmNld5KcXdP0ygXCjEovc1i-6Q,220 +pytz/zoneinfo/Pacific/Kiritimati,sha256=hYk1Ooz-Lj1PuZCbNV2WJIvOLtCwSwq2u63cb1Z-3NQ,224 +pytz/zoneinfo/Pacific/Kosrae,sha256=Q0jrb4zeDrd61bU4V8TqjMc0Iep8rWZyZqJ0uqsunxs,337 +pytz/zoneinfo/Pacific/Kwajalein,sha256=TmZ_0f-ySQ-saBAlRXV0f49Itwne51VBXn6rWcrWqHQ,302 +pytz/zoneinfo/Pacific/Majuro,sha256=UyaKimsR8LjgL8Z2g65I0HTvr3tMZuA2wUeBB6_Zp9c,152 +pytz/zoneinfo/Pacific/Marquesas,sha256=FTxPJTWtk48LVb3N2U64KLpLsmvu0DQBubTCg-dvyGM,159 +pytz/zoneinfo/Pacific/Midway,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Nauru,sha256=9ASKgLHB-8nsTEK1ApzfTH0yQtbNAmGX-JI7uHZiqnA,238 +pytz/zoneinfo/Pacific/Niue,sha256=OllXxukncR7a-SMmdFox5az1xpIPMhbahQhtObmpuDM,189 +pytz/zoneinfo/Pacific/Norfolk,sha256=DMdX1Bm18lzNuiCWzwfeHUMRGXPS8v5AWnh-_EX_AZw,866 +pytz/zoneinfo/Pacific/Noumea,sha256=tkHxxnxsXTOqz3YzWi0mkhTCIONzg-W7EpSRMdPjKdQ,290 +pytz/zoneinfo/Pacific/Pago_Pago,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Palau,sha256=aN2HbT0reqwKrtLKDK9M2zb0d0ikdNlTrrntVxdH66o,166 +pytz/zoneinfo/Pacific/Pitcairn,sha256=U4jAUuvsRNoy8XrPa16YpcXCcqHJY0u6JvCNgPEWO1c,188 +pytz/zoneinfo/Pacific/Pohnpei,sha256=M4kTWqaSQaV1AMhyLSvmwoBJF7X9icrILbvQJwp940g,152 +pytz/zoneinfo/Pacific/Ponape,sha256=M4kTWqaSQaV1AMhyLSvmwoBJF7X9icrILbvQJwp940g,152 +pytz/zoneinfo/Pacific/Port_Moresby,sha256=nB36HBWZTdh3TlP0DLFNz1KRQ0aHIfHbp7LC4Urp9fA,172 +pytz/zoneinfo/Pacific/Rarotonga,sha256=wPEsoXbyDnuhfzkgLvUqhSzrMx_FD42uAPluSPMh3Bc,589 +pytz/zoneinfo/Pacific/Saipan,sha256=Ex9znmf6rNfGze6gNpZJCMr1TT4rkl2SnrhecrdJufI,494 +pytz/zoneinfo/Pacific/Samoa,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Tahiti,sha256=BRff9G3E-iWKhOWR1Wu02Z0iMgjrwDXV-XNrqItXdTY,151 +pytz/zoneinfo/Pacific/Tarawa,sha256=UyaKimsR8LjgL8Z2g65I0HTvr3tMZuA2wUeBB6_Zp9c,152 +pytz/zoneinfo/Pacific/Tongatapu,sha256=OppBZqTAZib9HY7U9AC-JavO7m6NxPGUtUfPQAl9oBY,358 +pytz/zoneinfo/Pacific/Truk,sha256=nB36HBWZTdh3TlP0DLFNz1KRQ0aHIfHbp7LC4Urp9fA,172 +pytz/zoneinfo/Pacific/Wake,sha256=UyaKimsR8LjgL8Z2g65I0HTvr3tMZuA2wUeBB6_Zp9c,152 +pytz/zoneinfo/Pacific/Wallis,sha256=UyaKimsR8LjgL8Z2g65I0HTvr3tMZuA2wUeBB6_Zp9c,152 +pytz/zoneinfo/Pacific/Yap,sha256=nB36HBWZTdh3TlP0DLFNz1KRQ0aHIfHbp7LC4Urp9fA,172 +pytz/zoneinfo/Poland,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 +pytz/zoneinfo/Portugal,sha256=mpUpxGexMhbOBImDLSQs5-GAk7pm7tg4qYW044Kkle0,3497 +pytz/zoneinfo/ROC,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 +pytz/zoneinfo/ROK,sha256=LI9LsV3XcJC0l-KoQf8zI-y7rk-du57erS-N2Ptdi7Q,617 +pytz/zoneinfo/Singapore,sha256=XmeVImeqcJ8hJzm7TjAti1nWJAxawOqq7jIzDnHX2hI,401 +pytz/zoneinfo/Turkey,sha256=Jk4wjndDta_uLWc8W1dWdjbavJJbsL5ROTmZboVnGKU,1933 +pytz/zoneinfo/UCT,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/US/Alaska,sha256=oZA1NSPS2BWdymYpnCHFO8BlYVS-ll5KLg2Ez9CbETs,2371 +pytz/zoneinfo/US/Aleutian,sha256=IB1DhwJQAKbhPJ9jHLf8zW5Dad7HIkBS-dhv64E1OlM,2356 +pytz/zoneinfo/US/Arizona,sha256=illz0sYuLL8lIPK0Tkou6dL0Vck_D0W_3rRTOvFYRmQ,360 +pytz/zoneinfo/US/Central,sha256=_roybr6I6sIAF6cYdIxGxoRpoef153Fty48dQ6bm9oY,3592 +pytz/zoneinfo/US/East-Indiana,sha256=kNKy9Kj9ICsiYYfCCbAggzMA7exf-GpGPMxoXocHUyw,1682 +pytz/zoneinfo/US/Eastern,sha256=6e0H177gx2qdRC0JHvHwFmj-58TyYBTAqGixn-bBipU,3552 +pytz/zoneinfo/US/Hawaii,sha256=fwPRv1Jk56sCOi75uZfd_Iy2k2aSQHx3B2K5xUlSPzM,329 +pytz/zoneinfo/US/Indiana-Starke,sha256=CsvZ5BKw2qVav3x_F8CU9taJdDk7jX41Cfsqms6jXV8,2444 +pytz/zoneinfo/US/Michigan,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 +pytz/zoneinfo/US/Mountain,sha256=MugZwApDs8NI9TnXANQlUE8guNBowWQY0m-ptpPndck,2460 +pytz/zoneinfo/US/Pacific,sha256=aJd7ua1tGG_vxser02AQpm4wAI3LLTdgh6QcSYYecmg,2852 +pytz/zoneinfo/US/Samoa,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/UTC,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/Universal,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/W-SU,sha256=KmkofRcj6T8Ph28PJChm8JVp13uRvef6TZ0GuPzUiDw,1535 +pytz/zoneinfo/WET,sha256=Sc0l03EfVs_aIi17I4KyZJFkwiAHat5BgpjuuFDhgQ0,1905 +pytz/zoneinfo/Zulu,sha256=i4WEZ5GrLIpUY8g6W-PAQ-JXDXRIQ01BOYlp7Ufj5vI,114 +pytz/zoneinfo/iso3166.tab,sha256=gQmErUEP8d4llZmd-JcsEr_wN4EqizvWxx50a2wsBMw,4446 +pytz/zoneinfo/leapseconds,sha256=hxBfINJuU6Z6N7NQt3SECA9OWlBLFrzDhK2tYynZ7_U,3392 +pytz/zoneinfo/tzdata.zi,sha256=3_MCtqxasI-LYbAIV8H2pT9R1k6rCB95qTKaavZYYd4,109314 +pytz/zoneinfo/zone.tab,sha256=4sq6yxD3v1vIyrOY_ii7qiJrHq_aNSUtrN87WdXeg60,18855 +pytz/zoneinfo/zone1970.tab,sha256=QKiBcMzCUUjF6j0uOliv2GFfDc2VSbktmzhZf97v6i0,17551 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..ef99c6cf3283b50a273ac4c6d009a0aa85597070 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..af44f198c687e245aada835efbab2f75ed2c9baf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/top_level.txt @@ -0,0 +1 @@ +pytz diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/zip-safe b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/zip-safe new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz-2023.2.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fac456913bd33985900bbf66cd8efc7404b4555a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__init__.py @@ -0,0 +1,1555 @@ +''' +datetime.tzinfo timezone definitions generated from the +Olson timezone database: + + ftp://elsie.nci.nih.gov/pub/tz*.tar.gz + +See the datetime section of the Python Library Reference for information +on how to use these modules. +''' + +import sys +import datetime +import os.path + +from pytz.exceptions import AmbiguousTimeError +from pytz.exceptions import InvalidTimeError +from pytz.exceptions import NonExistentTimeError +from pytz.exceptions import UnknownTimeZoneError +from pytz.lazy import LazyDict, LazyList, LazySet # noqa +from pytz.tzinfo import unpickler, BaseTzInfo +from pytz.tzfile import build_tzinfo + + +# The IANA (nee Olson) database is updated several times a year. +OLSON_VERSION = '2023b' +VERSION = '2023.2' # pip compatible version number. +__version__ = VERSION + +OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling + +__all__ = [ + 'timezone', 'utc', 'country_timezones', 'country_names', + 'AmbiguousTimeError', 'InvalidTimeError', + 'NonExistentTimeError', 'UnknownTimeZoneError', + 'all_timezones', 'all_timezones_set', + 'common_timezones', 'common_timezones_set', + 'BaseTzInfo', 'FixedOffset', +] + + +if sys.version_info[0] > 2: # Python 3.x + + # Python 3.x doesn't have unicode(), making writing code + # for Python 2.3 and Python 3.x a pain. + unicode = str + + def ascii(s): + r""" + >>> ascii('Hello') + 'Hello' + >>> ascii('\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + UnicodeEncodeError: ... + """ + if type(s) == bytes: + s = s.decode('ASCII') + else: + s.encode('ASCII') # Raise an exception if not ASCII + return s # But the string - not a byte string. + +else: # Python 2.x + + def ascii(s): + r""" + >>> ascii('Hello') + 'Hello' + >>> ascii(u'Hello') + 'Hello' + >>> ascii(u'\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + UnicodeEncodeError: ... + """ + return s.encode('ASCII') + + +def open_resource(name): + """Open a resource from the zoneinfo subdir for reading. + + Uses the pkg_resources module if available and no standard file + found at the calculated location. + + It is possible to specify different location for zoneinfo + subdir by using the PYTZ_TZDATADIR environment variable. + """ + name_parts = name.lstrip('/').split('/') + for part in name_parts: + if part == os.path.pardir or os.sep in part: + raise ValueError('Bad path segment: %r' % part) + zoneinfo_dir = os.environ.get('PYTZ_TZDATADIR', None) + if zoneinfo_dir is not None: + filename = os.path.join(zoneinfo_dir, *name_parts) + else: + filename = os.path.join(os.path.dirname(__file__), + 'zoneinfo', *name_parts) + if not os.path.exists(filename): + # http://bugs.launchpad.net/bugs/383171 - we avoid using this + # unless absolutely necessary to help when a broken version of + # pkg_resources is installed. + try: + from pkg_resources import resource_stream + except ImportError: + resource_stream = None + + if resource_stream is not None: + return resource_stream(__name__, 'zoneinfo/' + name) + return open(filename, 'rb') + + +def resource_exists(name): + """Return true if the given resource exists""" + try: + if os.environ.get('PYTZ_SKIPEXISTSCHECK', ''): + # In "standard" distributions, we can assume that + # all the listed timezones are present. As an + # import-speed optimization, you can set the + # PYTZ_SKIPEXISTSCHECK flag to skip checking + # for the presence of the resource file on disk. + return True + open_resource(name).close() + return True + except IOError: + return False + + +_tzinfo_cache = {} + + +def timezone(zone): + r''' Return a datetime.tzinfo implementation for the given timezone + + >>> from datetime import datetime, timedelta + >>> utc = timezone('UTC') + >>> eastern = timezone('US/Eastern') + >>> eastern.zone + 'US/Eastern' + >>> timezone(unicode('US/Eastern')) is eastern + True + >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) + >>> loc_dt = utc_dt.astimezone(eastern) + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> loc_dt.strftime(fmt) + '2002-10-27 01:00:00 EST (-0500)' + >>> (loc_dt - timedelta(minutes=10)).strftime(fmt) + '2002-10-27 00:50:00 EST (-0500)' + >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt) + '2002-10-27 01:50:00 EDT (-0400)' + >>> (loc_dt + timedelta(minutes=10)).strftime(fmt) + '2002-10-27 01:10:00 EST (-0500)' + + Raises UnknownTimeZoneError if passed an unknown zone. + + >>> try: + ... timezone('Asia/Shangri-La') + ... except UnknownTimeZoneError: + ... print('Unknown') + Unknown + + >>> try: + ... timezone(unicode('\N{TRADE MARK SIGN}')) + ... except UnknownTimeZoneError: + ... print('Unknown') + Unknown + + ''' + if zone is None: + raise UnknownTimeZoneError(None) + + if zone.upper() == 'UTC': + return utc + + try: + zone = ascii(zone) + except UnicodeEncodeError: + # All valid timezones are ASCII + raise UnknownTimeZoneError(zone) + + zone = _case_insensitive_zone_lookup(_unmunge_zone(zone)) + if zone not in _tzinfo_cache: + if zone in all_timezones_set: # noqa + fp = open_resource(zone) + try: + _tzinfo_cache[zone] = build_tzinfo(zone, fp) + finally: + fp.close() + else: + raise UnknownTimeZoneError(zone) + + return _tzinfo_cache[zone] + + +def _unmunge_zone(zone): + """Undo the time zone name munging done by older versions of pytz.""" + return zone.replace('_plus_', '+').replace('_minus_', '-') + + +_all_timezones_lower_to_standard = None + + +def _case_insensitive_zone_lookup(zone): + """case-insensitively matching timezone, else return zone unchanged""" + global _all_timezones_lower_to_standard + if _all_timezones_lower_to_standard is None: + _all_timezones_lower_to_standard = dict((tz.lower(), tz) for tz in _all_timezones_unchecked) # noqa + return _all_timezones_lower_to_standard.get(zone.lower()) or zone # noqa + + +ZERO = datetime.timedelta(0) +HOUR = datetime.timedelta(hours=1) + + +class UTC(BaseTzInfo): + """UTC + + Optimized UTC implementation. It unpickles using the single module global + instance defined beneath this class declaration. + """ + zone = "UTC" + + _utcoffset = ZERO + _dst = ZERO + _tzname = zone + + def fromutc(self, dt): + if dt.tzinfo is None: + return self.localize(dt) + return super(utc.__class__, self).fromutc(dt) + + def utcoffset(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def dst(self, dt): + return ZERO + + def __reduce__(self): + return _UTC, () + + def localize(self, dt, is_dst=False): + '''Convert naive time to local time''' + if dt.tzinfo is not None: + raise ValueError('Not naive datetime (tzinfo is already set)') + return dt.replace(tzinfo=self) + + def normalize(self, dt, is_dst=False): + '''Correct the timezone information on the given datetime''' + if dt.tzinfo is self: + return dt + if dt.tzinfo is None: + raise ValueError('Naive time - no tzinfo set') + return dt.astimezone(self) + + def __repr__(self): + return "<UTC>" + + def __str__(self): + return "UTC" + + +UTC = utc = UTC() # UTC is a singleton + + +def _UTC(): + """Factory function for utc unpickling. + + Makes sure that unpickling a utc instance always returns the same + module global. + + These examples belong in the UTC class above, but it is obscured; or in + the README.rst, but we are not depending on Python 2.4 so integrating + the README.rst examples with the unit tests is not trivial. + + >>> import datetime, pickle + >>> dt = datetime.datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) + >>> naive = dt.replace(tzinfo=None) + >>> p = pickle.dumps(dt, 1) + >>> naive_p = pickle.dumps(naive, 1) + >>> len(p) - len(naive_p) + 17 + >>> new = pickle.loads(p) + >>> new == dt + True + >>> new is dt + False + >>> new.tzinfo is dt.tzinfo + True + >>> utc is UTC is timezone('UTC') + True + >>> utc is timezone('GMT') + False + """ + return utc + + +_UTC.__safe_for_unpickling__ = True + + +def _p(*args): + """Factory function for unpickling pytz tzinfo instances. + + Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle + by shortening the path. + """ + return unpickler(*args) + + +_p.__safe_for_unpickling__ = True + + +class _CountryTimezoneDict(LazyDict): + """Map ISO 3166 country code to a list of timezone names commonly used + in that country. + + iso3166_code is the two letter code used to identify the country. + + >>> def print_list(list_of_strings): + ... 'We use a helper so doctests work under Python 2.3 -> 3.x' + ... for s in list_of_strings: + ... print(s) + + >>> print_list(country_timezones['nz']) + Pacific/Auckland + Pacific/Chatham + >>> print_list(country_timezones['ch']) + Europe/Zurich + >>> print_list(country_timezones['CH']) + Europe/Zurich + >>> print_list(country_timezones[unicode('ch')]) + Europe/Zurich + >>> print_list(country_timezones['XXX']) + Traceback (most recent call last): + ... + KeyError: 'XXX' + + Previously, this information was exposed as a function rather than a + dictionary. This is still supported:: + + >>> print_list(country_timezones('nz')) + Pacific/Auckland + Pacific/Chatham + """ + def __call__(self, iso3166_code): + """Backwards compatibility.""" + return self[iso3166_code] + + def _fill(self): + data = {} + zone_tab = open_resource('zone.tab') + try: + for line in zone_tab: + line = line.decode('UTF-8') + if line.startswith('#'): + continue + code, coordinates, zone = line.split(None, 4)[:3] + if zone not in all_timezones_set: # noqa + continue + try: + data[code].append(zone) + except KeyError: + data[code] = [zone] + self.data = data + finally: + zone_tab.close() + + +country_timezones = _CountryTimezoneDict() + + +class _CountryNameDict(LazyDict): + '''Dictionary proving ISO3166 code -> English name. + + >>> print(country_names['au']) + Australia + ''' + def _fill(self): + data = {} + zone_tab = open_resource('iso3166.tab') + try: + for line in zone_tab.readlines(): + line = line.decode('UTF-8') + if line.startswith('#'): + continue + code, name = line.split(None, 1) + data[code] = name.strip() + self.data = data + finally: + zone_tab.close() + + +country_names = _CountryNameDict() + + +# Time-zone info based solely on fixed offsets + +class _FixedOffset(datetime.tzinfo): + + zone = None # to match the standard pytz API + + def __init__(self, minutes): + if abs(minutes) >= 1440: + raise ValueError("absolute offset is too large", minutes) + self._minutes = minutes + self._offset = datetime.timedelta(minutes=minutes) + + def utcoffset(self, dt): + return self._offset + + def __reduce__(self): + return FixedOffset, (self._minutes, ) + + def dst(self, dt): + return ZERO + + def tzname(self, dt): + return None + + def __repr__(self): + return 'pytz.FixedOffset(%d)' % self._minutes + + def localize(self, dt, is_dst=False): + '''Convert naive time to local time''' + if dt.tzinfo is not None: + raise ValueError('Not naive datetime (tzinfo is already set)') + return dt.replace(tzinfo=self) + + def normalize(self, dt, is_dst=False): + '''Correct the timezone information on the given datetime''' + if dt.tzinfo is self: + return dt + if dt.tzinfo is None: + raise ValueError('Naive time - no tzinfo set') + return dt.astimezone(self) + + +def FixedOffset(offset, _tzinfos={}): + """return a fixed-offset timezone based off a number of minutes. + + >>> one = FixedOffset(-330) + >>> one + pytz.FixedOffset(-330) + >>> str(one.utcoffset(datetime.datetime.now())) + '-1 day, 18:30:00' + >>> str(one.dst(datetime.datetime.now())) + '0:00:00' + + >>> two = FixedOffset(1380) + >>> two + pytz.FixedOffset(1380) + >>> str(two.utcoffset(datetime.datetime.now())) + '23:00:00' + >>> str(two.dst(datetime.datetime.now())) + '0:00:00' + + The datetime.timedelta must be between the range of -1 and 1 day, + non-inclusive. + + >>> FixedOffset(1440) + Traceback (most recent call last): + ... + ValueError: ('absolute offset is too large', 1440) + + >>> FixedOffset(-1440) + Traceback (most recent call last): + ... + ValueError: ('absolute offset is too large', -1440) + + An offset of 0 is special-cased to return UTC. + + >>> FixedOffset(0) is UTC + True + + There should always be only one instance of a FixedOffset per timedelta. + This should be true for multiple creation calls. + + >>> FixedOffset(-330) is one + True + >>> FixedOffset(1380) is two + True + + It should also be true for pickling. + + >>> import pickle + >>> pickle.loads(pickle.dumps(one)) is one + True + >>> pickle.loads(pickle.dumps(two)) is two + True + """ + if offset == 0: + return UTC + + info = _tzinfos.get(offset) + if info is None: + # We haven't seen this one before. we need to save it. + + # Use setdefault to avoid a race condition and make sure we have + # only one + info = _tzinfos.setdefault(offset, _FixedOffset(offset)) + + return info + + +FixedOffset.__safe_for_unpickling__ = True + + +def _test(): + import doctest + sys.path.insert(0, os.pardir) + import pytz + return doctest.testmod(pytz) + + +if __name__ == '__main__': + _test() +_all_timezones_unchecked = \ +['Africa/Abidjan', + 'Africa/Accra', + 'Africa/Addis_Ababa', + 'Africa/Algiers', + 'Africa/Asmara', + 'Africa/Asmera', + 'Africa/Bamako', + 'Africa/Bangui', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Blantyre', + 'Africa/Brazzaville', + 'Africa/Bujumbura', + 'Africa/Cairo', + 'Africa/Casablanca', + 'Africa/Ceuta', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Douala', + 'Africa/El_Aaiun', + 'Africa/Freetown', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Kigali', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Lome', + 'Africa/Luanda', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Malabo', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Africa/Mogadishu', + 'Africa/Monrovia', + 'Africa/Nairobi', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Porto-Novo', + 'Africa/Sao_Tome', + 'Africa/Timbuktu', + 'Africa/Tripoli', + 'Africa/Tunis', + 'Africa/Windhoek', + 'America/Adak', + 'America/Anchorage', + 'America/Anguilla', + 'America/Antigua', + 'America/Araguaina', + 'America/Argentina/Buenos_Aires', + 'America/Argentina/Catamarca', + 'America/Argentina/ComodRivadavia', + 'America/Argentina/Cordoba', + 'America/Argentina/Jujuy', + 'America/Argentina/La_Rioja', + 'America/Argentina/Mendoza', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Aruba', + 'America/Asuncion', + 'America/Atikokan', + 'America/Atka', + 'America/Bahia', + 'America/Bahia_Banderas', + 'America/Barbados', + 'America/Belem', + 'America/Belize', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Bogota', + 'America/Boise', + 'America/Buenos_Aires', + 'America/Cambridge_Bay', + 'America/Campo_Grande', + 'America/Cancun', + 'America/Caracas', + 'America/Catamarca', + 'America/Cayenne', + 'America/Cayman', + 'America/Chicago', + 'America/Chihuahua', + 'America/Ciudad_Juarez', + 'America/Coral_Harbour', + 'America/Cordoba', + 'America/Costa_Rica', + 'America/Creston', + 'America/Cuiaba', + 'America/Curacao', + 'America/Danmarkshavn', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Denver', + 'America/Detroit', + 'America/Dominica', + 'America/Edmonton', + 'America/Eirunepe', + 'America/El_Salvador', + 'America/Ensenada', + 'America/Fort_Nelson', + 'America/Fort_Wayne', + 'America/Fortaleza', + 'America/Glace_Bay', + 'America/Godthab', + 'America/Goose_Bay', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guatemala', + 'America/Guayaquil', + 'America/Guyana', + 'America/Halifax', + 'America/Havana', + 'America/Hermosillo', + 'America/Indiana/Indianapolis', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Indianapolis', + 'America/Inuvik', + 'America/Iqaluit', + 'America/Jamaica', + 'America/Jujuy', + 'America/Juneau', + 'America/Kentucky/Louisville', + 'America/Kentucky/Monticello', + 'America/Knox_IN', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lima', + 'America/Los_Angeles', + 'America/Louisville', + 'America/Lower_Princes', + 'America/Maceio', + 'America/Managua', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Matamoros', + 'America/Mazatlan', + 'America/Mendoza', + 'America/Menominee', + 'America/Merida', + 'America/Metlakatla', + 'America/Mexico_City', + 'America/Miquelon', + 'America/Moncton', + 'America/Monterrey', + 'America/Montevideo', + 'America/Montreal', + 'America/Montserrat', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Nome', + 'America/Noronha', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Nuuk', + 'America/Ojinaga', + 'America/Panama', + 'America/Pangnirtung', + 'America/Paramaribo', + 'America/Phoenix', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'America/Porto_Acre', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rainy_River', + 'America/Rankin_Inlet', + 'America/Recife', + 'America/Regina', + 'America/Resolute', + 'America/Rio_Branco', + 'America/Rosario', + 'America/Santa_Isabel', + 'America/Santarem', + 'America/Santiago', + 'America/Santo_Domingo', + 'America/Sao_Paulo', + 'America/Scoresbysund', + 'America/Shiprock', + 'America/Sitka', + 'America/St_Barthelemy', + 'America/St_Johns', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Swift_Current', + 'America/Tegucigalpa', + 'America/Thule', + 'America/Thunder_Bay', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + 'America/Virgin', + 'America/Whitehorse', + 'America/Winnipeg', + 'America/Yakutat', + 'America/Yellowknife', + 'Antarctica/Casey', + 'Antarctica/Davis', + 'Antarctica/DumontDUrville', + 'Antarctica/Macquarie', + 'Antarctica/Mawson', + 'Antarctica/McMurdo', + 'Antarctica/Palmer', + 'Antarctica/Rothera', + 'Antarctica/South_Pole', + 'Antarctica/Syowa', + 'Antarctica/Troll', + 'Antarctica/Vostok', + 'Arctic/Longyearbyen', + 'Asia/Aden', + 'Asia/Almaty', + 'Asia/Amman', + 'Asia/Anadyr', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Ashkhabad', + 'Asia/Atyrau', + 'Asia/Baghdad', + 'Asia/Bahrain', + 'Asia/Baku', + 'Asia/Bangkok', + 'Asia/Barnaul', + 'Asia/Beirut', + 'Asia/Bishkek', + 'Asia/Brunei', + 'Asia/Calcutta', + 'Asia/Chita', + 'Asia/Choibalsan', + 'Asia/Chongqing', + 'Asia/Chungking', + 'Asia/Colombo', + 'Asia/Dacca', + 'Asia/Damascus', + 'Asia/Dhaka', + 'Asia/Dili', + 'Asia/Dubai', + 'Asia/Dushanbe', + 'Asia/Famagusta', + 'Asia/Gaza', + 'Asia/Harbin', + 'Asia/Hebron', + 'Asia/Ho_Chi_Minh', + 'Asia/Hong_Kong', + 'Asia/Hovd', + 'Asia/Irkutsk', + 'Asia/Istanbul', + 'Asia/Jakarta', + 'Asia/Jayapura', + 'Asia/Jerusalem', + 'Asia/Kabul', + 'Asia/Kamchatka', + 'Asia/Karachi', + 'Asia/Kashgar', + 'Asia/Kathmandu', + 'Asia/Katmandu', + 'Asia/Khandyga', + 'Asia/Kolkata', + 'Asia/Krasnoyarsk', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Kuwait', + 'Asia/Macao', + 'Asia/Macau', + 'Asia/Magadan', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Muscat', + 'Asia/Nicosia', + 'Asia/Novokuznetsk', + 'Asia/Novosibirsk', + 'Asia/Omsk', + 'Asia/Oral', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Pyongyang', + 'Asia/Qatar', + 'Asia/Qostanay', + 'Asia/Qyzylorda', + 'Asia/Rangoon', + 'Asia/Riyadh', + 'Asia/Saigon', + 'Asia/Sakhalin', + 'Asia/Samarkand', + 'Asia/Seoul', + 'Asia/Shanghai', + 'Asia/Singapore', + 'Asia/Srednekolymsk', + 'Asia/Taipei', + 'Asia/Tashkent', + 'Asia/Tbilisi', + 'Asia/Tehran', + 'Asia/Tel_Aviv', + 'Asia/Thimbu', + 'Asia/Thimphu', + 'Asia/Tokyo', + 'Asia/Tomsk', + 'Asia/Ujung_Pandang', + 'Asia/Ulaanbaatar', + 'Asia/Ulan_Bator', + 'Asia/Urumqi', + 'Asia/Ust-Nera', + 'Asia/Vientiane', + 'Asia/Vladivostok', + 'Asia/Yakutsk', + 'Asia/Yangon', + 'Asia/Yekaterinburg', + 'Asia/Yerevan', + 'Atlantic/Azores', + 'Atlantic/Bermuda', + 'Atlantic/Canary', + 'Atlantic/Cape_Verde', + 'Atlantic/Faeroe', + 'Atlantic/Faroe', + 'Atlantic/Jan_Mayen', + 'Atlantic/Madeira', + 'Atlantic/Reykjavik', + 'Atlantic/South_Georgia', + 'Atlantic/St_Helena', + 'Atlantic/Stanley', + 'Australia/ACT', + 'Australia/Adelaide', + 'Australia/Brisbane', + 'Australia/Broken_Hill', + 'Australia/Canberra', + 'Australia/Currie', + 'Australia/Darwin', + 'Australia/Eucla', + 'Australia/Hobart', + 'Australia/LHI', + 'Australia/Lindeman', + 'Australia/Lord_Howe', + 'Australia/Melbourne', + 'Australia/NSW', + 'Australia/North', + 'Australia/Perth', + 'Australia/Queensland', + 'Australia/South', + 'Australia/Sydney', + 'Australia/Tasmania', + 'Australia/Victoria', + 'Australia/West', + 'Australia/Yancowinna', + 'Brazil/Acre', + 'Brazil/DeNoronha', + 'Brazil/East', + 'Brazil/West', + 'CET', + 'CST6CDT', + 'Canada/Atlantic', + 'Canada/Central', + 'Canada/Eastern', + 'Canada/Mountain', + 'Canada/Newfoundland', + 'Canada/Pacific', + 'Canada/Saskatchewan', + 'Canada/Yukon', + 'Chile/Continental', + 'Chile/EasterIsland', + 'Cuba', + 'EET', + 'EST', + 'EST5EDT', + 'Egypt', + 'Eire', + 'Etc/GMT', + 'Etc/GMT+0', + 'Etc/GMT+1', + 'Etc/GMT+10', + 'Etc/GMT+11', + 'Etc/GMT+12', + 'Etc/GMT+2', + 'Etc/GMT+3', + 'Etc/GMT+4', + 'Etc/GMT+5', + 'Etc/GMT+6', + 'Etc/GMT+7', + 'Etc/GMT+8', + 'Etc/GMT+9', + 'Etc/GMT-0', + 'Etc/GMT-1', + 'Etc/GMT-10', + 'Etc/GMT-11', + 'Etc/GMT-12', + 'Etc/GMT-13', + 'Etc/GMT-14', + 'Etc/GMT-2', + 'Etc/GMT-3', + 'Etc/GMT-4', + 'Etc/GMT-5', + 'Etc/GMT-6', + 'Etc/GMT-7', + 'Etc/GMT-8', + 'Etc/GMT-9', + 'Etc/GMT0', + 'Etc/Greenwich', + 'Etc/UCT', + 'Etc/UTC', + 'Etc/Universal', + 'Etc/Zulu', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Astrakhan', + 'Europe/Athens', + 'Europe/Belfast', + 'Europe/Belgrade', + 'Europe/Berlin', + 'Europe/Bratislava', + 'Europe/Brussels', + 'Europe/Bucharest', + 'Europe/Budapest', + 'Europe/Busingen', + 'Europe/Chisinau', + 'Europe/Copenhagen', + 'Europe/Dublin', + 'Europe/Gibraltar', + 'Europe/Guernsey', + 'Europe/Helsinki', + 'Europe/Isle_of_Man', + 'Europe/Istanbul', + 'Europe/Jersey', + 'Europe/Kaliningrad', + 'Europe/Kiev', + 'Europe/Kirov', + 'Europe/Kyiv', + 'Europe/Lisbon', + 'Europe/Ljubljana', + 'Europe/London', + 'Europe/Luxembourg', + 'Europe/Madrid', + 'Europe/Malta', + 'Europe/Mariehamn', + 'Europe/Minsk', + 'Europe/Monaco', + 'Europe/Moscow', + 'Europe/Nicosia', + 'Europe/Oslo', + 'Europe/Paris', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Riga', + 'Europe/Rome', + 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', + 'Europe/Saratov', + 'Europe/Simferopol', + 'Europe/Skopje', + 'Europe/Sofia', + 'Europe/Stockholm', + 'Europe/Tallinn', + 'Europe/Tirane', + 'Europe/Tiraspol', + 'Europe/Ulyanovsk', + 'Europe/Uzhgorod', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zaporozhye', + 'Europe/Zurich', + 'GB', + 'GB-Eire', + 'GMT', + 'GMT+0', + 'GMT-0', + 'GMT0', + 'Greenwich', + 'HST', + 'Hongkong', + 'Iceland', + 'Indian/Antananarivo', + 'Indian/Chagos', + 'Indian/Christmas', + 'Indian/Cocos', + 'Indian/Comoro', + 'Indian/Kerguelen', + 'Indian/Mahe', + 'Indian/Maldives', + 'Indian/Mauritius', + 'Indian/Mayotte', + 'Indian/Reunion', + 'Iran', + 'Israel', + 'Jamaica', + 'Japan', + 'Kwajalein', + 'Libya', + 'MET', + 'MST', + 'MST7MDT', + 'Mexico/BajaNorte', + 'Mexico/BajaSur', + 'Mexico/General', + 'NZ', + 'NZ-CHAT', + 'Navajo', + 'PRC', + 'PST8PDT', + 'Pacific/Apia', + 'Pacific/Auckland', + 'Pacific/Bougainville', + 'Pacific/Chatham', + 'Pacific/Chuuk', + 'Pacific/Easter', + 'Pacific/Efate', + 'Pacific/Enderbury', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + 'Pacific/Johnston', + 'Pacific/Kanton', + 'Pacific/Kiritimati', + 'Pacific/Kosrae', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Marquesas', + 'Pacific/Midway', + 'Pacific/Nauru', + 'Pacific/Niue', + 'Pacific/Norfolk', + 'Pacific/Noumea', + 'Pacific/Pago_Pago', + 'Pacific/Palau', + 'Pacific/Pitcairn', + 'Pacific/Pohnpei', + 'Pacific/Ponape', + 'Pacific/Port_Moresby', + 'Pacific/Rarotonga', + 'Pacific/Saipan', + 'Pacific/Samoa', + 'Pacific/Tahiti', + 'Pacific/Tarawa', + 'Pacific/Tongatapu', + 'Pacific/Truk', + 'Pacific/Wake', + 'Pacific/Wallis', + 'Pacific/Yap', + 'Poland', + 'Portugal', + 'ROC', + 'ROK', + 'Singapore', + 'Turkey', + 'UCT', + 'US/Alaska', + 'US/Aleutian', + 'US/Arizona', + 'US/Central', + 'US/East-Indiana', + 'US/Eastern', + 'US/Hawaii', + 'US/Indiana-Starke', + 'US/Michigan', + 'US/Mountain', + 'US/Pacific', + 'US/Samoa', + 'UTC', + 'Universal', + 'W-SU', + 'WET', + 'Zulu'] +all_timezones = LazyList( + tz for tz in _all_timezones_unchecked if resource_exists(tz)) + +all_timezones_set = LazySet(all_timezones) +common_timezones = \ +['Africa/Abidjan', + 'Africa/Accra', + 'Africa/Addis_Ababa', + 'Africa/Algiers', + 'Africa/Asmara', + 'Africa/Bamako', + 'Africa/Bangui', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Blantyre', + 'Africa/Brazzaville', + 'Africa/Bujumbura', + 'Africa/Cairo', + 'Africa/Casablanca', + 'Africa/Ceuta', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Douala', + 'Africa/El_Aaiun', + 'Africa/Freetown', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Kigali', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Lome', + 'Africa/Luanda', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Malabo', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Africa/Mogadishu', + 'Africa/Monrovia', + 'Africa/Nairobi', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Porto-Novo', + 'Africa/Sao_Tome', + 'Africa/Tripoli', + 'Africa/Tunis', + 'Africa/Windhoek', + 'America/Adak', + 'America/Anchorage', + 'America/Anguilla', + 'America/Antigua', + 'America/Araguaina', + 'America/Argentina/Buenos_Aires', + 'America/Argentina/Catamarca', + 'America/Argentina/Cordoba', + 'America/Argentina/Jujuy', + 'America/Argentina/La_Rioja', + 'America/Argentina/Mendoza', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Aruba', + 'America/Asuncion', + 'America/Atikokan', + 'America/Bahia', + 'America/Bahia_Banderas', + 'America/Barbados', + 'America/Belem', + 'America/Belize', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Bogota', + 'America/Boise', + 'America/Cambridge_Bay', + 'America/Campo_Grande', + 'America/Cancun', + 'America/Caracas', + 'America/Cayenne', + 'America/Cayman', + 'America/Chicago', + 'America/Chihuahua', + 'America/Ciudad_Juarez', + 'America/Costa_Rica', + 'America/Creston', + 'America/Cuiaba', + 'America/Curacao', + 'America/Danmarkshavn', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Denver', + 'America/Detroit', + 'America/Dominica', + 'America/Edmonton', + 'America/Eirunepe', + 'America/El_Salvador', + 'America/Fort_Nelson', + 'America/Fortaleza', + 'America/Glace_Bay', + 'America/Goose_Bay', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guatemala', + 'America/Guayaquil', + 'America/Guyana', + 'America/Halifax', + 'America/Havana', + 'America/Hermosillo', + 'America/Indiana/Indianapolis', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Inuvik', + 'America/Iqaluit', + 'America/Jamaica', + 'America/Juneau', + 'America/Kentucky/Louisville', + 'America/Kentucky/Monticello', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lima', + 'America/Los_Angeles', + 'America/Lower_Princes', + 'America/Maceio', + 'America/Managua', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Matamoros', + 'America/Mazatlan', + 'America/Menominee', + 'America/Merida', + 'America/Metlakatla', + 'America/Mexico_City', + 'America/Miquelon', + 'America/Moncton', + 'America/Monterrey', + 'America/Montevideo', + 'America/Montserrat', + 'America/Nassau', + 'America/New_York', + 'America/Nome', + 'America/Noronha', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Nuuk', + 'America/Ojinaga', + 'America/Panama', + 'America/Paramaribo', + 'America/Phoenix', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rankin_Inlet', + 'America/Recife', + 'America/Regina', + 'America/Resolute', + 'America/Rio_Branco', + 'America/Santarem', + 'America/Santiago', + 'America/Santo_Domingo', + 'America/Sao_Paulo', + 'America/Scoresbysund', + 'America/Sitka', + 'America/St_Barthelemy', + 'America/St_Johns', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Swift_Current', + 'America/Tegucigalpa', + 'America/Thule', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + 'America/Whitehorse', + 'America/Winnipeg', + 'America/Yakutat', + 'Antarctica/Casey', + 'Antarctica/Davis', + 'Antarctica/DumontDUrville', + 'Antarctica/Macquarie', + 'Antarctica/Mawson', + 'Antarctica/McMurdo', + 'Antarctica/Palmer', + 'Antarctica/Rothera', + 'Antarctica/Syowa', + 'Antarctica/Troll', + 'Antarctica/Vostok', + 'Arctic/Longyearbyen', + 'Asia/Aden', + 'Asia/Almaty', + 'Asia/Amman', + 'Asia/Anadyr', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Atyrau', + 'Asia/Baghdad', + 'Asia/Bahrain', + 'Asia/Baku', + 'Asia/Bangkok', + 'Asia/Barnaul', + 'Asia/Beirut', + 'Asia/Bishkek', + 'Asia/Brunei', + 'Asia/Chita', + 'Asia/Choibalsan', + 'Asia/Colombo', + 'Asia/Damascus', + 'Asia/Dhaka', + 'Asia/Dili', + 'Asia/Dubai', + 'Asia/Dushanbe', + 'Asia/Famagusta', + 'Asia/Gaza', + 'Asia/Hebron', + 'Asia/Ho_Chi_Minh', + 'Asia/Hong_Kong', + 'Asia/Hovd', + 'Asia/Irkutsk', + 'Asia/Jakarta', + 'Asia/Jayapura', + 'Asia/Jerusalem', + 'Asia/Kabul', + 'Asia/Kamchatka', + 'Asia/Karachi', + 'Asia/Kathmandu', + 'Asia/Khandyga', + 'Asia/Kolkata', + 'Asia/Krasnoyarsk', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Kuwait', + 'Asia/Macau', + 'Asia/Magadan', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Muscat', + 'Asia/Nicosia', + 'Asia/Novokuznetsk', + 'Asia/Novosibirsk', + 'Asia/Omsk', + 'Asia/Oral', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Pyongyang', + 'Asia/Qatar', + 'Asia/Qostanay', + 'Asia/Qyzylorda', + 'Asia/Riyadh', + 'Asia/Sakhalin', + 'Asia/Samarkand', + 'Asia/Seoul', + 'Asia/Shanghai', + 'Asia/Singapore', + 'Asia/Srednekolymsk', + 'Asia/Taipei', + 'Asia/Tashkent', + 'Asia/Tbilisi', + 'Asia/Tehran', + 'Asia/Thimphu', + 'Asia/Tokyo', + 'Asia/Tomsk', + 'Asia/Ulaanbaatar', + 'Asia/Urumqi', + 'Asia/Ust-Nera', + 'Asia/Vientiane', + 'Asia/Vladivostok', + 'Asia/Yakutsk', + 'Asia/Yangon', + 'Asia/Yekaterinburg', + 'Asia/Yerevan', + 'Atlantic/Azores', + 'Atlantic/Bermuda', + 'Atlantic/Canary', + 'Atlantic/Cape_Verde', + 'Atlantic/Faroe', + 'Atlantic/Madeira', + 'Atlantic/Reykjavik', + 'Atlantic/South_Georgia', + 'Atlantic/St_Helena', + 'Atlantic/Stanley', + 'Australia/Adelaide', + 'Australia/Brisbane', + 'Australia/Broken_Hill', + 'Australia/Darwin', + 'Australia/Eucla', + 'Australia/Hobart', + 'Australia/Lindeman', + 'Australia/Lord_Howe', + 'Australia/Melbourne', + 'Australia/Perth', + 'Australia/Sydney', + 'Canada/Atlantic', + 'Canada/Central', + 'Canada/Eastern', + 'Canada/Mountain', + 'Canada/Newfoundland', + 'Canada/Pacific', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Astrakhan', + 'Europe/Athens', + 'Europe/Belgrade', + 'Europe/Berlin', + 'Europe/Bratislava', + 'Europe/Brussels', + 'Europe/Bucharest', + 'Europe/Budapest', + 'Europe/Busingen', + 'Europe/Chisinau', + 'Europe/Copenhagen', + 'Europe/Dublin', + 'Europe/Gibraltar', + 'Europe/Guernsey', + 'Europe/Helsinki', + 'Europe/Isle_of_Man', + 'Europe/Istanbul', + 'Europe/Jersey', + 'Europe/Kaliningrad', + 'Europe/Kirov', + 'Europe/Kyiv', + 'Europe/Lisbon', + 'Europe/Ljubljana', + 'Europe/London', + 'Europe/Luxembourg', + 'Europe/Madrid', + 'Europe/Malta', + 'Europe/Mariehamn', + 'Europe/Minsk', + 'Europe/Monaco', + 'Europe/Moscow', + 'Europe/Oslo', + 'Europe/Paris', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Riga', + 'Europe/Rome', + 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', + 'Europe/Saratov', + 'Europe/Simferopol', + 'Europe/Skopje', + 'Europe/Sofia', + 'Europe/Stockholm', + 'Europe/Tallinn', + 'Europe/Tirane', + 'Europe/Ulyanovsk', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zurich', + 'GMT', + 'Indian/Antananarivo', + 'Indian/Chagos', + 'Indian/Christmas', + 'Indian/Cocos', + 'Indian/Comoro', + 'Indian/Kerguelen', + 'Indian/Mahe', + 'Indian/Maldives', + 'Indian/Mauritius', + 'Indian/Mayotte', + 'Indian/Reunion', + 'Pacific/Apia', + 'Pacific/Auckland', + 'Pacific/Bougainville', + 'Pacific/Chatham', + 'Pacific/Chuuk', + 'Pacific/Easter', + 'Pacific/Efate', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + 'Pacific/Kanton', + 'Pacific/Kiritimati', + 'Pacific/Kosrae', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Marquesas', + 'Pacific/Midway', + 'Pacific/Nauru', + 'Pacific/Niue', + 'Pacific/Norfolk', + 'Pacific/Noumea', + 'Pacific/Pago_Pago', + 'Pacific/Palau', + 'Pacific/Pitcairn', + 'Pacific/Pohnpei', + 'Pacific/Port_Moresby', + 'Pacific/Rarotonga', + 'Pacific/Saipan', + 'Pacific/Tahiti', + 'Pacific/Tarawa', + 'Pacific/Tongatapu', + 'Pacific/Wake', + 'Pacific/Wallis', + 'US/Alaska', + 'US/Arizona', + 'US/Central', + 'US/Eastern', + 'US/Hawaii', + 'US/Mountain', + 'US/Pacific', + 'UTC'] +common_timezones = LazyList( + tz for tz in common_timezones if tz in all_timezones) + +common_timezones_set = LazySet(common_timezones) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1549c683324ee5146099a783887e6ecb83c6b3e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0235fd5c4b046bbffc2da9555d8e4ba79d4892db Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/lazy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/lazy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f36a7caaa8766897cc806aedbb56f25cb9e4e2e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/lazy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/reference.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/reference.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a2ba08db15642d56667cdb0ffdaf34ce24f0e8f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/reference.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzfile.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzfile.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40bb47353cad85261efcc4a6fd27f988209fcc86 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzfile.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzinfo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzinfo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91aaa934c9c5f3077ae4f9f6e7da0c1ea5712bcf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/__pycache__/tzinfo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..4b20bde9ff9240ce8cc578e480f4d9aa8555bab4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/exceptions.py @@ -0,0 +1,59 @@ +''' +Custom exceptions raised by pytz. +''' + +__all__ = [ + 'UnknownTimeZoneError', 'InvalidTimeError', 'AmbiguousTimeError', + 'NonExistentTimeError', +] + + +class Error(Exception): + '''Base class for all exceptions raised by the pytz library''' + + +class UnknownTimeZoneError(KeyError, Error): + '''Exception raised when pytz is passed an unknown timezone. + + >>> isinstance(UnknownTimeZoneError(), LookupError) + True + + This class is actually a subclass of KeyError to provide backwards + compatibility with code relying on the undocumented behavior of earlier + pytz releases. + + >>> isinstance(UnknownTimeZoneError(), KeyError) + True + + And also a subclass of pytz.exceptions.Error, as are other pytz + exceptions. + + >>> isinstance(UnknownTimeZoneError(), Error) + True + + ''' + pass + + +class InvalidTimeError(Error): + '''Base class for invalid time exceptions.''' + + +class AmbiguousTimeError(InvalidTimeError): + '''Exception raised when attempting to create an ambiguous wallclock time. + + At the end of a DST transition period, a particular wallclock time will + occur twice (once before the clocks are set back, once after). Both + possibilities may be correct, unless further information is supplied. + + See DstTzInfo.normalize() for more info + ''' + + +class NonExistentTimeError(InvalidTimeError): + '''Exception raised when attempting to create a wallclock time that + cannot exist. + + At the start of a DST transition period, the wallclock time jumps forward. + The instants jumped over never occur. + ''' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/lazy.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/lazy.py new file mode 100644 index 0000000000000000000000000000000000000000..39344fc1f8c77d5ec43539d0c8e655f4b5d7d6f6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/lazy.py @@ -0,0 +1,172 @@ +from threading import RLock +try: + from collections.abc import Mapping as DictMixin +except ImportError: # Python < 3.3 + try: + from UserDict import DictMixin # Python 2 + except ImportError: # Python 3.0-3.3 + from collections import Mapping as DictMixin + + +# With lazy loading, we might end up with multiple threads triggering +# it at the same time. We need a lock. +_fill_lock = RLock() + + +class LazyDict(DictMixin): + """Dictionary populated on first use.""" + data = None + + def __getitem__(self, key): + if self.data is None: + _fill_lock.acquire() + try: + if self.data is None: + self._fill() + finally: + _fill_lock.release() + return self.data[key.upper()] + + def __contains__(self, key): + if self.data is None: + _fill_lock.acquire() + try: + if self.data is None: + self._fill() + finally: + _fill_lock.release() + return key in self.data + + def __iter__(self): + if self.data is None: + _fill_lock.acquire() + try: + if self.data is None: + self._fill() + finally: + _fill_lock.release() + return iter(self.data) + + def __len__(self): + if self.data is None: + _fill_lock.acquire() + try: + if self.data is None: + self._fill() + finally: + _fill_lock.release() + return len(self.data) + + def keys(self): + if self.data is None: + _fill_lock.acquire() + try: + if self.data is None: + self._fill() + finally: + _fill_lock.release() + return self.data.keys() + + +class LazyList(list): + """List populated on first use.""" + + _props = [ + '__str__', '__repr__', '__unicode__', + '__hash__', '__sizeof__', '__cmp__', + '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', + 'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove', + 'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__', + '__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__', + '__getitem__', '__setitem__', '__delitem__', '__iter__', + '__reversed__', '__getslice__', '__setslice__', '__delslice__'] + + def __new__(cls, fill_iter=None): + + if fill_iter is None: + return list() + + # We need a new class as we will be dynamically messing with its + # methods. + class LazyList(list): + pass + + fill_iter = [fill_iter] + + def lazy(name): + def _lazy(self, *args, **kw): + _fill_lock.acquire() + try: + if len(fill_iter) > 0: + list.extend(self, fill_iter.pop()) + for method_name in cls._props: + delattr(LazyList, method_name) + finally: + _fill_lock.release() + return getattr(list, name)(self, *args, **kw) + return _lazy + + for name in cls._props: + setattr(LazyList, name, lazy(name)) + + new_list = LazyList() + return new_list + +# Not all versions of Python declare the same magic methods. +# Filter out properties that don't exist in this version of Python +# from the list. +LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)] + + +class LazySet(set): + """Set populated on first use.""" + + _props = ( + '__str__', '__repr__', '__unicode__', + '__hash__', '__sizeof__', '__cmp__', + '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', + '__contains__', '__len__', '__nonzero__', + '__getitem__', '__setitem__', '__delitem__', '__iter__', + '__sub__', '__and__', '__xor__', '__or__', + '__rsub__', '__rand__', '__rxor__', '__ror__', + '__isub__', '__iand__', '__ixor__', '__ior__', + 'add', 'clear', 'copy', 'difference', 'difference_update', + 'discard', 'intersection', 'intersection_update', 'isdisjoint', + 'issubset', 'issuperset', 'pop', 'remove', + 'symmetric_difference', 'symmetric_difference_update', + 'union', 'update') + + def __new__(cls, fill_iter=None): + + if fill_iter is None: + return set() + + class LazySet(set): + pass + + fill_iter = [fill_iter] + + def lazy(name): + def _lazy(self, *args, **kw): + _fill_lock.acquire() + try: + if len(fill_iter) > 0: + for i in fill_iter.pop(): + set.add(self, i) + for method_name in cls._props: + delattr(LazySet, method_name) + finally: + _fill_lock.release() + return getattr(set, name)(self, *args, **kw) + return _lazy + + for name in cls._props: + setattr(LazySet, name, lazy(name)) + + new_set = LazySet() + return new_set + +# Not all versions of Python declare the same magic methods. +# Filter out properties that don't exist in this version of Python +# from the list. +LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/reference.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/reference.py new file mode 100644 index 0000000000000000000000000000000000000000..f765ca0af0b24e66dc3b7d51b9bf97e71b2b67aa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/reference.py @@ -0,0 +1,140 @@ +''' +Reference tzinfo implementations from the Python docs. +Used for testing against as they are only correct for the years +1987 to 2006. Do not use these for real code. +''' + +from datetime import tzinfo, timedelta, datetime +from pytz import HOUR, ZERO, UTC + +__all__ = [ + 'FixedOffset', + 'LocalTimezone', + 'USTimeZone', + 'Eastern', + 'Central', + 'Mountain', + 'Pacific', + 'UTC' +] + + +# A class building tzinfo objects for fixed-offset time zones. +# Note that FixedOffset(0, "UTC") is a different way to build a +# UTC tzinfo object. +class FixedOffset(tzinfo): + """Fixed offset in minutes east from UTC.""" + + def __init__(self, offset, name): + self.__offset = timedelta(minutes=offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return ZERO + + +import time as _time + +STDOFFSET = timedelta(seconds=-_time.timezone) +if _time.daylight: + DSTOFFSET = timedelta(seconds=-_time.altzone) +else: + DSTOFFSET = STDOFFSET + +DSTDIFF = DSTOFFSET - STDOFFSET + + +# A class capturing the platform's idea of local time. +class LocalTimezone(tzinfo): + + def utcoffset(self, dt): + if self._isdst(dt): + return DSTOFFSET + else: + return STDOFFSET + + def dst(self, dt): + if self._isdst(dt): + return DSTDIFF + else: + return ZERO + + def tzname(self, dt): + return _time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = _time.mktime(tt) + tt = _time.localtime(stamp) + return tt.tm_isdst > 0 + +Local = LocalTimezone() + + +def first_sunday_on_or_after(dt): + days_to_go = 6 - dt.weekday() + if days_to_go: + dt += timedelta(days_to_go) + return dt + + +# In the US, DST starts at 2am (standard time) on the first Sunday in April. +DSTSTART = datetime(1, 4, 1, 2) +# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. +# which is the first Sunday on or after Oct 25. +DSTEND = datetime(1, 10, 25, 1) + + +# A complete implementation of current DST rules for major US time zones. +class USTimeZone(tzinfo): + + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = timedelta(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname + + def __repr__(self): + return self.reprname + + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname + + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) + + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception may be sensible here, in one or both cases. + # It depends on how you want to treat them. The default + # fromutc() implementation (called by the default astimezone() + # implementation) passes a datetime with dt.tzinfo is self. + return ZERO + assert dt.tzinfo is self + + # Find first Sunday in April & the last in October. + start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) + end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) + + # Can't compare naive to aware objects, so strip the timezone from + # dt first. + if start <= dt.replace(tzinfo=None) < end: + return HOUR + else: + return ZERO + +Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") +Central = USTimeZone(-6, "Central", "CST", "CDT") +Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") +Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzfile.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzfile.py new file mode 100644 index 0000000000000000000000000000000000000000..99e74489b859e21fcaa68e93089035c3d81a73c8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzfile.py @@ -0,0 +1,133 @@ +''' +$Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $ +''' + +from datetime import datetime +from struct import unpack, calcsize + +from pytz.tzinfo import StaticTzInfo, DstTzInfo, memorized_ttinfo +from pytz.tzinfo import memorized_datetime, memorized_timedelta + + +def _byte_string(s): + """Cast a string or byte string to an ASCII byte string.""" + return s.encode('ASCII') + +_NULL = _byte_string('\0') + + +def _std_string(s): + """Cast a string or byte string to an ASCII string.""" + return str(s.decode('ASCII')) + + +def build_tzinfo(zone, fp): + head_fmt = '>4s c 15x 6l' + head_size = calcsize(head_fmt) + (magic, format, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt, + typecnt, charcnt) = unpack(head_fmt, fp.read(head_size)) + + # Make sure it is a tzfile(5) file + assert magic == _byte_string('TZif'), 'Got magic %s' % repr(magic) + + # Read out the transition times, localtime indices and ttinfo structures. + data_fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict( + timecnt=timecnt, ttinfo='lBB' * typecnt, charcnt=charcnt) + data_size = calcsize(data_fmt) + data = unpack(data_fmt, fp.read(data_size)) + + # make sure we unpacked the right number of values + assert len(data) == 2 * timecnt + 3 * typecnt + 1 + transitions = [memorized_datetime(trans) + for trans in data[:timecnt]] + lindexes = list(data[timecnt:2 * timecnt]) + ttinfo_raw = data[2 * timecnt:-1] + tznames_raw = data[-1] + del data + + # Process ttinfo into separate structs + ttinfo = [] + tznames = {} + i = 0 + while i < len(ttinfo_raw): + # have we looked up this timezone name yet? + tzname_offset = ttinfo_raw[i + 2] + if tzname_offset not in tznames: + nul = tznames_raw.find(_NULL, tzname_offset) + if nul < 0: + nul = len(tznames_raw) + tznames[tzname_offset] = _std_string( + tznames_raw[tzname_offset:nul]) + ttinfo.append((ttinfo_raw[i], + bool(ttinfo_raw[i + 1]), + tznames[tzname_offset])) + i += 3 + + # Now build the timezone object + if len(ttinfo) == 1 or len(transitions) == 0: + ttinfo[0][0], ttinfo[0][2] + cls = type(zone, (StaticTzInfo,), dict( + zone=zone, + _utcoffset=memorized_timedelta(ttinfo[0][0]), + _tzname=ttinfo[0][2])) + else: + # Early dates use the first standard time ttinfo + i = 0 + while ttinfo[i][1]: + i += 1 + if ttinfo[i] == ttinfo[lindexes[0]]: + transitions[0] = datetime.min + else: + transitions.insert(0, datetime.min) + lindexes.insert(0, i) + + # calculate transition info + transition_info = [] + for i in range(len(transitions)): + inf = ttinfo[lindexes[i]] + utcoffset = inf[0] + if not inf[1]: + dst = 0 + else: + for j in range(i - 1, -1, -1): + prev_inf = ttinfo[lindexes[j]] + if not prev_inf[1]: + break + dst = inf[0] - prev_inf[0] # dst offset + + # Bad dst? Look further. DST > 24 hours happens when + # a timzone has moved across the international dateline. + if dst <= 0 or dst > 3600 * 3: + for j in range(i + 1, len(transitions)): + stdinf = ttinfo[lindexes[j]] + if not stdinf[1]: + dst = inf[0] - stdinf[0] + if dst > 0: + break # Found a useful std time. + + tzname = inf[2] + + # Round utcoffset and dst to the nearest minute or the + # datetime library will complain. Conversions to these timezones + # might be up to plus or minus 30 seconds out, but it is + # the best we can do. + utcoffset = int((utcoffset + 30) // 60) * 60 + dst = int((dst + 30) // 60) * 60 + transition_info.append(memorized_ttinfo(utcoffset, dst, tzname)) + + cls = type(zone, (DstTzInfo,), dict( + zone=zone, + _utc_transition_times=transitions, + _transition_info=transition_info)) + + return cls() + +if __name__ == '__main__': + import os.path + from pprint import pprint + base = os.path.join(os.path.dirname(__file__), 'zoneinfo') + tz = build_tzinfo('Australia/Melbourne', + open(os.path.join(base, 'Australia', 'Melbourne'), 'rb')) + tz = build_tzinfo('US/Eastern', + open(os.path.join(base, 'US', 'Eastern'), 'rb')) + pprint(tz._utc_transition_times) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzinfo.py b/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzinfo.py new file mode 100644 index 0000000000000000000000000000000000000000..725978d53720202bf7b1a64f356f47c49d42fd92 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/tzinfo.py @@ -0,0 +1,577 @@ +'''Base classes and helpers for building zone specific tzinfo classes''' + +from datetime import datetime, timedelta, tzinfo +from bisect import bisect_right +try: + set +except NameError: + from sets import Set as set + +import pytz +from pytz.exceptions import AmbiguousTimeError, NonExistentTimeError + +__all__ = [] + +_timedelta_cache = {} + + +def memorized_timedelta(seconds): + '''Create only one instance of each distinct timedelta''' + try: + return _timedelta_cache[seconds] + except KeyError: + delta = timedelta(seconds=seconds) + _timedelta_cache[seconds] = delta + return delta + +_epoch = datetime.utcfromtimestamp(0) +_datetime_cache = {0: _epoch} + + +def memorized_datetime(seconds): + '''Create only one instance of each distinct datetime''' + try: + return _datetime_cache[seconds] + except KeyError: + # NB. We can't just do datetime.utcfromtimestamp(seconds) as this + # fails with negative values under Windows (Bug #90096) + dt = _epoch + timedelta(seconds=seconds) + _datetime_cache[seconds] = dt + return dt + +_ttinfo_cache = {} + + +def memorized_ttinfo(*args): + '''Create only one instance of each distinct tuple''' + try: + return _ttinfo_cache[args] + except KeyError: + ttinfo = ( + memorized_timedelta(args[0]), + memorized_timedelta(args[1]), + args[2] + ) + _ttinfo_cache[args] = ttinfo + return ttinfo + +_notime = memorized_timedelta(0) + + +def _to_seconds(td): + '''Convert a timedelta to seconds''' + return td.seconds + td.days * 24 * 60 * 60 + + +class BaseTzInfo(tzinfo): + # Overridden in subclass + _utcoffset = None + _tzname = None + zone = None + + def __str__(self): + return self.zone + + +class StaticTzInfo(BaseTzInfo): + '''A timezone that has a constant offset from UTC + + These timezones are rare, as most locations have changed their + offset at some point in their history + ''' + def fromutc(self, dt): + '''See datetime.tzinfo.fromutc''' + if dt.tzinfo is not None and dt.tzinfo is not self: + raise ValueError('fromutc: dt.tzinfo is not self') + return (dt + self._utcoffset).replace(tzinfo=self) + + def utcoffset(self, dt, is_dst=None): + '''See datetime.tzinfo.utcoffset + + is_dst is ignored for StaticTzInfo, and exists only to + retain compatibility with DstTzInfo. + ''' + return self._utcoffset + + def dst(self, dt, is_dst=None): + '''See datetime.tzinfo.dst + + is_dst is ignored for StaticTzInfo, and exists only to + retain compatibility with DstTzInfo. + ''' + return _notime + + def tzname(self, dt, is_dst=None): + '''See datetime.tzinfo.tzname + + is_dst is ignored for StaticTzInfo, and exists only to + retain compatibility with DstTzInfo. + ''' + return self._tzname + + def localize(self, dt, is_dst=False): + '''Convert naive time to local time''' + if dt.tzinfo is not None: + raise ValueError('Not naive datetime (tzinfo is already set)') + return dt.replace(tzinfo=self) + + def normalize(self, dt, is_dst=False): + '''Correct the timezone information on the given datetime. + + This is normally a no-op, as StaticTzInfo timezones never have + ambiguous cases to correct: + + >>> from pytz import timezone + >>> gmt = timezone('GMT') + >>> isinstance(gmt, StaticTzInfo) + True + >>> dt = datetime(2011, 5, 8, 1, 2, 3, tzinfo=gmt) + >>> gmt.normalize(dt) is dt + True + + The supported method of converting between timezones is to use + datetime.astimezone(). Currently normalize() also works: + + >>> la = timezone('America/Los_Angeles') + >>> dt = la.localize(datetime(2011, 5, 7, 1, 2, 3)) + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> gmt.normalize(dt).strftime(fmt) + '2011-05-07 08:02:03 GMT (+0000)' + ''' + if dt.tzinfo is self: + return dt + if dt.tzinfo is None: + raise ValueError('Naive time - no tzinfo set') + return dt.astimezone(self) + + def __repr__(self): + return '<StaticTzInfo %r>' % (self.zone,) + + def __reduce__(self): + # Special pickle to zone remains a singleton and to cope with + # database changes. + return pytz._p, (self.zone,) + + +class DstTzInfo(BaseTzInfo): + '''A timezone that has a variable offset from UTC + + The offset might change if daylight saving time comes into effect, + or at a point in history when the region decides to change their + timezone definition. + ''' + # Overridden in subclass + + # Sorted list of DST transition times, UTC + _utc_transition_times = None + + # [(utcoffset, dstoffset, tzname)] corresponding to + # _utc_transition_times entries + _transition_info = None + + zone = None + + # Set in __init__ + + _tzinfos = None + _dst = None # DST offset + + def __init__(self, _inf=None, _tzinfos=None): + if _inf: + self._tzinfos = _tzinfos + self._utcoffset, self._dst, self._tzname = _inf + else: + _tzinfos = {} + self._tzinfos = _tzinfos + self._utcoffset, self._dst, self._tzname = ( + self._transition_info[0]) + _tzinfos[self._transition_info[0]] = self + for inf in self._transition_info[1:]: + if inf not in _tzinfos: + _tzinfos[inf] = self.__class__(inf, _tzinfos) + + def fromutc(self, dt): + '''See datetime.tzinfo.fromutc''' + if (dt.tzinfo is not None and + getattr(dt.tzinfo, '_tzinfos', None) is not self._tzinfos): + raise ValueError('fromutc: dt.tzinfo is not self') + dt = dt.replace(tzinfo=None) + idx = max(0, bisect_right(self._utc_transition_times, dt) - 1) + inf = self._transition_info[idx] + return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf]) + + def normalize(self, dt): + '''Correct the timezone information on the given datetime + + If date arithmetic crosses DST boundaries, the tzinfo + is not magically adjusted. This method normalizes the + tzinfo to the correct one. + + To test, first we need to do some setup + + >>> from pytz import timezone + >>> utc = timezone('UTC') + >>> eastern = timezone('US/Eastern') + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + + We next create a datetime right on an end-of-DST transition point, + the instant when the wallclocks are wound back one hour. + + >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) + >>> loc_dt = utc_dt.astimezone(eastern) + >>> loc_dt.strftime(fmt) + '2002-10-27 01:00:00 EST (-0500)' + + Now, if we subtract a few minutes from it, note that the timezone + information has not changed. + + >>> before = loc_dt - timedelta(minutes=10) + >>> before.strftime(fmt) + '2002-10-27 00:50:00 EST (-0500)' + + But we can fix that by calling the normalize method + + >>> before = eastern.normalize(before) + >>> before.strftime(fmt) + '2002-10-27 01:50:00 EDT (-0400)' + + The supported method of converting between timezones is to use + datetime.astimezone(). Currently, normalize() also works: + + >>> th = timezone('Asia/Bangkok') + >>> am = timezone('Europe/Amsterdam') + >>> dt = th.localize(datetime(2011, 5, 7, 1, 2, 3)) + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> am.normalize(dt).strftime(fmt) + '2011-05-06 20:02:03 CEST (+0200)' + ''' + if dt.tzinfo is None: + raise ValueError('Naive time - no tzinfo set') + + # Convert dt in localtime to UTC + offset = dt.tzinfo._utcoffset + dt = dt.replace(tzinfo=None) + dt = dt - offset + # convert it back, and return it + return self.fromutc(dt) + + def localize(self, dt, is_dst=False): + '''Convert naive time to local time. + + This method should be used to construct localtimes, rather + than passing a tzinfo argument to a datetime constructor. + + is_dst is used to determine the correct timezone in the ambigous + period at the end of daylight saving time. + + >>> from pytz import timezone + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> amdam = timezone('Europe/Amsterdam') + >>> dt = datetime(2004, 10, 31, 2, 0, 0) + >>> loc_dt1 = amdam.localize(dt, is_dst=True) + >>> loc_dt2 = amdam.localize(dt, is_dst=False) + >>> loc_dt1.strftime(fmt) + '2004-10-31 02:00:00 CEST (+0200)' + >>> loc_dt2.strftime(fmt) + '2004-10-31 02:00:00 CET (+0100)' + >>> str(loc_dt2 - loc_dt1) + '1:00:00' + + Use is_dst=None to raise an AmbiguousTimeError for ambiguous + times at the end of daylight saving time + + >>> try: + ... loc_dt1 = amdam.localize(dt, is_dst=None) + ... except AmbiguousTimeError: + ... print('Ambiguous') + Ambiguous + + is_dst defaults to False + + >>> amdam.localize(dt) == amdam.localize(dt, False) + True + + is_dst is also used to determine the correct timezone in the + wallclock times jumped over at the start of daylight saving time. + + >>> pacific = timezone('US/Pacific') + >>> dt = datetime(2008, 3, 9, 2, 0, 0) + >>> ploc_dt1 = pacific.localize(dt, is_dst=True) + >>> ploc_dt2 = pacific.localize(dt, is_dst=False) + >>> ploc_dt1.strftime(fmt) + '2008-03-09 02:00:00 PDT (-0700)' + >>> ploc_dt2.strftime(fmt) + '2008-03-09 02:00:00 PST (-0800)' + >>> str(ploc_dt2 - ploc_dt1) + '1:00:00' + + Use is_dst=None to raise a NonExistentTimeError for these skipped + times. + + >>> try: + ... loc_dt1 = pacific.localize(dt, is_dst=None) + ... except NonExistentTimeError: + ... print('Non-existent') + Non-existent + ''' + if dt.tzinfo is not None: + raise ValueError('Not naive datetime (tzinfo is already set)') + + # Find the two best possibilities. + possible_loc_dt = set() + for delta in [timedelta(days=-1), timedelta(days=1)]: + loc_dt = dt + delta + idx = max(0, bisect_right( + self._utc_transition_times, loc_dt) - 1) + inf = self._transition_info[idx] + tzinfo = self._tzinfos[inf] + loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo)) + if loc_dt.replace(tzinfo=None) == dt: + possible_loc_dt.add(loc_dt) + + if len(possible_loc_dt) == 1: + return possible_loc_dt.pop() + + # If there are no possibly correct timezones, we are attempting + # to convert a time that never happened - the time period jumped + # during the start-of-DST transition period. + if len(possible_loc_dt) == 0: + # If we refuse to guess, raise an exception. + if is_dst is None: + raise NonExistentTimeError(dt) + + # If we are forcing the pre-DST side of the DST transition, we + # obtain the correct timezone by winding the clock forward a few + # hours. + elif is_dst: + return self.localize( + dt + timedelta(hours=6), is_dst=True) - timedelta(hours=6) + + # If we are forcing the post-DST side of the DST transition, we + # obtain the correct timezone by winding the clock back. + else: + return self.localize( + dt - timedelta(hours=6), + is_dst=False) + timedelta(hours=6) + + # If we get this far, we have multiple possible timezones - this + # is an ambiguous case occuring during the end-of-DST transition. + + # If told to be strict, raise an exception since we have an + # ambiguous case + if is_dst is None: + raise AmbiguousTimeError(dt) + + # Filter out the possiblilities that don't match the requested + # is_dst + filtered_possible_loc_dt = [ + p for p in possible_loc_dt if bool(p.tzinfo._dst) == is_dst + ] + + # Hopefully we only have one possibility left. Return it. + if len(filtered_possible_loc_dt) == 1: + return filtered_possible_loc_dt[0] + + if len(filtered_possible_loc_dt) == 0: + filtered_possible_loc_dt = list(possible_loc_dt) + + # If we get this far, we have in a wierd timezone transition + # where the clocks have been wound back but is_dst is the same + # in both (eg. Europe/Warsaw 1915 when they switched to CET). + # At this point, we just have to guess unless we allow more + # hints to be passed in (such as the UTC offset or abbreviation), + # but that is just getting silly. + # + # Choose the earliest (by UTC) applicable timezone if is_dst=True + # Choose the latest (by UTC) applicable timezone if is_dst=False + # i.e., behave like end-of-DST transition + dates = {} # utc -> local + for local_dt in filtered_possible_loc_dt: + utc_time = ( + local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset) + assert utc_time not in dates + dates[utc_time] = local_dt + return dates[[min, max][not is_dst](dates)] + + def utcoffset(self, dt, is_dst=None): + '''See datetime.tzinfo.utcoffset + + The is_dst parameter may be used to remove ambiguity during DST + transitions. + + >>> from pytz import timezone + >>> tz = timezone('America/St_Johns') + >>> ambiguous = datetime(2009, 10, 31, 23, 30) + + >>> str(tz.utcoffset(ambiguous, is_dst=False)) + '-1 day, 20:30:00' + + >>> str(tz.utcoffset(ambiguous, is_dst=True)) + '-1 day, 21:30:00' + + >>> try: + ... tz.utcoffset(ambiguous) + ... except AmbiguousTimeError: + ... print('Ambiguous') + Ambiguous + + ''' + if dt is None: + return None + elif dt.tzinfo is not self: + dt = self.localize(dt, is_dst) + return dt.tzinfo._utcoffset + else: + return self._utcoffset + + def dst(self, dt, is_dst=None): + '''See datetime.tzinfo.dst + + The is_dst parameter may be used to remove ambiguity during DST + transitions. + + >>> from pytz import timezone + >>> tz = timezone('America/St_Johns') + + >>> normal = datetime(2009, 9, 1) + + >>> str(tz.dst(normal)) + '1:00:00' + >>> str(tz.dst(normal, is_dst=False)) + '1:00:00' + >>> str(tz.dst(normal, is_dst=True)) + '1:00:00' + + >>> ambiguous = datetime(2009, 10, 31, 23, 30) + + >>> str(tz.dst(ambiguous, is_dst=False)) + '0:00:00' + >>> str(tz.dst(ambiguous, is_dst=True)) + '1:00:00' + >>> try: + ... tz.dst(ambiguous) + ... except AmbiguousTimeError: + ... print('Ambiguous') + Ambiguous + + ''' + if dt is None: + return None + elif dt.tzinfo is not self: + dt = self.localize(dt, is_dst) + return dt.tzinfo._dst + else: + return self._dst + + def tzname(self, dt, is_dst=None): + '''See datetime.tzinfo.tzname + + The is_dst parameter may be used to remove ambiguity during DST + transitions. + + >>> from pytz import timezone + >>> tz = timezone('America/St_Johns') + + >>> normal = datetime(2009, 9, 1) + + >>> tz.tzname(normal) + 'NDT' + >>> tz.tzname(normal, is_dst=False) + 'NDT' + >>> tz.tzname(normal, is_dst=True) + 'NDT' + + >>> ambiguous = datetime(2009, 10, 31, 23, 30) + + >>> tz.tzname(ambiguous, is_dst=False) + 'NST' + >>> tz.tzname(ambiguous, is_dst=True) + 'NDT' + >>> try: + ... tz.tzname(ambiguous) + ... except AmbiguousTimeError: + ... print('Ambiguous') + Ambiguous + ''' + if dt is None: + return self.zone + elif dt.tzinfo is not self: + dt = self.localize(dt, is_dst) + return dt.tzinfo._tzname + else: + return self._tzname + + def __repr__(self): + if self._dst: + dst = 'DST' + else: + dst = 'STD' + if self._utcoffset > _notime: + return '<DstTzInfo %r %s+%s %s>' % ( + self.zone, self._tzname, self._utcoffset, dst + ) + else: + return '<DstTzInfo %r %s%s %s>' % ( + self.zone, self._tzname, self._utcoffset, dst + ) + + def __reduce__(self): + # Special pickle to zone remains a singleton and to cope with + # database changes. + return pytz._p, ( + self.zone, + _to_seconds(self._utcoffset), + _to_seconds(self._dst), + self._tzname + ) + + +def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None): + """Factory function for unpickling pytz tzinfo instances. + + This is shared for both StaticTzInfo and DstTzInfo instances, because + database changes could cause a zones implementation to switch between + these two base classes and we can't break pickles on a pytz version + upgrade. + """ + # Raises a KeyError if zone no longer exists, which should never happen + # and would be a bug. + tz = pytz.timezone(zone) + + # A StaticTzInfo - just return it + if utcoffset is None: + return tz + + # This pickle was created from a DstTzInfo. We need to + # determine which of the list of tzinfo instances for this zone + # to use in order to restore the state of any datetime instances using + # it correctly. + utcoffset = memorized_timedelta(utcoffset) + dstoffset = memorized_timedelta(dstoffset) + try: + return tz._tzinfos[(utcoffset, dstoffset, tzname)] + except KeyError: + # The particular state requested in this timezone no longer exists. + # This indicates a corrupt pickle, or the timezone database has been + # corrected violently enough to make this particular + # (utcoffset,dstoffset) no longer exist in the zone, or the + # abbreviation has been changed. + pass + + # See if we can find an entry differing only by tzname. Abbreviations + # get changed from the initial guess by the database maintainers to + # match reality when this information is discovered. + for localized_tz in tz._tzinfos.values(): + if (localized_tz._utcoffset == utcoffset and + localized_tz._dst == dstoffset): + return localized_tz + + # This (utcoffset, dstoffset) information has been removed from the + # zone. Add it back. This might occur when the database maintainers have + # corrected incorrect information. datetime instances using this + # incorrect information will continue to do so, exactly as they were + # before being pickled. This is purely an overly paranoid safety net - I + # doubt this will ever been needed in real life. + inf = (utcoffset, dstoffset, tzname) + tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos) + return tz._tzinfos[inf] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Abidjan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Abidjan new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Abidjan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Accra b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Accra new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Accra differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Addis_Ababa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Addis_Ababa new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Addis_Ababa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Algiers b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Algiers new file mode 100644 index 0000000000000000000000000000000000000000..6cfd8a16e16ec08c7cd83e6c0e1f9e1bbc5dc18a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Algiers differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmara b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmara new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmara differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmera b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmera new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Asmera differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bamako b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bamako new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bamako differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bangui b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bangui new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bangui differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Banjul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Banjul new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Banjul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bissau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bissau new file mode 100644 index 0000000000000000000000000000000000000000..82ea5aaf0c6ae2b3ec582013b6d16e6d6f29eb0a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bissau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Blantyre b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Blantyre new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Blantyre differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Brazzaville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Brazzaville new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Brazzaville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bujumbura b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bujumbura new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Bujumbura differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Cairo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Cairo new file mode 100644 index 0000000000000000000000000000000000000000..dd538c65db6ed0a0e47feb7b6001640516958e19 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Cairo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Casablanca b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Casablanca new file mode 100644 index 0000000000000000000000000000000000000000..d39016b89d3c945030ce95f721ebb592c8105064 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Casablanca differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ceuta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ceuta new file mode 100644 index 0000000000000000000000000000000000000000..b41ec4f81ab104943e84105246f0e5d0157e6e2e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ceuta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Conakry b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Conakry new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Conakry differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dakar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dakar new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dakar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Djibouti b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Djibouti new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Djibouti differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Douala b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Douala new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Douala differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/El_Aaiun b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/El_Aaiun new file mode 100644 index 0000000000000000000000000000000000000000..066fbed008cf662455eeca2c012ab8cb5bf1731a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/El_Aaiun differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Freetown b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Freetown new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Freetown differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Gaborone b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Gaborone new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Gaborone differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Harare b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Harare new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Harare differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Johannesburg b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Johannesburg new file mode 100644 index 0000000000000000000000000000000000000000..b1c425daced454f53d7d18fea807bf8d081cf97e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Johannesburg differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Juba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Juba new file mode 100644 index 0000000000000000000000000000000000000000..06482943a45a58a02a43b9e2b6a3f215b21b045f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Juba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kampala b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kampala new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kampala differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Khartoum b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Khartoum new file mode 100644 index 0000000000000000000000000000000000000000..8ee8cb92e72d9c507ad0ee06dc6a38406ab06f34 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Khartoum differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kigali b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kigali new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kigali differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kinshasa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kinshasa new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Kinshasa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lagos b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lagos new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lagos differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Libreville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Libreville new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Libreville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lome b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lome new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lome differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Luanda b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Luanda new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Luanda differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lubumbashi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lubumbashi new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lubumbashi differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lusaka b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lusaka new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Lusaka differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Malabo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Malabo new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Malabo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maputo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maputo new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maputo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maseru b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maseru new file mode 100644 index 0000000000000000000000000000000000000000..b1c425daced454f53d7d18fea807bf8d081cf97e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Maseru differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mbabane b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mbabane new file mode 100644 index 0000000000000000000000000000000000000000..b1c425daced454f53d7d18fea807bf8d081cf97e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mbabane differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mogadishu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mogadishu new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Mogadishu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Monrovia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Monrovia new file mode 100644 index 0000000000000000000000000000000000000000..6d688502a1ca80f2e57a6de2790ac3193879d248 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Monrovia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nairobi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nairobi new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nairobi differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ndjamena b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ndjamena new file mode 100644 index 0000000000000000000000000000000000000000..a968845e29b8b2b47d4a73f74ae04ef681d7d485 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ndjamena differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Niamey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Niamey new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Niamey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nouakchott b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nouakchott new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Nouakchott differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ouagadougou b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ouagadougou new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Ouagadougou differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Porto-Novo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Porto-Novo new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Porto-Novo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Sao_Tome b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Sao_Tome new file mode 100644 index 0000000000000000000000000000000000000000..59f3759c409a1fb50e632ef5ef613d3fee7af7ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Sao_Tome differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Timbuktu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Timbuktu new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Timbuktu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tripoli b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tripoli new file mode 100644 index 0000000000000000000000000000000000000000..07b393bb7db14cef1e906ebe63cfbbe8cddc79d5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tripoli differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tunis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tunis new file mode 100644 index 0000000000000000000000000000000000000000..427fa563033fdd8533ae56337fa20befe9719b42 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Tunis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Windhoek b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Windhoek new file mode 100644 index 0000000000000000000000000000000000000000..abecd137b1fc3220637b22ffea0e7256a58e9377 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Africa/Windhoek differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Adak b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Adak new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Adak differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anchorage b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anchorage new file mode 100644 index 0000000000000000000000000000000000000000..9bbb2fd3b361ea8aa4c126d14df5fa370343a63f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anchorage differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anguilla b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anguilla new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Anguilla differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Antigua b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Antigua new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Antigua differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Araguaina b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Araguaina new file mode 100644 index 0000000000000000000000000000000000000000..919723dc2ca581b4f95154d4192d8f732cc55a45 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Araguaina differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires new file mode 100644 index 0000000000000000000000000000000000000000..cc82e69898f161842b5001f10a84d3ac127c5c6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Catamarca b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Catamarca new file mode 100644 index 0000000000000000000000000000000000000000..7268eb3738e5b3ba906f962533f48016cf3dcabc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Catamarca differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia new file mode 100644 index 0000000000000000000000000000000000000000..7268eb3738e5b3ba906f962533f48016cf3dcabc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Cordoba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Cordoba new file mode 100644 index 0000000000000000000000000000000000000000..2ad6ea5db204d599266412558f5a1fae076fc41a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Cordoba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Jujuy b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Jujuy new file mode 100644 index 0000000000000000000000000000000000000000..7ca0b46f680b80780981aab0699e64dd04070fe7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Jujuy differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja new file mode 100644 index 0000000000000000000000000000000000000000..a6a6694f3317a25e7bc4c66502e9f396fa106509 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Mendoza b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Mendoza new file mode 100644 index 0000000000000000000000000000000000000000..3232c80e2003489921578f7acbabc73fb9148205 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Mendoza differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos new file mode 100644 index 0000000000000000000000000000000000000000..8b1a2816ab136098d10a3d294993ea56b6c432dc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Salta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Salta new file mode 100644 index 0000000000000000000000000000000000000000..7072dec22958ad5ac74ba3457a178a4faadaf570 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Salta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Juan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Juan new file mode 100644 index 0000000000000000000000000000000000000000..f3e185c3ab516065c52557aaceaaeacae1f8b221 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Juan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Luis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Luis new file mode 100644 index 0000000000000000000000000000000000000000..2d1da3ae3d6f9c6f92a8ddf01c2ff51ae28e4de2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/San_Luis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Tucuman b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Tucuman new file mode 100644 index 0000000000000000000000000000000000000000..c6449f582a7804ecf66858a7fceda207c5d979be Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Tucuman differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia new file mode 100644 index 0000000000000000000000000000000000000000..e74ce049c793c96e855ebb15779887a48622bf26 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Aruba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Aruba new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Aruba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Asuncion b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Asuncion new file mode 100644 index 0000000000000000000000000000000000000000..891279d4db7f89ee8cf063b64b6e87a29ea86821 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Asuncion differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atikokan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atikokan new file mode 100644 index 0000000000000000000000000000000000000000..9964b9a33452f4b636f43703b7cdec4891cbda5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atikokan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atka b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atka new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Atka differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia new file mode 100644 index 0000000000000000000000000000000000000000..0b65e49fca21f1be92c3ab0dfa4cd05137f028b2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia_Banderas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia_Banderas new file mode 100644 index 0000000000000000000000000000000000000000..ae4a8a754617b8b918daffb6a45a067df2fd2fe6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bahia_Banderas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Barbados b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Barbados new file mode 100644 index 0000000000000000000000000000000000000000..00cd045ac86d6060e9e8b8dc0460caa49d2479b5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Barbados differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belem b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belem new file mode 100644 index 0000000000000000000000000000000000000000..0ae1202682c94ee52f74a795099f6a11d34e0d1e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belem differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belize b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belize new file mode 100644 index 0000000000000000000000000000000000000000..e6f5dfa6a8d82523e8cb12f17cf73560bc09a383 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Belize differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Blanc-Sablon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Blanc-Sablon new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Blanc-Sablon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boa_Vista b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boa_Vista new file mode 100644 index 0000000000000000000000000000000000000000..08d518b151425f85458727fbf69f6e601f12be86 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boa_Vista differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bogota b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bogota new file mode 100644 index 0000000000000000000000000000000000000000..331a1b7c4c3af257841900fe076e5393e15db100 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Bogota differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boise b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boise new file mode 100644 index 0000000000000000000000000000000000000000..aad1d991c49c2e0fa28be3da4de447af33c8df1c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Boise differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Buenos_Aires b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Buenos_Aires new file mode 100644 index 0000000000000000000000000000000000000000..cc82e69898f161842b5001f10a84d3ac127c5c6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Buenos_Aires differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cambridge_Bay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cambridge_Bay new file mode 100644 index 0000000000000000000000000000000000000000..7e58a203c6bdc9045092f879f8f58aa960084cad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cambridge_Bay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Campo_Grande b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Campo_Grande new file mode 100644 index 0000000000000000000000000000000000000000..53b3330fac2bd64c02d8dc171c722ec491bea41d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Campo_Grande differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cancun b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cancun new file mode 100644 index 0000000000000000000000000000000000000000..e7acbff18a2469c79f4ce77064adeb189d60bf10 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cancun differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Caracas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Caracas new file mode 100644 index 0000000000000000000000000000000000000000..3f3ebc9c410fe2a33ad26a5d02bb99b9503e1f72 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Caracas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Catamarca b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Catamarca new file mode 100644 index 0000000000000000000000000000000000000000..7268eb3738e5b3ba906f962533f48016cf3dcabc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Catamarca differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayenne b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayenne new file mode 100644 index 0000000000000000000000000000000000000000..e898594276143fa4cfd5d3815c4598b9e58dba07 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayenne differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayman b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayman new file mode 100644 index 0000000000000000000000000000000000000000..9964b9a33452f4b636f43703b7cdec4891cbda5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cayman differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chicago b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chicago new file mode 100644 index 0000000000000000000000000000000000000000..c6981a06b1d9c26f447518efe265a6454726eae7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chicago differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chihuahua b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chihuahua new file mode 100644 index 0000000000000000000000000000000000000000..e0910396704ffda1d7f39e70a369249aeb4b0353 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Chihuahua differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ciudad_Juarez b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ciudad_Juarez new file mode 100644 index 0000000000000000000000000000000000000000..eb1e53961c1ebe1e147dd42248753ad30817a349 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ciudad_Juarez differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Coral_Harbour b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Coral_Harbour new file mode 100644 index 0000000000000000000000000000000000000000..9964b9a33452f4b636f43703b7cdec4891cbda5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Coral_Harbour differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cordoba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cordoba new file mode 100644 index 0000000000000000000000000000000000000000..2ad6ea5db204d599266412558f5a1fae076fc41a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cordoba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Costa_Rica b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Costa_Rica new file mode 100644 index 0000000000000000000000000000000000000000..37cb85e4dbfb7ac9c01eecf584a1a721ed251e93 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Costa_Rica differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Creston b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Creston new file mode 100644 index 0000000000000000000000000000000000000000..ab37e845566aa95659b7b85be0051d0c67a7e53a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Creston differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cuiaba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cuiaba new file mode 100644 index 0000000000000000000000000000000000000000..26e97f6ebfc60c1517244840b77dbaedcbfabaaa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Cuiaba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Curacao b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Curacao new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Curacao differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Danmarkshavn b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Danmarkshavn new file mode 100644 index 0000000000000000000000000000000000000000..9549adcb657569ea304592a4070ceecb4550a4db Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Danmarkshavn differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson new file mode 100644 index 0000000000000000000000000000000000000000..343b63227d2185863cd720bf449de000bbc794d0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson_Creek b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson_Creek new file mode 100644 index 0000000000000000000000000000000000000000..db9e3396557652707c0c2232e119e13a2dd172fb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dawson_Creek differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Denver b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Denver new file mode 100644 index 0000000000000000000000000000000000000000..abb2b974a47eb3e5c8b4f5d4370baf4898b239ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Denver differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Detroit b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Detroit new file mode 100644 index 0000000000000000000000000000000000000000..e104faa46545ee873295cde34e1d46bccad8647c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Detroit differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dominica b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dominica new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Dominica differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Edmonton b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Edmonton new file mode 100644 index 0000000000000000000000000000000000000000..cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Edmonton differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Eirunepe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Eirunepe new file mode 100644 index 0000000000000000000000000000000000000000..d4c46e3091fe37b7db8d8b67d383302cd667987e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Eirunepe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/El_Salvador b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/El_Salvador new file mode 100644 index 0000000000000000000000000000000000000000..e2f22304aad56062cfb66d23f3a8c296689286ed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/El_Salvador differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ensenada b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ensenada new file mode 100644 index 0000000000000000000000000000000000000000..63dfdf48a68d02240737ecd6af081e02eb0b6317 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ensenada differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Nelson b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Nelson new file mode 100644 index 0000000000000000000000000000000000000000..5a0b7f1ca032be1adf8ba91f863e727c5ec6a026 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Nelson differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Wayne b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Wayne new file mode 100644 index 0000000000000000000000000000000000000000..a84b6e99671f7305d1c459956e16a4dd772fc60e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fort_Wayne differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fortaleza b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fortaleza new file mode 100644 index 0000000000000000000000000000000000000000..bee1a95152cbc37db7117d996d370ff9d3f11f79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Fortaleza differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Glace_Bay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Glace_Bay new file mode 100644 index 0000000000000000000000000000000000000000..48412a4cbf9241ea83887876b1b8b22c367ff4fd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Glace_Bay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Godthab b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Godthab new file mode 100644 index 0000000000000000000000000000000000000000..adb7934aadf5f45928ce67e82efa92ca92391703 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Godthab differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Goose_Bay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Goose_Bay new file mode 100644 index 0000000000000000000000000000000000000000..a3f299079aebb8524bf77e7f92e0a7e6d0a7b6fb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Goose_Bay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grand_Turk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grand_Turk new file mode 100644 index 0000000000000000000000000000000000000000..06da1a6d7a3eeec0e82f7c5815a8fed4252e16b2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grand_Turk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grenada b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grenada new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Grenada differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guadeloupe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guadeloupe new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guadeloupe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guatemala b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guatemala new file mode 100644 index 0000000000000000000000000000000000000000..407138caf94e467b52d925f96ad80b506e16d9ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guatemala differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guayaquil b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guayaquil new file mode 100644 index 0000000000000000000000000000000000000000..40831be11e0ab028ada80cecf5fdc0e2a233ee17 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guayaquil differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guyana b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guyana new file mode 100644 index 0000000000000000000000000000000000000000..9b7036723053b8e8e3888b0497528fe714b5b735 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Guyana differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Halifax b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Halifax new file mode 100644 index 0000000000000000000000000000000000000000..756099abe6cee44295a5566ad6cd0c352fb82e64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Halifax differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Havana b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Havana new file mode 100644 index 0000000000000000000000000000000000000000..b69ac4510784f23ee794cd6d11e62315a7318e5e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Havana differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Hermosillo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Hermosillo new file mode 100644 index 0000000000000000000000000000000000000000..86bd1a20a3fca3908723ffbe0201d3b162474066 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Hermosillo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis new file mode 100644 index 0000000000000000000000000000000000000000..a84b6e99671f7305d1c459956e16a4dd772fc60e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Knox b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Knox new file mode 100644 index 0000000000000000000000000000000000000000..025d132dd48ba978c6fedf86d70173127be49d49 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Knox differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Marengo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Marengo new file mode 100644 index 0000000000000000000000000000000000000000..677bbff6a9d89180cfd2dd3279a1c412610b6540 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Marengo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Petersburg b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Petersburg new file mode 100644 index 0000000000000000000000000000000000000000..3082de00c2e0bfe89d4ac5e093d9e5921aa63610 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Petersburg differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Tell_City b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Tell_City new file mode 100644 index 0000000000000000000000000000000000000000..103c5cb31795edc15d548ef4ca71f1e04e2996b5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Tell_City differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vevay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vevay new file mode 100644 index 0000000000000000000000000000000000000000..315b4c45aef1f241d025900544133c085fe4f69d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vevay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vincennes b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vincennes new file mode 100644 index 0000000000000000000000000000000000000000..35a24133446b9ee1e8f8a7931519d93517130315 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Vincennes differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Winamac b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Winamac new file mode 100644 index 0000000000000000000000000000000000000000..6d4e19377e9f70c3782daa223753c640c60ab1eb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indiana/Winamac differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indianapolis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indianapolis new file mode 100644 index 0000000000000000000000000000000000000000..a84b6e99671f7305d1c459956e16a4dd772fc60e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Indianapolis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Inuvik b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Inuvik new file mode 100644 index 0000000000000000000000000000000000000000..04c2df456ff0f879a419331dc3e9f4d4f68f0ecd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Inuvik differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Iqaluit b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Iqaluit new file mode 100644 index 0000000000000000000000000000000000000000..0b47b9032f11d4ea7dd6ac51aa329f7a98253638 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Iqaluit differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jamaica b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jamaica new file mode 100644 index 0000000000000000000000000000000000000000..2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jamaica differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jujuy b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jujuy new file mode 100644 index 0000000000000000000000000000000000000000..7ca0b46f680b80780981aab0699e64dd04070fe7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Jujuy differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Juneau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Juneau new file mode 100644 index 0000000000000000000000000000000000000000..451f3490096338f40e601628ac70f04112ace51d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Juneau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Louisville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Louisville new file mode 100644 index 0000000000000000000000000000000000000000..3a335b37165d2b3d6a09a1716cb158e272087c9f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Louisville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Monticello b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Monticello new file mode 100644 index 0000000000000000000000000000000000000000..576f16bb2b21a7e0871a7222241ad65e533bb93a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kentucky/Monticello differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Knox_IN b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Knox_IN new file mode 100644 index 0000000000000000000000000000000000000000..025d132dd48ba978c6fedf86d70173127be49d49 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Knox_IN differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kralendijk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kralendijk new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Kralendijk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/La_Paz b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/La_Paz new file mode 100644 index 0000000000000000000000000000000000000000..374586ea67601c4512b52859ff4e73bb30dbecc0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/La_Paz differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lima b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lima new file mode 100644 index 0000000000000000000000000000000000000000..c13bb6be45a3be6cc747d056c571623528dc1e34 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lima differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Los_Angeles b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Los_Angeles new file mode 100644 index 0000000000000000000000000000000000000000..610e7af5fc13d9784de30d272c7c39d7938873a0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Los_Angeles differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Louisville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Louisville new file mode 100644 index 0000000000000000000000000000000000000000..3a335b37165d2b3d6a09a1716cb158e272087c9f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Louisville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lower_Princes b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lower_Princes new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Lower_Princes differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Maceio b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Maceio new file mode 100644 index 0000000000000000000000000000000000000000..437a47310ec174736b0efbbe9e7e9a8cc26c150c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Maceio differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Managua b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Managua new file mode 100644 index 0000000000000000000000000000000000000000..e0242bff6e5df45de8b235abb4a8405fbb8ba6a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Managua differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Manaus b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Manaus new file mode 100644 index 0000000000000000000000000000000000000000..2708baea5af1d5169a1cebd00c4762d6bb937fda Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Manaus differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Marigot b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Marigot new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Marigot differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Martinique b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Martinique new file mode 100644 index 0000000000000000000000000000000000000000..8df43dcf1c9f63d3ea9f056f062ea97e5c7c0b57 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Martinique differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Matamoros b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Matamoros new file mode 100644 index 0000000000000000000000000000000000000000..bbe04e86610a302d0a4deb36dd56f17673f2d3dc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Matamoros differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mazatlan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mazatlan new file mode 100644 index 0000000000000000000000000000000000000000..06fa22749d0a3157b5a693f0797086f78e1201c5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mazatlan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mendoza b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mendoza new file mode 100644 index 0000000000000000000000000000000000000000..3232c80e2003489921578f7acbabc73fb9148205 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mendoza differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Menominee b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Menominee new file mode 100644 index 0000000000000000000000000000000000000000..314613866de53e1457f6cbf2fb617be7e4955edf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Menominee differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Merida b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Merida new file mode 100644 index 0000000000000000000000000000000000000000..17654cb59991e52537f87d9d9a2b56396f9c5c7e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Merida differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Metlakatla b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Metlakatla new file mode 100644 index 0000000000000000000000000000000000000000..1e94be3d552ea0d6e29824469866c2a51a187be9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Metlakatla differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mexico_City b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mexico_City new file mode 100644 index 0000000000000000000000000000000000000000..68176daa4976b015fb79026f3053e74e4a7457ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Mexico_City differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Miquelon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Miquelon new file mode 100644 index 0000000000000000000000000000000000000000..5eccd861071d4eccb76fe0d8f5195bd1a7f646b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Miquelon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Moncton b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Moncton new file mode 100644 index 0000000000000000000000000000000000000000..9df8d0f2ec9fc8f1974d83cdd8155c79340007ed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Moncton differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Monterrey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Monterrey new file mode 100644 index 0000000000000000000000000000000000000000..5eb723c80949d0cf2a99603ea6aba4688ade6b21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Monterrey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montevideo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montevideo new file mode 100644 index 0000000000000000000000000000000000000000..e7bbfbb8c332fee14ae1b4aa07cc4d128e6a3ca7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montevideo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montreal b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montreal new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montreal differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montserrat b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montserrat new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Montserrat differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nassau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nassau new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nassau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/New_York b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/New_York new file mode 100644 index 0000000000000000000000000000000000000000..a8b9ab1992257d721ad627b14f535c3d4b020888 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/New_York differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nipigon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nipigon new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nipigon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nome b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nome new file mode 100644 index 0000000000000000000000000000000000000000..10998df3bbe67aa8a02602301d10ec2b2c33006b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nome differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Noronha b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Noronha new file mode 100644 index 0000000000000000000000000000000000000000..73b4b336ab55544e6061409261c16cacc39aff61 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Noronha differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah new file mode 100644 index 0000000000000000000000000000000000000000..33e317e25b127335de68052f57d33ceed620524e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Center b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Center new file mode 100644 index 0000000000000000000000000000000000000000..17fe13bcc1c73ecbc6738499667816f54c164e39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/Center differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem new file mode 100644 index 0000000000000000000000000000000000000000..12dbe801aeb06823483525727f6f6695dec1bc24 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nuuk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nuuk new file mode 100644 index 0000000000000000000000000000000000000000..adb7934aadf5f45928ce67e82efa92ca92391703 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Nuuk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ojinaga b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ojinaga new file mode 100644 index 0000000000000000000000000000000000000000..f97946d1e269bf9c83fd4a02591b7ef04e8eb6a8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Ojinaga differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Panama b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Panama new file mode 100644 index 0000000000000000000000000000000000000000..9964b9a33452f4b636f43703b7cdec4891cbda5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Panama differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Pangnirtung b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Pangnirtung new file mode 100644 index 0000000000000000000000000000000000000000..0b47b9032f11d4ea7dd6ac51aa329f7a98253638 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Pangnirtung differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Paramaribo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Paramaribo new file mode 100644 index 0000000000000000000000000000000000000000..f1b82b4f9a546fd067cf043ba5d35da6fbe41fbe Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Paramaribo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Phoenix b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Phoenix new file mode 100644 index 0000000000000000000000000000000000000000..ab37e845566aa95659b7b85be0051d0c67a7e53a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Phoenix differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port-au-Prince b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port-au-Prince new file mode 100644 index 0000000000000000000000000000000000000000..287f1439266639f9564149d6e162feaba3fbed86 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port-au-Prince differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port_of_Spain b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port_of_Spain new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Port_of_Spain differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Acre b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Acre new file mode 100644 index 0000000000000000000000000000000000000000..cdda168cb97b1d45a4f1b7791a74523b74c88e6d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Acre differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Velho b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Velho new file mode 100644 index 0000000000000000000000000000000000000000..e00398602c634e6f1e9c0bc0e12b064f343ffe0c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Porto_Velho differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Puerto_Rico b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Puerto_Rico new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Puerto_Rico differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Punta_Arenas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Punta_Arenas new file mode 100644 index 0000000000000000000000000000000000000000..411a839b84d3c629bf7eb623024077efe614ed07 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Punta_Arenas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rainy_River b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rainy_River new file mode 100644 index 0000000000000000000000000000000000000000..ac40299f6b27043e8f2454ac594b0ec184c1a237 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rainy_River differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rankin_Inlet b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rankin_Inlet new file mode 100644 index 0000000000000000000000000000000000000000..e2714921a8f3c05189d20a9151931fb6eadf493b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rankin_Inlet differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Recife b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Recife new file mode 100644 index 0000000000000000000000000000000000000000..5bf6c211c19b7cd37107a2e3b317c2a7195c2947 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Recife differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Regina b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Regina new file mode 100644 index 0000000000000000000000000000000000000000..20c9c84df491e4072ec4c5d2c931a7433d9fd394 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Regina differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Resolute b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Resolute new file mode 100644 index 0000000000000000000000000000000000000000..19668900dea9249c1714b8838e44ac2070069138 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Resolute differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rio_Branco b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rio_Branco new file mode 100644 index 0000000000000000000000000000000000000000..cdda168cb97b1d45a4f1b7791a74523b74c88e6d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rio_Branco differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rosario b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rosario new file mode 100644 index 0000000000000000000000000000000000000000..2ad6ea5db204d599266412558f5a1fae076fc41a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Rosario differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santa_Isabel b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santa_Isabel new file mode 100644 index 0000000000000000000000000000000000000000..63dfdf48a68d02240737ecd6af081e02eb0b6317 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santa_Isabel differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santarem b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santarem new file mode 100644 index 0000000000000000000000000000000000000000..001638c2f2a964eb2cc75660f66a1bcc447d7a57 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santarem differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santiago b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santiago new file mode 100644 index 0000000000000000000000000000000000000000..010c6bd04cae79078540da560ce38400bfe0ade6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santiago differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santo_Domingo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santo_Domingo new file mode 100644 index 0000000000000000000000000000000000000000..4fe36fd4c11f998ba3f626c5e23d97bd82d12791 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Santo_Domingo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sao_Paulo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sao_Paulo new file mode 100644 index 0000000000000000000000000000000000000000..67935ff4da8f527e03cd05ed2aa20e601e10f921 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sao_Paulo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Scoresbysund b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Scoresbysund new file mode 100644 index 0000000000000000000000000000000000000000..286d13216eb3b14bf9fec1fceebf2fe731472d39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Scoresbysund differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Shiprock b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Shiprock new file mode 100644 index 0000000000000000000000000000000000000000..abb2b974a47eb3e5c8b4f5d4370baf4898b239ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Shiprock differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sitka b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sitka new file mode 100644 index 0000000000000000000000000000000000000000..31f7061371910ad42e4310b7a646ba1a98b6cba4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Sitka differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Barthelemy b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Barthelemy new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Barthelemy differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Johns b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Johns new file mode 100644 index 0000000000000000000000000000000000000000..65a5b0c720dad151ffdcba3dbe91c8bd638845c6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Johns differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Kitts b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Kitts new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Kitts differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Lucia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Lucia new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Lucia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Thomas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Thomas new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Thomas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Vincent b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Vincent new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/St_Vincent differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Swift_Current b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Swift_Current new file mode 100644 index 0000000000000000000000000000000000000000..8e9ef255eeb11515b84126d9ee5c0c6b3c72f2a0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Swift_Current differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tegucigalpa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tegucigalpa new file mode 100644 index 0000000000000000000000000000000000000000..2adacb2e500e2f9621b2debc1756d308747b67f6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tegucigalpa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thule b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thule new file mode 100644 index 0000000000000000000000000000000000000000..6f802f1c2acf9cc73481ae86c9e099fcfc28cf25 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thule differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thunder_Bay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thunder_Bay new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Thunder_Bay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tijuana b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tijuana new file mode 100644 index 0000000000000000000000000000000000000000..63dfdf48a68d02240737ecd6af081e02eb0b6317 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tijuana differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Toronto b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Toronto new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Toronto differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tortola b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tortola new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Tortola differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Vancouver b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Vancouver new file mode 100644 index 0000000000000000000000000000000000000000..bb60cbced30763c08b6cf73554c8d6651ff387d0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Vancouver differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Virgin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Virgin new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Virgin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Whitehorse b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Whitehorse new file mode 100644 index 0000000000000000000000000000000000000000..318c4a8e4003bcff00f9a21e294e7815f170235b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Whitehorse differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Winnipeg b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Winnipeg new file mode 100644 index 0000000000000000000000000000000000000000..ac40299f6b27043e8f2454ac594b0ec184c1a237 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Winnipeg differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yakutat b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yakutat new file mode 100644 index 0000000000000000000000000000000000000000..da209f9f0a07625ec83d4ec84917216347f5687f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yakutat differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yellowknife b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yellowknife new file mode 100644 index 0000000000000000000000000000000000000000..cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/America/Yellowknife differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Casey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Casey new file mode 100644 index 0000000000000000000000000000000000000000..4b98133d7af497a840e2630bc72a02439c4d774f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Casey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Davis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Davis new file mode 100644 index 0000000000000000000000000000000000000000..d4d47b24647bcabc981440f0859e94228428798d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Davis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville new file mode 100644 index 0000000000000000000000000000000000000000..7be2474dd91c8a7da181fcda09d838254b890d75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Macquarie b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Macquarie new file mode 100644 index 0000000000000000000000000000000000000000..9e7cc687d76b00d8f112245d5c5d2f20a2a61814 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Macquarie differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Mawson b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Mawson new file mode 100644 index 0000000000000000000000000000000000000000..6d93f6e1d3f76bcb6325f503958d19798b098fa0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Mawson differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/McMurdo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/McMurdo new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/McMurdo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Palmer b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Palmer new file mode 100644 index 0000000000000000000000000000000000000000..9c8fd317e0537afd4066001f6700cd6490fbe5a8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Palmer differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Rothera b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Rothera new file mode 100644 index 0000000000000000000000000000000000000000..241cc44d507c50777f7225df197765e522f22313 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Rothera differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/South_Pole b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/South_Pole new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/South_Pole differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Syowa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Syowa new file mode 100644 index 0000000000000000000000000000000000000000..8c8062471dce91a5be827d6908795ee7391a4afc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Syowa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Troll b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Troll new file mode 100644 index 0000000000000000000000000000000000000000..a1dcea14de9cfb95311ebe94e8a1096c27800941 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Troll differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Vostok b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Vostok new file mode 100644 index 0000000000000000000000000000000000000000..62bdcac14db3f464ff561e32db2c6b55c0cb1866 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Antarctica/Vostok differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Arctic/Longyearbyen b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Arctic/Longyearbyen new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Arctic/Longyearbyen differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aden b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aden new file mode 100644 index 0000000000000000000000000000000000000000..8c8062471dce91a5be827d6908795ee7391a4afc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aden differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Almaty b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Almaty new file mode 100644 index 0000000000000000000000000000000000000000..91c916a3a5d7949cc304532fe3fb2eac117ab2ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Almaty differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Amman b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Amman new file mode 100644 index 0000000000000000000000000000000000000000..0a8e350a334bbee29b155fb9944c6831460d973e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Amman differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Anadyr b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Anadyr new file mode 100644 index 0000000000000000000000000000000000000000..35c531c0709fabace97e52cacef74b4cfbbcd820 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Anadyr differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtau new file mode 100644 index 0000000000000000000000000000000000000000..0e1c16d32eca7652aa7e1392e606cf5b54e26bc5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtobe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtobe new file mode 100644 index 0000000000000000000000000000000000000000..3b5d6eb41883a7b32819f387b4c03c93e9d489cf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Aqtobe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashgabat b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashgabat new file mode 100644 index 0000000000000000000000000000000000000000..2bd1cb3da0f5a11024f1609b09ae68645e6ae75c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashgabat differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashkhabad b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashkhabad new file mode 100644 index 0000000000000000000000000000000000000000..2bd1cb3da0f5a11024f1609b09ae68645e6ae75c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ashkhabad differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Atyrau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Atyrau new file mode 100644 index 0000000000000000000000000000000000000000..e7ea9c545a56ae0b0fabd02e47748004a6d87c3b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Atyrau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baghdad b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baghdad new file mode 100644 index 0000000000000000000000000000000000000000..c0e607234a07cd2650aabc1fd022bd5d4f99b175 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baghdad differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bahrain b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bahrain new file mode 100644 index 0000000000000000000000000000000000000000..098997e7dd972ca4acedc535c4a645ee966baa33 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bahrain differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baku b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baku new file mode 100644 index 0000000000000000000000000000000000000000..ae0ce4e7c3d273b537fa3653784e73be68ebb441 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Baku differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bangkok b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bangkok new file mode 100644 index 0000000000000000000000000000000000000000..fa799db39e7625dd74bd9caa5c29b4819a7cbd3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bangkok differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Barnaul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Barnaul new file mode 100644 index 0000000000000000000000000000000000000000..2f6b8101d474642410af84260fb2b88c493945b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Barnaul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Beirut b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Beirut new file mode 100644 index 0000000000000000000000000000000000000000..23dbffba0109d6eab03c8cbdbc8f0ba196d3c572 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Beirut differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bishkek b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bishkek new file mode 100644 index 0000000000000000000000000000000000000000..547fd5e1bd16152073f7237ad265b5c643e7cbfe Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Bishkek differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Brunei b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Brunei new file mode 100644 index 0000000000000000000000000000000000000000..098c6a0b0afc2c3ef3a6937104d270074ff2a9b6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Brunei differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Calcutta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Calcutta new file mode 100644 index 0000000000000000000000000000000000000000..0014046d29a38e9b8006f746fea794d7f71eb479 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Calcutta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chita b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chita new file mode 100644 index 0000000000000000000000000000000000000000..75b3d7b3a6b3bf2b7459532fce1142912b897efd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chita differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Choibalsan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Choibalsan new file mode 100644 index 0000000000000000000000000000000000000000..c5f4bb0b3858f7078b35cb7a63021d7dc0262605 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Choibalsan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chongqing b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chongqing new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chongqing differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chungking b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chungking new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Chungking differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Colombo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Colombo new file mode 100644 index 0000000000000000000000000000000000000000..353fe2aa3564c79809e05e12711f90669e5e2388 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Colombo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dacca b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dacca new file mode 100644 index 0000000000000000000000000000000000000000..3cf597d83f90403132573d78247e6d02e66d0583 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dacca differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Damascus b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Damascus new file mode 100644 index 0000000000000000000000000000000000000000..afd956c878856e0e239887963b32ddb8327ccf38 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Damascus differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dhaka b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dhaka new file mode 100644 index 0000000000000000000000000000000000000000..3cf597d83f90403132573d78247e6d02e66d0583 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dhaka differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dili b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dili new file mode 100644 index 0000000000000000000000000000000000000000..c1af113af0a87e5c96033c83f199161062073bf0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dili differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dubai b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dubai new file mode 100644 index 0000000000000000000000000000000000000000..b3ac791aef4e73d6d644c40c614f37f15d462cdd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dubai differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dushanbe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dushanbe new file mode 100644 index 0000000000000000000000000000000000000000..89e875beaef780b2ceae08ee4703cd813f33d6a4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Dushanbe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Famagusta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Famagusta new file mode 100644 index 0000000000000000000000000000000000000000..653b146a60e5e5641a07bfc82f9590dad1ed69f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Famagusta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Gaza b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Gaza new file mode 100644 index 0000000000000000000000000000000000000000..c9b2ff90823a5809d877fb68c10494a38ab183b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Gaza differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Harbin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Harbin new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Harbin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hebron b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hebron new file mode 100644 index 0000000000000000000000000000000000000000..64194fd85c676a5407878a197f6f9a011f2ff067 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hebron differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh new file mode 100644 index 0000000000000000000000000000000000000000..a213d290e1a920271e924506a57191f1f4bfc4c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hong_Kong b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hong_Kong new file mode 100644 index 0000000000000000000000000000000000000000..f9f7b134dd5c35e4718c6fa3697024cb95442c53 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hong_Kong differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hovd b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hovd new file mode 100644 index 0000000000000000000000000000000000000000..8b9abca344daf199b554888fc4fff562a7a18e4a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Hovd differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Irkutsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Irkutsk new file mode 100644 index 0000000000000000000000000000000000000000..e74a4d3f6b3a799b0fd12272c3aae0f084fb2783 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Irkutsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Istanbul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Istanbul new file mode 100644 index 0000000000000000000000000000000000000000..7c2336dd80c3c9cbf71cb53d2b2c1f89a65a8ba5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Istanbul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jakarta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jakarta new file mode 100644 index 0000000000000000000000000000000000000000..ec4bd5747a8c9c528dfd22c8e3171851784ade59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jakarta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jayapura b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jayapura new file mode 100644 index 0000000000000000000000000000000000000000..3002c82022f7e9a4ff1ad545ea617106a13b24e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jayapura differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jerusalem b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jerusalem new file mode 100644 index 0000000000000000000000000000000000000000..1ebd0664aa29c0abd722661f761031ec0304631c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Jerusalem differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kabul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kabul new file mode 100644 index 0000000000000000000000000000000000000000..661efc83294edbe5f615daa87a1f4a5590aae167 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kabul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kamchatka b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kamchatka new file mode 100644 index 0000000000000000000000000000000000000000..99776f515fd53a86a6886311d91ff33b401396c3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kamchatka differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Karachi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Karachi new file mode 100644 index 0000000000000000000000000000000000000000..ba65c0e8d31cb1d59935878af29baac722f45936 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Karachi differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kashgar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kashgar new file mode 100644 index 0000000000000000000000000000000000000000..62bdcac14db3f464ff561e32db2c6b55c0cb1866 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kashgar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kathmandu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kathmandu new file mode 100644 index 0000000000000000000000000000000000000000..751cf4a8939e898f8abe4358a98b2a5f59f65e21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kathmandu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Katmandu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Katmandu new file mode 100644 index 0000000000000000000000000000000000000000..751cf4a8939e898f8abe4358a98b2a5f59f65e21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Katmandu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Khandyga b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Khandyga new file mode 100644 index 0000000000000000000000000000000000000000..7cdc99a9803f4e1ce3c5f7f9e6cd761f178536ae Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Khandyga differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kolkata b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kolkata new file mode 100644 index 0000000000000000000000000000000000000000..0014046d29a38e9b8006f746fea794d7f71eb479 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kolkata differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk new file mode 100644 index 0000000000000000000000000000000000000000..4c27b2decd1159cf47285f0b18b5ed5178641e82 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur new file mode 100644 index 0000000000000000000000000000000000000000..3d9f191e3acad56fb4f73ab44a74c50cdf91c12e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuching b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuching new file mode 100644 index 0000000000000000000000000000000000000000..098c6a0b0afc2c3ef3a6937104d270074ff2a9b6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuching differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuwait b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuwait new file mode 100644 index 0000000000000000000000000000000000000000..8c8062471dce91a5be827d6908795ee7391a4afc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Kuwait differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macao b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macao new file mode 100644 index 0000000000000000000000000000000000000000..cac65063d0dbf48e37c547fba3b67f34110d5a90 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macao differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macau new file mode 100644 index 0000000000000000000000000000000000000000..cac65063d0dbf48e37c547fba3b67f34110d5a90 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Macau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Magadan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Magadan new file mode 100644 index 0000000000000000000000000000000000000000..70c198baf743457c58a8fe4d1f28186d8541a505 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Magadan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Makassar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Makassar new file mode 100644 index 0000000000000000000000000000000000000000..556ba866933d37f3cfcf8042045d64e209bae30f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Makassar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Manila b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Manila new file mode 100644 index 0000000000000000000000000000000000000000..f4f4b04efa2b6a442d4072b3899f4dae69bdd771 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Manila differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Muscat b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Muscat new file mode 100644 index 0000000000000000000000000000000000000000..b3ac791aef4e73d6d644c40c614f37f15d462cdd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Muscat differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Nicosia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Nicosia new file mode 100644 index 0000000000000000000000000000000000000000..f7f10ab7665e94ca44fd8cd98a362cd4b304eff1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Nicosia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novokuznetsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novokuznetsk new file mode 100644 index 0000000000000000000000000000000000000000..a5e1b79600d21019a3b93f3e2d796129d9b1d655 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novokuznetsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novosibirsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novosibirsk new file mode 100644 index 0000000000000000000000000000000000000000..4ac7582ad5ee895bf9b354436142fd7ece1996ee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Novosibirsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Omsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Omsk new file mode 100644 index 0000000000000000000000000000000000000000..16c5f3cfed75151d50ffc2dc483ac6279816a01f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Omsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Oral b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Oral new file mode 100644 index 0000000000000000000000000000000000000000..3b9ecacf6eef72366df1cc847c0d4666efc8a48c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Oral differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Phnom_Penh b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Phnom_Penh new file mode 100644 index 0000000000000000000000000000000000000000..fa799db39e7625dd74bd9caa5c29b4819a7cbd3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Phnom_Penh differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pontianak b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pontianak new file mode 100644 index 0000000000000000000000000000000000000000..12ce24cbeae404efe6921081d21289be452ff88d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pontianak differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pyongyang b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pyongyang new file mode 100644 index 0000000000000000000000000000000000000000..7ad7e0b2cf8fa4fc844fe8cc9c58e4f3018cead1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Pyongyang differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qatar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qatar new file mode 100644 index 0000000000000000000000000000000000000000..098997e7dd972ca4acedc535c4a645ee966baa33 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qatar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qostanay b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qostanay new file mode 100644 index 0000000000000000000000000000000000000000..f8baf676496adea298f078d6d5931ba7aa64e902 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qostanay differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qyzylorda b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qyzylorda new file mode 100644 index 0000000000000000000000000000000000000000..27b522a7d5e24eafdf29dd541ebbca69ce4db7b8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Qyzylorda differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Rangoon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Rangoon new file mode 100644 index 0000000000000000000000000000000000000000..eef37b42e8a0e7179f8113bea01f4a71d668e8ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Rangoon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Riyadh b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Riyadh new file mode 100644 index 0000000000000000000000000000000000000000..8c8062471dce91a5be827d6908795ee7391a4afc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Riyadh differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Saigon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Saigon new file mode 100644 index 0000000000000000000000000000000000000000..a213d290e1a920271e924506a57191f1f4bfc4c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Saigon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Sakhalin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Sakhalin new file mode 100644 index 0000000000000000000000000000000000000000..beb77b449654decdfec1f6bfc16fafc8bc8ceeaa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Sakhalin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Samarkand b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Samarkand new file mode 100644 index 0000000000000000000000000000000000000000..8a93767bfef2cecbeee15db413a0a7c277e761a1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Samarkand differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Seoul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Seoul new file mode 100644 index 0000000000000000000000000000000000000000..96199e73e73aafacd89e48cb2855a96d7a134e1d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Seoul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Shanghai b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Shanghai new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Shanghai differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Singapore b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Singapore new file mode 100644 index 0000000000000000000000000000000000000000..3d9f191e3acad56fb4f73ab44a74c50cdf91c12e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Singapore differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Srednekolymsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Srednekolymsk new file mode 100644 index 0000000000000000000000000000000000000000..d21e7eeed5408affb3277bde903d6f5f2090ea61 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Srednekolymsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Taipei b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Taipei new file mode 100644 index 0000000000000000000000000000000000000000..24c43444b6751343d2915843d03e55753d4d7359 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Taipei differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tashkent b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tashkent new file mode 100644 index 0000000000000000000000000000000000000000..a9f6cd93c849c8b1677bc54f8bb836c91b40d63d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tashkent differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tbilisi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tbilisi new file mode 100644 index 0000000000000000000000000000000000000000..3b131bb10e100bc2dd619d57367a4e43c86e5316 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tbilisi differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tehran b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tehran new file mode 100644 index 0000000000000000000000000000000000000000..cc2a2c219b0c893cfa8187e962028eb19ea3425d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tehran differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tel_Aviv b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tel_Aviv new file mode 100644 index 0000000000000000000000000000000000000000..1ebd0664aa29c0abd722661f761031ec0304631c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tel_Aviv differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimbu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimbu new file mode 100644 index 0000000000000000000000000000000000000000..95a9de9657f5b8b15aacb6e05c085c7e11bb8f55 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimbu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimphu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimphu new file mode 100644 index 0000000000000000000000000000000000000000..95a9de9657f5b8b15aacb6e05c085c7e11bb8f55 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Thimphu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tokyo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tokyo new file mode 100644 index 0000000000000000000000000000000000000000..26f4d34d67b46513491f26c2e661c6e653cc130d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tokyo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tomsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tomsk new file mode 100644 index 0000000000000000000000000000000000000000..a6e494a78cef4baaa30d06cea4186391788eb30b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Tomsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang new file mode 100644 index 0000000000000000000000000000000000000000..556ba866933d37f3cfcf8042045d64e209bae30f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar new file mode 100644 index 0000000000000000000000000000000000000000..2aa5cc4b84d369b03684c30cdb66b7abf087f467 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulan_Bator b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulan_Bator new file mode 100644 index 0000000000000000000000000000000000000000..2aa5cc4b84d369b03684c30cdb66b7abf087f467 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ulan_Bator differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Urumqi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Urumqi new file mode 100644 index 0000000000000000000000000000000000000000..62bdcac14db3f464ff561e32db2c6b55c0cb1866 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Urumqi differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ust-Nera b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ust-Nera new file mode 100644 index 0000000000000000000000000000000000000000..d05726aba9fd67bf230290b3e2d74b75e46ee214 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Ust-Nera differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vientiane b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vientiane new file mode 100644 index 0000000000000000000000000000000000000000..fa799db39e7625dd74bd9caa5c29b4819a7cbd3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vientiane differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vladivostok b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vladivostok new file mode 100644 index 0000000000000000000000000000000000000000..274a10b43d8089ed522daf9ded5b6aa3653075c9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Vladivostok differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yakutsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yakutsk new file mode 100644 index 0000000000000000000000000000000000000000..ae65a5f9b94d196b29b68ddec7862e098d829b59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yakutsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yangon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yangon new file mode 100644 index 0000000000000000000000000000000000000000..eef37b42e8a0e7179f8113bea01f4a71d668e8ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yangon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yekaterinburg b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yekaterinburg new file mode 100644 index 0000000000000000000000000000000000000000..d4d19ccf1e91121589a7cabff444bc916f67f9ce Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yekaterinburg differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yerevan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yerevan new file mode 100644 index 0000000000000000000000000000000000000000..0d5f6853ac79c41fcb445a23062a27aca9e471f3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Asia/Yerevan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Azores b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Azores new file mode 100644 index 0000000000000000000000000000000000000000..10232ab38ec595b889167a3f0f037a940ef2ac98 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Azores differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Bermuda b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Bermuda new file mode 100644 index 0000000000000000000000000000000000000000..527524ed295aba41b9a0448ffd7993c489a2cb99 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Bermuda differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Canary b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Canary new file mode 100644 index 0000000000000000000000000000000000000000..f3192156ff043a529461aa9004a8de9dda326f7d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Canary differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde new file mode 100644 index 0000000000000000000000000000000000000000..0d0d31a2f092d03f8512ed9c34f36a3f3f21209b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faeroe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faeroe new file mode 100644 index 0000000000000000000000000000000000000000..4dab7ef0859c244b916d61b7489d7371881e0ca2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faeroe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faroe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faroe new file mode 100644 index 0000000000000000000000000000000000000000..4dab7ef0859c244b916d61b7489d7371881e0ca2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Faroe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Madeira b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Madeira new file mode 100644 index 0000000000000000000000000000000000000000..7ddcd883fedcb493b7ab527483c7d4a6d4fc5055 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Madeira differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Reykjavik b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Reykjavik new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Reykjavik differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/South_Georgia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/South_Georgia new file mode 100644 index 0000000000000000000000000000000000000000..a2b59a9d1088690cb2f9ad9011bfa59e6cb5c658 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/South_Georgia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/St_Helena b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/St_Helena new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/St_Helena differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Stanley b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Stanley new file mode 100644 index 0000000000000000000000000000000000000000..1527d0e1a762674748735a95b6c3034d162f4240 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Atlantic/Stanley differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/ACT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/ACT new file mode 100644 index 0000000000000000000000000000000000000000..0aea4c3d43e504dafabc031d7ca9cbe8db46163c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/ACT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Adelaide b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Adelaide new file mode 100644 index 0000000000000000000000000000000000000000..f5dedca59e2b220f7395c73f60ff26e610373e8b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Adelaide differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Brisbane b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Brisbane new file mode 100644 index 0000000000000000000000000000000000000000..7ff9949ffa93e44835ab133998b89e440094f909 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Brisbane differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Broken_Hill b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Broken_Hill new file mode 100644 index 0000000000000000000000000000000000000000..698c76e30e91f568a29daca12993cfacbfdbf83e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Broken_Hill differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Canberra b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Canberra new file mode 100644 index 0000000000000000000000000000000000000000..0aea4c3d43e504dafabc031d7ca9cbe8db46163c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Canberra differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Currie b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Currie new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Currie differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Darwin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Darwin new file mode 100644 index 0000000000000000000000000000000000000000..74a30879bc6180d588a706451226cb4c95faf79d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Darwin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Eucla b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Eucla new file mode 100644 index 0000000000000000000000000000000000000000..1551e96cbc3de5565356954b61aac3c4388e90db Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Eucla differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Hobart b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Hobart new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Hobart differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/LHI b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/LHI new file mode 100644 index 0000000000000000000000000000000000000000..069a95ad686c1139e2ff2b9ce94dc5ef5bc98c67 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/LHI differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lindeman b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lindeman new file mode 100644 index 0000000000000000000000000000000000000000..4ee1825abfe65887069dcbd10bcf786d50ba0702 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lindeman differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lord_Howe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lord_Howe new file mode 100644 index 0000000000000000000000000000000000000000..069a95ad686c1139e2ff2b9ce94dc5ef5bc98c67 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Lord_Howe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Melbourne b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Melbourne new file mode 100644 index 0000000000000000000000000000000000000000..ee903f4b1fc292bc9cbec7b501a266030ef3510e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Melbourne differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/NSW b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/NSW new file mode 100644 index 0000000000000000000000000000000000000000..0aea4c3d43e504dafabc031d7ca9cbe8db46163c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/NSW differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/North b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/North new file mode 100644 index 0000000000000000000000000000000000000000..74a30879bc6180d588a706451226cb4c95faf79d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/North differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Perth b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Perth new file mode 100644 index 0000000000000000000000000000000000000000..f8ddbdf215d34b022af11c3d1930dd6ea4dca87e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Perth differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Queensland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Queensland new file mode 100644 index 0000000000000000000000000000000000000000..7ff9949ffa93e44835ab133998b89e440094f909 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Queensland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/South b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/South new file mode 100644 index 0000000000000000000000000000000000000000..f5dedca59e2b220f7395c73f60ff26e610373e8b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/South differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Sydney b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Sydney new file mode 100644 index 0000000000000000000000000000000000000000..0aea4c3d43e504dafabc031d7ca9cbe8db46163c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Sydney differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Tasmania b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Tasmania new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Tasmania differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Victoria b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Victoria new file mode 100644 index 0000000000000000000000000000000000000000..ee903f4b1fc292bc9cbec7b501a266030ef3510e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Victoria differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/West b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/West new file mode 100644 index 0000000000000000000000000000000000000000..f8ddbdf215d34b022af11c3d1930dd6ea4dca87e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/West differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Yancowinna b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Yancowinna new file mode 100644 index 0000000000000000000000000000000000000000..698c76e30e91f568a29daca12993cfacbfdbf83e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Australia/Yancowinna differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/Acre b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/Acre new file mode 100644 index 0000000000000000000000000000000000000000..cdda168cb97b1d45a4f1b7791a74523b74c88e6d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/Acre differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/DeNoronha b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/DeNoronha new file mode 100644 index 0000000000000000000000000000000000000000..73b4b336ab55544e6061409261c16cacc39aff61 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/DeNoronha differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/East b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/East new file mode 100644 index 0000000000000000000000000000000000000000..67935ff4da8f527e03cd05ed2aa20e601e10f921 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/East differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/West b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/West new file mode 100644 index 0000000000000000000000000000000000000000..2708baea5af1d5169a1cebd00c4762d6bb937fda Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Brazil/West differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CET b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CET new file mode 100644 index 0000000000000000000000000000000000000000..122e934210cabf0b29a2dd7d11eb8220ed1cad43 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CET differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CST6CDT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CST6CDT new file mode 100644 index 0000000000000000000000000000000000000000..ca67929fbeb05083c63e8319dd9ebf65b3d75e4d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/CST6CDT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Atlantic b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Atlantic new file mode 100644 index 0000000000000000000000000000000000000000..756099abe6cee44295a5566ad6cd0c352fb82e64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Atlantic differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Central b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Central new file mode 100644 index 0000000000000000000000000000000000000000..ac40299f6b27043e8f2454ac594b0ec184c1a237 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Central differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Eastern b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Eastern new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Eastern differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Mountain b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Mountain new file mode 100644 index 0000000000000000000000000000000000000000..cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Mountain differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Newfoundland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Newfoundland new file mode 100644 index 0000000000000000000000000000000000000000..65a5b0c720dad151ffdcba3dbe91c8bd638845c6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Newfoundland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Pacific b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Pacific new file mode 100644 index 0000000000000000000000000000000000000000..bb60cbced30763c08b6cf73554c8d6651ff387d0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Pacific differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Saskatchewan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Saskatchewan new file mode 100644 index 0000000000000000000000000000000000000000..20c9c84df491e4072ec4c5d2c931a7433d9fd394 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Saskatchewan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Yukon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Yukon new file mode 100644 index 0000000000000000000000000000000000000000..318c4a8e4003bcff00f9a21e294e7815f170235b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Canada/Yukon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/Continental b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/Continental new file mode 100644 index 0000000000000000000000000000000000000000..010c6bd04cae79078540da560ce38400bfe0ade6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/Continental differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/EasterIsland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/EasterIsland new file mode 100644 index 0000000000000000000000000000000000000000..184cb6a83b3392d0492c42297531c85e7e38c4f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Chile/EasterIsland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Cuba b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Cuba new file mode 100644 index 0000000000000000000000000000000000000000..b69ac4510784f23ee794cd6d11e62315a7318e5e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Cuba differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EET b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EET new file mode 100644 index 0000000000000000000000000000000000000000..cbdb71ddd38be8f4a23e57bdb4b86e52195e9f89 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EET differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST new file mode 100644 index 0000000000000000000000000000000000000000..21ebc00b3fc096035b9810519d778d04a3562a44 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST5EDT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST5EDT new file mode 100644 index 0000000000000000000000000000000000000000..9bce5007d4dbb871974a69cb0f68151c1ee22556 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/EST5EDT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Egypt b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Egypt new file mode 100644 index 0000000000000000000000000000000000000000..dd538c65db6ed0a0e47feb7b6001640516958e19 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Egypt differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Eire b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Eire new file mode 100644 index 0000000000000000000000000000000000000000..c729def42fc0822e6b24f7bf503c67cc7e6965f0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Eire differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+1 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+1 new file mode 100644 index 0000000000000000000000000000000000000000..4dab6f9005bea50a065c685ec8260b0da2bff921 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+1 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+10 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+10 new file mode 100644 index 0000000000000000000000000000000000000000..c749290af2f6b5fe22770c34eb1e8fc87cd85aff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+10 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+11 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+11 new file mode 100644 index 0000000000000000000000000000000000000000..d969982309e5ca7d32979a7dad814ca307d2cd8d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+11 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+12 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+12 new file mode 100644 index 0000000000000000000000000000000000000000..cdeec90973be28ee4075eadd22b8b574db2d7a5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+12 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+2 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+2 new file mode 100644 index 0000000000000000000000000000000000000000..fbd2a941fda996f4abc1f0e09cdf99c271f5a1e2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+2 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+3 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+3 new file mode 100644 index 0000000000000000000000000000000000000000..ee246ef56f18de61105af0c14d201fd090f74905 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+3 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+4 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+4 new file mode 100644 index 0000000000000000000000000000000000000000..5a25ff2a6afda2cb09b9e147ad20610bc1923444 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+4 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+5 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+5 new file mode 100644 index 0000000000000000000000000000000000000000..c0b745f1cc44d03a00f8bdf127c154392e3baf27 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+5 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+6 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+6 new file mode 100644 index 0000000000000000000000000000000000000000..06e777d57e0267a0635b6b284729fddcfe6221dd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+6 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+7 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+7 new file mode 100644 index 0000000000000000000000000000000000000000..4e0b53a082f11f9b9debf5e110b97b1b0473c9a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+7 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+8 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+8 new file mode 100644 index 0000000000000000000000000000000000000000..714b0c562889a8a774d9aa27810d8400164d00e6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+8 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+9 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+9 new file mode 100644 index 0000000000000000000000000000000000000000..78b9daa373d2aa2856eafcc92ebc6d899cafde5c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT+9 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-1 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-1 new file mode 100644 index 0000000000000000000000000000000000000000..a838bebf5e7bac3e1257eeb0a61c1b83feb1324c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-1 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-10 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-10 new file mode 100644 index 0000000000000000000000000000000000000000..68ff77db0d95c7d054ef33c05e05ba71bcbbbdd8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-10 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-11 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-11 new file mode 100644 index 0000000000000000000000000000000000000000..66af5a42be440f1fb8fec3b915afb49b356f63a5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-11 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-12 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-12 new file mode 100644 index 0000000000000000000000000000000000000000..17ba5057727dd73bd5f6234cc5b239b71a861945 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-12 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-13 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-13 new file mode 100644 index 0000000000000000000000000000000000000000..5f3706ce64cadf081a6c56abd7ba423575a4abb2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-13 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-14 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-14 new file mode 100644 index 0000000000000000000000000000000000000000..7e9f9c465ce6211c65d617f60472c9b55b5052c5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-14 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-2 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-2 new file mode 100644 index 0000000000000000000000000000000000000000..fcef6d9acb247deb539fcc4b30149802572ea642 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-2 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-3 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-3 new file mode 100644 index 0000000000000000000000000000000000000000..27973bc857b4e618218ca2790acacb81f7c7bb82 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-3 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-4 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-4 new file mode 100644 index 0000000000000000000000000000000000000000..1efd841261a977ae218d408f9cc308c3e312a5e8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-4 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-5 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-5 new file mode 100644 index 0000000000000000000000000000000000000000..1f761844fc44f8228bb748235bfd30be6c389cd1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-5 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-6 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-6 new file mode 100644 index 0000000000000000000000000000000000000000..952681ed46cb60e59baf76a2c43b49d5f67255d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-6 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-7 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-7 new file mode 100644 index 0000000000000000000000000000000000000000..cefc9126c691060225ff2eee1241b1e5e9825fcd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-7 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-8 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-8 new file mode 100644 index 0000000000000000000000000000000000000000..afb093da00685297cb11347c4840acf3a8e2e2bf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-8 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-9 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-9 new file mode 100644 index 0000000000000000000000000000000000000000..9265fb7c2071ec0e66c657ad2ae42d5dd525fe97 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT-9 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/GMT0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Greenwich b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Greenwich new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Greenwich differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UCT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UCT new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UCT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UTC b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UTC new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/UTC differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Universal b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Universal new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Universal differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Zulu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Zulu new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Etc/Zulu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Amsterdam b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Amsterdam new file mode 100644 index 0000000000000000000000000000000000000000..40d7124e5346af056c75e2f7012a51d94e8154b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Amsterdam differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Andorra b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Andorra new file mode 100644 index 0000000000000000000000000000000000000000..5962550392fa78514061582e9371c32b9f1d929b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Andorra differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Astrakhan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Astrakhan new file mode 100644 index 0000000000000000000000000000000000000000..a41624f5df9698d78049008a2bd8a77395c0480a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Astrakhan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Athens b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Athens new file mode 100644 index 0000000000000000000000000000000000000000..9f3a0678d766881389e129c93def7fffd74f14f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Athens differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belfast b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belfast new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belfast differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belgrade b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belgrade new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Belgrade differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Berlin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Berlin new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Berlin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bratislava b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bratislava new file mode 100644 index 0000000000000000000000000000000000000000..ce8f433ece44f0b96b18d3b5780730e7f9cad9f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bratislava differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Brussels b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Brussels new file mode 100644 index 0000000000000000000000000000000000000000..40d7124e5346af056c75e2f7012a51d94e8154b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Brussels differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bucharest b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bucharest new file mode 100644 index 0000000000000000000000000000000000000000..4303b903e5e007484c0d8e1eea43a35e9b53f38b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Bucharest differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Budapest b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Budapest new file mode 100644 index 0000000000000000000000000000000000000000..b76c873d9256e1d73c2ea672140b813f15657bc7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Budapest differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Busingen b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Busingen new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Busingen differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Chisinau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Chisinau new file mode 100644 index 0000000000000000000000000000000000000000..5ee23fe0e59f044598675db44d53c20590b88934 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Chisinau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Copenhagen b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Copenhagen new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Copenhagen differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Dublin b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Dublin new file mode 100644 index 0000000000000000000000000000000000000000..c729def42fc0822e6b24f7bf503c67cc7e6965f0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Dublin differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Gibraltar b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Gibraltar new file mode 100644 index 0000000000000000000000000000000000000000..a38f11ffdf2a9e538695ea8cae20b1d2c04164af Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Gibraltar differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Guernsey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Guernsey new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Guernsey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Helsinki b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Helsinki new file mode 100644 index 0000000000000000000000000000000000000000..b4f8f9cbb57450549933f83ac90dd56a2ca75344 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Helsinki differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Isle_of_Man b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Isle_of_Man new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Isle_of_Man differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Istanbul b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Istanbul new file mode 100644 index 0000000000000000000000000000000000000000..7c2336dd80c3c9cbf71cb53d2b2c1f89a65a8ba5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Istanbul differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Jersey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Jersey new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Jersey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kaliningrad b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kaliningrad new file mode 100644 index 0000000000000000000000000000000000000000..cc99beabe4ffc5107c4719d1201d6583b9ead03a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kaliningrad differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kiev b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kiev new file mode 100644 index 0000000000000000000000000000000000000000..52efea88065b220e44fd876de3bf3090fe62cc79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kiev differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kirov b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kirov new file mode 100644 index 0000000000000000000000000000000000000000..0cfb956be223ab593ca27569ad554dae9b106117 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kirov differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kyiv b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kyiv new file mode 100644 index 0000000000000000000000000000000000000000..52efea88065b220e44fd876de3bf3090fe62cc79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Kyiv differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Lisbon b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Lisbon new file mode 100644 index 0000000000000000000000000000000000000000..55f01930ba92ff6852ae4745e78adb5f96c5b057 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Lisbon differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ljubljana b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ljubljana new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ljubljana differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/London b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/London new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/London differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Luxembourg b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Luxembourg new file mode 100644 index 0000000000000000000000000000000000000000..40d7124e5346af056c75e2f7012a51d94e8154b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Luxembourg differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Madrid b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Madrid new file mode 100644 index 0000000000000000000000000000000000000000..53f4cd101c18058a1ee4d4b9d1184ada11d74232 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Madrid differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Malta b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Malta new file mode 100644 index 0000000000000000000000000000000000000000..1d1a7bcfcbbf37ff1ad7025f9843d0d2d8cb06d4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Malta differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Mariehamn b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Mariehamn new file mode 100644 index 0000000000000000000000000000000000000000..b4f8f9cbb57450549933f83ac90dd56a2ca75344 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Mariehamn differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Minsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Minsk new file mode 100644 index 0000000000000000000000000000000000000000..3731e40d8634c4d58ddb3378d828c92948f06d67 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Minsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Monaco b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Monaco new file mode 100644 index 0000000000000000000000000000000000000000..7d366c6098c49ecd546e1cc1538919e1414a3aee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Monaco differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Moscow b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Moscow new file mode 100644 index 0000000000000000000000000000000000000000..ddb3f4e99a1030f33b56fad986c8d9c16e59eb32 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Moscow differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Nicosia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Nicosia new file mode 100644 index 0000000000000000000000000000000000000000..f7f10ab7665e94ca44fd8cd98a362cd4b304eff1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Nicosia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Oslo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Oslo new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Oslo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Paris b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Paris new file mode 100644 index 0000000000000000000000000000000000000000..7d366c6098c49ecd546e1cc1538919e1414a3aee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Paris differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Podgorica b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Podgorica new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Podgorica differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Prague b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Prague new file mode 100644 index 0000000000000000000000000000000000000000..ce8f433ece44f0b96b18d3b5780730e7f9cad9f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Prague differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Riga b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Riga new file mode 100644 index 0000000000000000000000000000000000000000..8db477d01736445cafce8af7a7085d226d81f546 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Riga differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Rome b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Rome new file mode 100644 index 0000000000000000000000000000000000000000..32b2899a306dde401fa2e3952d06f5f4d9952bed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Rome differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Samara b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Samara new file mode 100644 index 0000000000000000000000000000000000000000..d0ea2f25e9b4acaf3167a09a1c647943425e51b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Samara differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/San_Marino b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/San_Marino new file mode 100644 index 0000000000000000000000000000000000000000..32b2899a306dde401fa2e3952d06f5f4d9952bed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/San_Marino differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sarajevo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sarajevo new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sarajevo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Saratov b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Saratov new file mode 100644 index 0000000000000000000000000000000000000000..a863913358adb7a9118fcc48a6a5dcfba5f9914b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Saratov differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Simferopol b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Simferopol new file mode 100644 index 0000000000000000000000000000000000000000..4bf24de1d9f8ebc410f120aa83d98b7e41d1e6c4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Simferopol differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Skopje b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Skopje new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Skopje differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sofia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sofia new file mode 100644 index 0000000000000000000000000000000000000000..0e4d879332d21c93c229fc25587205020eeb3127 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Sofia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Stockholm b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Stockholm new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Stockholm differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tallinn b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tallinn new file mode 100644 index 0000000000000000000000000000000000000000..b5acca3cf51e7f7b3176965748688ff41720246f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tallinn differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tirane b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tirane new file mode 100644 index 0000000000000000000000000000000000000000..0b86017d243f1b7bbb41d6b4feefcb2b7edfc7d8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tirane differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tiraspol b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tiraspol new file mode 100644 index 0000000000000000000000000000000000000000..5ee23fe0e59f044598675db44d53c20590b88934 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Tiraspol differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ulyanovsk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ulyanovsk new file mode 100644 index 0000000000000000000000000000000000000000..d668233b37f268a745e995177195b06ffab1e69b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Ulyanovsk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Uzhgorod b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Uzhgorod new file mode 100644 index 0000000000000000000000000000000000000000..52efea88065b220e44fd876de3bf3090fe62cc79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Uzhgorod differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vaduz b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vaduz new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vaduz differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vatican b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vatican new file mode 100644 index 0000000000000000000000000000000000000000..32b2899a306dde401fa2e3952d06f5f4d9952bed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vatican differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vienna b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vienna new file mode 100644 index 0000000000000000000000000000000000000000..3582bb15cd7322088839b0134987ad10e717b6b5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vienna differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vilnius b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vilnius new file mode 100644 index 0000000000000000000000000000000000000000..7abd63fa608e0186b9f154d9fcc32472c28f6759 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Vilnius differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Volgograd b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Volgograd new file mode 100644 index 0000000000000000000000000000000000000000..9d51a38c0ea719c5042837d47e0f427057b845f0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Volgograd differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Warsaw b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Warsaw new file mode 100644 index 0000000000000000000000000000000000000000..e33cf67171da78aa9e6eb02e50f9b9603da4c3f4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Warsaw differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zagreb b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zagreb new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zagreb differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zaporozhye b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zaporozhye new file mode 100644 index 0000000000000000000000000000000000000000..52efea88065b220e44fd876de3bf3090fe62cc79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zaporozhye differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zurich b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zurich new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Europe/Zurich differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Factory b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Factory new file mode 100644 index 0000000000000000000000000000000000000000..60aa2a0d695ba577ff87624d479f1eb25c8f1caf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Factory differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB-Eire b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB-Eire new file mode 100644 index 0000000000000000000000000000000000000000..5ad74220e83e6c30a0aeefda4a00271b8ebdfcad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GB-Eire differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT+0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT+0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT+0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT-0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT-0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT-0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT0 b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/GMT0 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Greenwich b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Greenwich new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Greenwich differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/HST b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/HST new file mode 100644 index 0000000000000000000000000000000000000000..cccd45eb8cb2f56b6a1b75e2d7b9530cb5abf2e1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/HST differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Hongkong b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Hongkong new file mode 100644 index 0000000000000000000000000000000000000000..f9f7b134dd5c35e4718c6fa3697024cb95442c53 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Hongkong differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iceland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iceland new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iceland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Antananarivo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Antananarivo new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Antananarivo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Chagos b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Chagos new file mode 100644 index 0000000000000000000000000000000000000000..a5554816e2928c2bd5d02e032bbeb1e1cb101009 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Chagos differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Christmas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Christmas new file mode 100644 index 0000000000000000000000000000000000000000..fa799db39e7625dd74bd9caa5c29b4819a7cbd3f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Christmas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Cocos b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Cocos new file mode 100644 index 0000000000000000000000000000000000000000..eef37b42e8a0e7179f8113bea01f4a71d668e8ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Cocos differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Comoro b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Comoro new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Comoro differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Kerguelen b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Kerguelen new file mode 100644 index 0000000000000000000000000000000000000000..555728b1a0187cc0ac63b8fe45c44bd1e0957918 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Kerguelen differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mahe b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mahe new file mode 100644 index 0000000000000000000000000000000000000000..b3ac791aef4e73d6d644c40c614f37f15d462cdd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mahe differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Maldives b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Maldives new file mode 100644 index 0000000000000000000000000000000000000000..555728b1a0187cc0ac63b8fe45c44bd1e0957918 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Maldives differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mauritius b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mauritius new file mode 100644 index 0000000000000000000000000000000000000000..212d4b2e2afaed06110a1acff4fdb6bd6103b4ff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mauritius differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mayotte b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mayotte new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Mayotte differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Reunion b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Reunion new file mode 100644 index 0000000000000000000000000000000000000000..b3ac791aef4e73d6d644c40c614f37f15d462cdd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Indian/Reunion differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iran b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iran new file mode 100644 index 0000000000000000000000000000000000000000..cc2a2c219b0c893cfa8187e962028eb19ea3425d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Iran differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Israel b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Israel new file mode 100644 index 0000000000000000000000000000000000000000..1ebd0664aa29c0abd722661f761031ec0304631c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Israel differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Jamaica b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Jamaica new file mode 100644 index 0000000000000000000000000000000000000000..2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Jamaica differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Japan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Japan new file mode 100644 index 0000000000000000000000000000000000000000..26f4d34d67b46513491f26c2e661c6e653cc130d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Japan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Kwajalein b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Kwajalein new file mode 100644 index 0000000000000000000000000000000000000000..1887a607422edd499fdf24afe91a04294f1caf6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Kwajalein differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Libya b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Libya new file mode 100644 index 0000000000000000000000000000000000000000..07b393bb7db14cef1e906ebe63cfbbe8cddc79d5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Libya differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MET b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MET new file mode 100644 index 0000000000000000000000000000000000000000..4a826bb185531c34eb37959037c68fbf08c23f71 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MET differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST new file mode 100644 index 0000000000000000000000000000000000000000..c93a58eee8b32f672fd3a96ca3e6ada5b0a0e168 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST7MDT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST7MDT new file mode 100644 index 0000000000000000000000000000000000000000..4506a6e150dfd73884811c8c0f5a0e21dc76a756 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/MST7MDT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaNorte b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaNorte new file mode 100644 index 0000000000000000000000000000000000000000..63dfdf48a68d02240737ecd6af081e02eb0b6317 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaNorte differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaSur b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaSur new file mode 100644 index 0000000000000000000000000000000000000000..06fa22749d0a3157b5a693f0797086f78e1201c5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/BajaSur differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/General b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/General new file mode 100644 index 0000000000000000000000000000000000000000..68176daa4976b015fb79026f3053e74e4a7457ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Mexico/General differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ-CHAT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ-CHAT new file mode 100644 index 0000000000000000000000000000000000000000..bde46cf7e4b7909714b93cee39a5d953387d756c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/NZ-CHAT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Navajo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Navajo new file mode 100644 index 0000000000000000000000000000000000000000..abb2b974a47eb3e5c8b4f5d4370baf4898b239ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Navajo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PRC b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PRC new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PRC differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PST8PDT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PST8PDT new file mode 100644 index 0000000000000000000000000000000000000000..99d246baa35cb9c6f56d50adbec163452e2a47fa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/PST8PDT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Apia b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Apia new file mode 100644 index 0000000000000000000000000000000000000000..e592a68e53f6215de9e1d1ac61ce062a333283c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Apia differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Auckland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Auckland new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Auckland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Bougainville b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Bougainville new file mode 100644 index 0000000000000000000000000000000000000000..c535acdabda1b6ed96420e589d4f6868d23d8933 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Bougainville differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chatham b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chatham new file mode 100644 index 0000000000000000000000000000000000000000..bde46cf7e4b7909714b93cee39a5d953387d756c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chatham differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chuuk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chuuk new file mode 100644 index 0000000000000000000000000000000000000000..7be2474dd91c8a7da181fcda09d838254b890d75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Chuuk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Easter b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Easter new file mode 100644 index 0000000000000000000000000000000000000000..184cb6a83b3392d0492c42297531c85e7e38c4f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Easter differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Efate b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Efate new file mode 100644 index 0000000000000000000000000000000000000000..777325fc6c6da8795d89aed5206c60f8bf80b0ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Efate differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Enderbury b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Enderbury new file mode 100644 index 0000000000000000000000000000000000000000..b1c4b0734483033722c28c8b2884ac9dddd2ab45 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Enderbury differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fakaofo b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fakaofo new file mode 100644 index 0000000000000000000000000000000000000000..4905ea72b1640ca67e35b06395e1c700dffa8d21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fakaofo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fiji b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fiji new file mode 100644 index 0000000000000000000000000000000000000000..acf8091ac85151a6c887e2b5049ee40754b7b0d3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Fiji differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Funafuti b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Funafuti new file mode 100644 index 0000000000000000000000000000000000000000..47661d40a4188eb39e8d52e5af8ab23ef7f23766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Funafuti differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Galapagos b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Galapagos new file mode 100644 index 0000000000000000000000000000000000000000..40051ddf63a32d79e5233b916e3911d6dc3ef759 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Galapagos differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Gambier b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Gambier new file mode 100644 index 0000000000000000000000000000000000000000..84acaf41520d2d302f75e300e2b47c5527218df4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Gambier differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guadalcanal b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guadalcanal new file mode 100644 index 0000000000000000000000000000000000000000..1ab8353464ddb93947f871f07cfd12540373269c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guadalcanal differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guam b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guam new file mode 100644 index 0000000000000000000000000000000000000000..66490d25dff9bcc8f710b0141f1a02e64aeb32f3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Guam differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Honolulu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Honolulu new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Honolulu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Johnston b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Johnston new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Johnston differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kanton b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kanton new file mode 100644 index 0000000000000000000000000000000000000000..b1c4b0734483033722c28c8b2884ac9dddd2ab45 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kanton differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kiritimati b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kiritimati new file mode 100644 index 0000000000000000000000000000000000000000..b4c6037a2d2a8f89539c3df05c32b6f52b1b1e92 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kiritimati differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kosrae b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kosrae new file mode 100644 index 0000000000000000000000000000000000000000..0666fb0dd161cb732b29f84d49c49cc985a3559a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kosrae differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kwajalein b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kwajalein new file mode 100644 index 0000000000000000000000000000000000000000..1887a607422edd499fdf24afe91a04294f1caf6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Kwajalein differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Majuro b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Majuro new file mode 100644 index 0000000000000000000000000000000000000000..47661d40a4188eb39e8d52e5af8ab23ef7f23766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Majuro differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Marquesas b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Marquesas new file mode 100644 index 0000000000000000000000000000000000000000..f546c03f96b24859521aab5b9997bfc5dd124ead Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Marquesas differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Midway b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Midway new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Midway differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Nauru b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Nauru new file mode 100644 index 0000000000000000000000000000000000000000..3339b6cf86d6e98ba70c9bd6cab3dbf50588acd2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Nauru differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Niue b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Niue new file mode 100644 index 0000000000000000000000000000000000000000..f76972f8849a7d6ed8c3e2649b02f44de891094f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Niue differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Norfolk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Norfolk new file mode 100644 index 0000000000000000000000000000000000000000..3b4186d61152629b764efc4222e41647b65f7fbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Norfolk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Noumea b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Noumea new file mode 100644 index 0000000000000000000000000000000000000000..959cc8cd26f8a7b10a70e0f93bf3b3c9bbc680d2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Noumea differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pago_Pago b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pago_Pago new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pago_Pago differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Palau b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Palau new file mode 100644 index 0000000000000000000000000000000000000000..1cbebe28afd90c0a2e02786655e18a157284a412 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Palau differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pitcairn b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pitcairn new file mode 100644 index 0000000000000000000000000000000000000000..5ee90e70203d72484b8752475c86139671bcb102 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pitcairn differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pohnpei b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pohnpei new file mode 100644 index 0000000000000000000000000000000000000000..1ab8353464ddb93947f871f07cfd12540373269c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Pohnpei differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Ponape b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Ponape new file mode 100644 index 0000000000000000000000000000000000000000..1ab8353464ddb93947f871f07cfd12540373269c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Ponape differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Port_Moresby b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Port_Moresby new file mode 100644 index 0000000000000000000000000000000000000000..7be2474dd91c8a7da181fcda09d838254b890d75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Port_Moresby differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Rarotonga b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Rarotonga new file mode 100644 index 0000000000000000000000000000000000000000..184a87c112b99536acbafa1ec7aba52c7a94b549 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Rarotonga differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Saipan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Saipan new file mode 100644 index 0000000000000000000000000000000000000000..66490d25dff9bcc8f710b0141f1a02e64aeb32f3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Saipan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Samoa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Samoa new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Samoa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tahiti b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tahiti new file mode 100644 index 0000000000000000000000000000000000000000..481edd30580f00eccf69de4f1c332fc048210011 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tahiti differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tarawa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tarawa new file mode 100644 index 0000000000000000000000000000000000000000..47661d40a4188eb39e8d52e5af8ab23ef7f23766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tarawa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tongatapu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tongatapu new file mode 100644 index 0000000000000000000000000000000000000000..c8824ab5434985650f33e12eace1981f8b116207 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Tongatapu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Truk b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Truk new file mode 100644 index 0000000000000000000000000000000000000000..7be2474dd91c8a7da181fcda09d838254b890d75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Truk differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wake b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wake new file mode 100644 index 0000000000000000000000000000000000000000..47661d40a4188eb39e8d52e5af8ab23ef7f23766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wake differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wallis b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wallis new file mode 100644 index 0000000000000000000000000000000000000000..47661d40a4188eb39e8d52e5af8ab23ef7f23766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Wallis differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Yap b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Yap new file mode 100644 index 0000000000000000000000000000000000000000..7be2474dd91c8a7da181fcda09d838254b890d75 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Pacific/Yap differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Poland b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Poland new file mode 100644 index 0000000000000000000000000000000000000000..e33cf67171da78aa9e6eb02e50f9b9603da4c3f4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Poland differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Portugal b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Portugal new file mode 100644 index 0000000000000000000000000000000000000000..55f01930ba92ff6852ae4745e78adb5f96c5b057 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Portugal differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROC b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROC new file mode 100644 index 0000000000000000000000000000000000000000..24c43444b6751343d2915843d03e55753d4d7359 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROC differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROK b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROK new file mode 100644 index 0000000000000000000000000000000000000000..96199e73e73aafacd89e48cb2855a96d7a134e1d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/ROK differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Singapore b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Singapore new file mode 100644 index 0000000000000000000000000000000000000000..3d9f191e3acad56fb4f73ab44a74c50cdf91c12e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Singapore differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Turkey b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Turkey new file mode 100644 index 0000000000000000000000000000000000000000..7c2336dd80c3c9cbf71cb53d2b2c1f89a65a8ba5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Turkey differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UCT b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UCT new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UCT differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Alaska b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Alaska new file mode 100644 index 0000000000000000000000000000000000000000..9bbb2fd3b361ea8aa4c126d14df5fa370343a63f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Alaska differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Aleutian b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Aleutian new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Aleutian differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Arizona b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Arizona new file mode 100644 index 0000000000000000000000000000000000000000..ab37e845566aa95659b7b85be0051d0c67a7e53a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Arizona differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Central b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Central new file mode 100644 index 0000000000000000000000000000000000000000..c6981a06b1d9c26f447518efe265a6454726eae7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Central differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/East-Indiana b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/East-Indiana new file mode 100644 index 0000000000000000000000000000000000000000..a84b6e99671f7305d1c459956e16a4dd772fc60e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/East-Indiana differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Eastern b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Eastern new file mode 100644 index 0000000000000000000000000000000000000000..a8b9ab1992257d721ad627b14f535c3d4b020888 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Eastern differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Hawaii b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Hawaii new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Hawaii differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Indiana-Starke b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Indiana-Starke new file mode 100644 index 0000000000000000000000000000000000000000..025d132dd48ba978c6fedf86d70173127be49d49 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Indiana-Starke differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Michigan b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Michigan new file mode 100644 index 0000000000000000000000000000000000000000..e104faa46545ee873295cde34e1d46bccad8647c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Michigan differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Mountain b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Mountain new file mode 100644 index 0000000000000000000000000000000000000000..abb2b974a47eb3e5c8b4f5d4370baf4898b239ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Mountain differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Pacific b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Pacific new file mode 100644 index 0000000000000000000000000000000000000000..610e7af5fc13d9784de30d272c7c39d7938873a0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Pacific differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Samoa b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Samoa new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/US/Samoa differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UTC b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UTC new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/UTC differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Universal b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Universal new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Universal differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/W-SU b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/W-SU new file mode 100644 index 0000000000000000000000000000000000000000..ddb3f4e99a1030f33b56fad986c8d9c16e59eb32 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/W-SU differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/WET b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/WET new file mode 100644 index 0000000000000000000000000000000000000000..c27390b5b638399057d5f5c6d09ef8c81d5f01c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/WET differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Zulu b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Zulu new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/Zulu differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/iso3166.tab b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/iso3166.tab new file mode 100644 index 0000000000000000000000000000000000000000..be3348d11a79cdb4f3230df95567df39bb54766e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/iso3166.tab @@ -0,0 +1,274 @@ +# ISO 3166 alpha-2 country codes +# +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# +# From Paul Eggert (2022-11-18): +# This file contains a table of two-letter country codes. Columns are +# separated by a single tab. Lines beginning with '#' are comments. +# All text uses UTF-8 encoding. The columns of the table are as follows: +# +# 1. ISO 3166-1 alpha-2 country code, current as of +# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 +# https://isotc.iso.org/livelink/livelink/Open/16944257 +# 2. The usual English name for the coded region, +# chosen so that alphabetic sorting of subsets produces helpful lists. +# This is not the same as the English name in the ISO 3166 tables. +# +# The table is sorted by country code. +# +# This table is intended as an aid for users, to help them select time +# zone data appropriate for their practical needs. It is not intended +# to take or endorse any position on legal or territorial claims. +# +#country- +#code name of country, territory, area, or subdivision +AD Andorra +AE United Arab Emirates +AF Afghanistan +AG Antigua & Barbuda +AI Anguilla +AL Albania +AM Armenia +AO Angola +AQ Antarctica +AR Argentina +AS Samoa (American) +AT Austria +AU Australia +AW Aruba +AX Åland Islands +AZ Azerbaijan +BA Bosnia & Herzegovina +BB Barbados +BD Bangladesh +BE Belgium +BF Burkina Faso +BG Bulgaria +BH Bahrain +BI Burundi +BJ Benin +BL St Barthelemy +BM Bermuda +BN Brunei +BO Bolivia +BQ Caribbean NL +BR Brazil +BS Bahamas +BT Bhutan +BV Bouvet Island +BW Botswana +BY Belarus +BZ Belize +CA Canada +CC Cocos (Keeling) Islands +CD Congo (Dem. Rep.) +CF Central African Rep. +CG Congo (Rep.) +CH Switzerland +CI Côte d'Ivoire +CK Cook Islands +CL Chile +CM Cameroon +CN China +CO Colombia +CR Costa Rica +CU Cuba +CV Cape Verde +CW Curaçao +CX Christmas Island +CY Cyprus +CZ Czech Republic +DE Germany +DJ Djibouti +DK Denmark +DM Dominica +DO Dominican Republic +DZ Algeria +EC Ecuador +EE Estonia +EG Egypt +EH Western Sahara +ER Eritrea +ES Spain +ET Ethiopia +FI Finland +FJ Fiji +FK Falkland Islands +FM Micronesia +FO Faroe Islands +FR France +GA Gabon +GB Britain (UK) +GD Grenada +GE Georgia +GF French Guiana +GG Guernsey +GH Ghana +GI Gibraltar +GL Greenland +GM Gambia +GN Guinea +GP Guadeloupe +GQ Equatorial Guinea +GR Greece +GS South Georgia & the South Sandwich Islands +GT Guatemala +GU Guam +GW Guinea-Bissau +GY Guyana +HK Hong Kong +HM Heard Island & McDonald Islands +HN Honduras +HR Croatia +HT Haiti +HU Hungary +ID Indonesia +IE Ireland +IL Israel +IM Isle of Man +IN India +IO British Indian Ocean Territory +IQ Iraq +IR Iran +IS Iceland +IT Italy +JE Jersey +JM Jamaica +JO Jordan +JP Japan +KE Kenya +KG Kyrgyzstan +KH Cambodia +KI Kiribati +KM Comoros +KN St Kitts & Nevis +KP Korea (North) +KR Korea (South) +KW Kuwait +KY Cayman Islands +KZ Kazakhstan +LA Laos +LB Lebanon +LC St Lucia +LI Liechtenstein +LK Sri Lanka +LR Liberia +LS Lesotho +LT Lithuania +LU Luxembourg +LV Latvia +LY Libya +MA Morocco +MC Monaco +MD Moldova +ME Montenegro +MF St Martin (French) +MG Madagascar +MH Marshall Islands +MK North Macedonia +ML Mali +MM Myanmar (Burma) +MN Mongolia +MO Macau +MP Northern Mariana Islands +MQ Martinique +MR Mauritania +MS Montserrat +MT Malta +MU Mauritius +MV Maldives +MW Malawi +MX Mexico +MY Malaysia +MZ Mozambique +NA Namibia +NC New Caledonia +NE Niger +NF Norfolk Island +NG Nigeria +NI Nicaragua +NL Netherlands +NO Norway +NP Nepal +NR Nauru +NU Niue +NZ New Zealand +OM Oman +PA Panama +PE Peru +PF French Polynesia +PG Papua New Guinea +PH Philippines +PK Pakistan +PL Poland +PM St Pierre & Miquelon +PN Pitcairn +PR Puerto Rico +PS Palestine +PT Portugal +PW Palau +PY Paraguay +QA Qatar +RE Réunion +RO Romania +RS Serbia +RU Russia +RW Rwanda +SA Saudi Arabia +SB Solomon Islands +SC Seychelles +SD Sudan +SE Sweden +SG Singapore +SH St Helena +SI Slovenia +SJ Svalbard & Jan Mayen +SK Slovakia +SL Sierra Leone +SM San Marino +SN Senegal +SO Somalia +SR Suriname +SS South Sudan +ST Sao Tome & Principe +SV El Salvador +SX St Maarten (Dutch) +SY Syria +SZ Eswatini (Swaziland) +TC Turks & Caicos Is +TD Chad +TF French S. Terr. +TG Togo +TH Thailand +TJ Tajikistan +TK Tokelau +TL East Timor +TM Turkmenistan +TN Tunisia +TO Tonga +TR Turkey +TT Trinidad & Tobago +TV Tuvalu +TW Taiwan +TZ Tanzania +UA Ukraine +UG Uganda +UM US minor outlying islands +US United States +UY Uruguay +UZ Uzbekistan +VA Vatican City +VC St Vincent +VE Venezuela +VG Virgin Islands (UK) +VI Virgin Islands (US) +VN Vietnam +VU Vanuatu +WF Wallis & Futuna +WS Samoa (western) +YE Yemen +YT Mayotte +ZA South Africa +ZM Zambia +ZW Zimbabwe diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/leapseconds b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/leapseconds new file mode 100644 index 0000000000000000000000000000000000000000..a6a170aa7028eab9b4e551ad68ce34a97d300092 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/leapseconds @@ -0,0 +1,82 @@ +# Allowance for leap seconds added to each time zone file. + +# This file is in the public domain. + +# This file is generated automatically from the data in the public-domain +# NIST format leap-seconds.list file, which can be copied from +# <ftp://ftp.nist.gov/pub/time/leap-seconds.list> +# or <ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list>. +# The NIST file is used instead of its IERS upstream counterpart +# <https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list> +# because under US law the NIST file is public domain +# whereas the IERS file's copyright and license status is unclear. +# For more about leap-seconds.list, please see +# The NTP Timescale and Leap Seconds +# <https://www.eecis.udel.edu/~mills/leap.html>. + +# The rules for leap seconds are specified in Annex 1 (Time scales) of: +# Standard-frequency and time-signal emissions. +# International Telecommunication Union - Radiocommunication Sector +# (ITU-R) Recommendation TF.460-6 (02/2002) +# <https://www.itu.int/rec/R-REC-TF.460-6-200202-I/>. +# The International Earth Rotation and Reference Systems Service (IERS) +# periodically uses leap seconds to keep UTC to within 0.9 s of UT1 +# (a proxy for Earth's angle in space as measured by astronomers) +# and publishes leap second data in a copyrighted file +# <https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat>. +# See: Levine J. Coordinated Universal Time and the leap second. +# URSI Radio Sci Bull. 2016;89(4):30-6. doi:10.23919/URSIRSB.2016.7909995 +# <https://ieeexplore.ieee.org/document/7909995>. + +# There were no leap seconds before 1972, as no official mechanism +# accounted for the discrepancy between atomic time (TAI) and the earth's +# rotation. The first ("1 Jan 1972") data line in leap-seconds.list +# does not denote a leap second; it denotes the start of the current definition +# of UTC. + +# All leap-seconds are Stationary (S) at the given UTC time. +# The correction (+ or -) is made at the given time, so in the unlikely +# event of a negative leap second, a line would look like this: +# Leap YEAR MON DAY 23:59:59 - S +# Typical lines look like this: +# Leap YEAR MON DAY 23:59:60 + S +Leap 1972 Jun 30 23:59:60 + S +Leap 1972 Dec 31 23:59:60 + S +Leap 1973 Dec 31 23:59:60 + S +Leap 1974 Dec 31 23:59:60 + S +Leap 1975 Dec 31 23:59:60 + S +Leap 1976 Dec 31 23:59:60 + S +Leap 1977 Dec 31 23:59:60 + S +Leap 1978 Dec 31 23:59:60 + S +Leap 1979 Dec 31 23:59:60 + S +Leap 1981 Jun 30 23:59:60 + S +Leap 1982 Jun 30 23:59:60 + S +Leap 1983 Jun 30 23:59:60 + S +Leap 1985 Jun 30 23:59:60 + S +Leap 1987 Dec 31 23:59:60 + S +Leap 1989 Dec 31 23:59:60 + S +Leap 1990 Dec 31 23:59:60 + S +Leap 1992 Jun 30 23:59:60 + S +Leap 1993 Jun 30 23:59:60 + S +Leap 1994 Jun 30 23:59:60 + S +Leap 1995 Dec 31 23:59:60 + S +Leap 1997 Jun 30 23:59:60 + S +Leap 1998 Dec 31 23:59:60 + S +Leap 2005 Dec 31 23:59:60 + S +Leap 2008 Dec 31 23:59:60 + S +Leap 2012 Jun 30 23:59:60 + S +Leap 2015 Jun 30 23:59:60 + S +Leap 2016 Dec 31 23:59:60 + S + +# UTC timestamp when this leap second list expires. +# Any additional leap seconds will come after this. +# This Expires line is commented out for now, +# so that pre-2020a zic implementations do not reject this file. +#Expires 2023 Dec 28 00:00:00 + +# POSIX timestamps for the data in this file: +#updated 1467936000 (2016-07-08 00:00:00 UTC) +#expires 1703721600 (2023-12-28 00:00:00 UTC) + +# Updated through IERS Bulletin C65 +# File expires on: 28 December 2023 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/tzdata.zi b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/tzdata.zi new file mode 100644 index 0000000000000000000000000000000000000000..7374f3ac1006f070b6d4d0e9fc3a5eb2377ab58d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/tzdata.zi @@ -0,0 +1,4287 @@ +# version unknown-dirty +# This zic input file is in the public domain. +R d 1916 o - Jun 14 23s 1 S +R d 1916 1919 - O Su>=1 23s 0 - +R d 1917 o - Mar 24 23s 1 S +R d 1918 o - Mar 9 23s 1 S +R d 1919 o - Mar 1 23s 1 S +R d 1920 o - F 14 23s 1 S +R d 1920 o - O 23 23s 0 - +R d 1921 o - Mar 14 23s 1 S +R d 1921 o - Jun 21 23s 0 - +R d 1939 o - S 11 23s 1 S +R d 1939 o - N 19 1 0 - +R d 1944 1945 - Ap M>=1 2 1 S +R d 1944 o - O 8 2 0 - +R d 1945 o - S 16 1 0 - +R d 1971 o - Ap 25 23s 1 S +R d 1971 o - S 26 23s 0 - +R d 1977 o - May 6 0 1 S +R d 1977 o - O 21 0 0 - +R d 1978 o - Mar 24 1 1 S +R d 1978 o - S 22 3 0 - +R d 1980 o - Ap 25 0 1 S +R d 1980 o - O 31 2 0 - +Z Africa/Algiers 0:12:12 - LMT 1891 Mar 16 +0:9:21 - PMT 1911 Mar 11 +0 d WE%sT 1940 F 25 2 +1 d CE%sT 1946 O 7 +0 - WET 1956 Ja 29 +1 - CET 1963 Ap 14 +0 d WE%sT 1977 O 21 +1 d CE%sT 1979 O 26 +0 d WE%sT 1981 May +1 - CET +Z Atlantic/Cape_Verde -1:34:4 - LMT 1912 Ja 1 2u +-2 - -02 1942 S +-2 1 -01 1945 O 15 +-2 - -02 1975 N 25 2 +-1 - -01 +Z Africa/Ndjamena 1:0:12 - LMT 1912 +1 - WAT 1979 O 14 +1 1 WAST 1980 Mar 8 +1 - WAT +Z Africa/Abidjan -0:16:8 - LMT 1912 +0 - GMT +R K 1940 o - Jul 15 0 1 S +R K 1940 o - O 1 0 0 - +R K 1941 o - Ap 15 0 1 S +R K 1941 o - S 16 0 0 - +R K 1942 1944 - Ap 1 0 1 S +R K 1942 o - O 27 0 0 - +R K 1943 1945 - N 1 0 0 - +R K 1945 o - Ap 16 0 1 S +R K 1957 o - May 10 0 1 S +R K 1957 1958 - O 1 0 0 - +R K 1958 o - May 1 0 1 S +R K 1959 1981 - May 1 1 1 S +R K 1959 1965 - S 30 3 0 - +R K 1966 1994 - O 1 3 0 - +R K 1982 o - Jul 25 1 1 S +R K 1983 o - Jul 12 1 1 S +R K 1984 1988 - May 1 1 1 S +R K 1989 o - May 6 1 1 S +R K 1990 1994 - May 1 1 1 S +R K 1995 2010 - Ap lastF 0s 1 S +R K 1995 2005 - S lastTh 24 0 - +R K 2006 o - S 21 24 0 - +R K 2007 o - S Th>=1 24 0 - +R K 2008 o - Au lastTh 24 0 - +R K 2009 o - Au 20 24 0 - +R K 2010 o - Au 10 24 0 - +R K 2010 o - S 9 24 1 S +R K 2010 o - S lastTh 24 0 - +R K 2014 o - May 15 24 1 S +R K 2014 o - Jun 26 24 0 - +R K 2014 o - Jul 31 24 1 S +R K 2014 o - S lastTh 24 0 - +R K 2023 ma - Ap lastF 0 1 S +R K 2023 ma - O lastTh 24 0 - +Z Africa/Cairo 2:5:9 - LMT 1900 O +2 K EE%sT +Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u +-1 - -01 1975 +0 - GMT +Z Africa/Nairobi 2:27:16 - LMT 1908 May +2:30 - +0230 1928 Jun 30 24 +3 - EAT 1930 Ja 4 24 +2:30 - +0230 1936 D 31 24 +2:45 - +0245 1942 Jul 31 24 +3 - EAT +Z Africa/Monrovia -0:43:8 - LMT 1882 +-0:43:8 - MMT 1919 Mar +-0:44:30 - MMT 1972 Ja 7 +0 - GMT +R L 1951 o - O 14 2 1 S +R L 1952 o - Ja 1 0 0 - +R L 1953 o - O 9 2 1 S +R L 1954 o - Ja 1 0 0 - +R L 1955 o - S 30 0 1 S +R L 1956 o - Ja 1 0 0 - +R L 1982 1984 - Ap 1 0 1 S +R L 1982 1985 - O 1 0 0 - +R L 1985 o - Ap 6 0 1 S +R L 1986 o - Ap 4 0 1 S +R L 1986 o - O 3 0 0 - +R L 1987 1989 - Ap 1 0 1 S +R L 1987 1989 - O 1 0 0 - +R L 1997 o - Ap 4 0 1 S +R L 1997 o - O 4 0 0 - +R L 2013 o - Mar lastF 1 1 S +R L 2013 o - O lastF 2 0 - +Z Africa/Tripoli 0:52:44 - LMT 1920 +1 L CE%sT 1959 +2 - EET 1982 +1 L CE%sT 1990 May 4 +2 - EET 1996 S 30 +1 L CE%sT 1997 O 4 +2 - EET 2012 N 10 2 +1 L CE%sT 2013 O 25 2 +2 - EET +R MU 1982 o - O 10 0 1 - +R MU 1983 o - Mar 21 0 0 - +R MU 2008 o - O lastSu 2 1 - +R MU 2009 o - Mar lastSu 2 0 - +Z Indian/Mauritius 3:50 - LMT 1907 +4 MU +04/+05 +R M 1939 o - S 12 0 1 - +R M 1939 o - N 19 0 0 - +R M 1940 o - F 25 0 1 - +R M 1945 o - N 18 0 0 - +R M 1950 o - Jun 11 0 1 - +R M 1950 o - O 29 0 0 - +R M 1967 o - Jun 3 12 1 - +R M 1967 o - O 1 0 0 - +R M 1974 o - Jun 24 0 1 - +R M 1974 o - S 1 0 0 - +R M 1976 1977 - May 1 0 1 - +R M 1976 o - Au 1 0 0 - +R M 1977 o - S 28 0 0 - +R M 1978 o - Jun 1 0 1 - +R M 1978 o - Au 4 0 0 - +R M 2008 o - Jun 1 0 1 - +R M 2008 o - S 1 0 0 - +R M 2009 o - Jun 1 0 1 - +R M 2009 o - Au 21 0 0 - +R M 2010 o - May 2 0 1 - +R M 2010 o - Au 8 0 0 - +R M 2011 o - Ap 3 0 1 - +R M 2011 o - Jul 31 0 0 - +R M 2012 2013 - Ap lastSu 2 1 - +R M 2012 o - Jul 20 3 0 - +R M 2012 o - Au 20 2 1 - +R M 2012 o - S 30 3 0 - +R M 2013 o - Jul 7 3 0 - +R M 2013 o - Au 10 2 1 - +R M 2013 2018 - O lastSu 3 0 - +R M 2014 2018 - Mar lastSu 2 1 - +R M 2014 o - Jun 28 3 0 - +R M 2014 o - Au 2 2 1 - +R M 2015 o - Jun 14 3 0 - +R M 2015 o - Jul 19 2 1 - +R M 2016 o - Jun 5 3 0 - +R M 2016 o - Jul 10 2 1 - +R M 2017 o - May 21 3 0 - +R M 2017 o - Jul 2 2 1 - +R M 2018 o - May 13 3 0 - +R M 2018 o - Jun 17 2 1 - +R M 2019 o - May 5 3 -1 - +R M 2019 o - Jun 9 2 0 - +R M 2020 o - Ap 19 3 -1 - +R M 2020 o - May 31 2 0 - +R M 2021 o - Ap 11 3 -1 - +R M 2021 o - May 16 2 0 - +R M 2022 o - Mar 27 3 -1 - +R M 2022 o - May 8 2 0 - +R M 2023 o - Mar 19 3 -1 - +R M 2023 o - Ap 23 2 0 - +R M 2024 o - Mar 10 3 -1 - +R M 2024 o - Ap 14 2 0 - +R M 2025 o - F 23 3 -1 - +R M 2025 o - Ap 6 2 0 - +R M 2026 o - F 15 3 -1 - +R M 2026 o - Mar 22 2 0 - +R M 2027 o - F 7 3 -1 - +R M 2027 o - Mar 14 2 0 - +R M 2028 o - Ja 23 3 -1 - +R M 2028 o - Mar 5 2 0 - +R M 2029 o - Ja 14 3 -1 - +R M 2029 o - F 18 2 0 - +R M 2029 o - D 30 3 -1 - +R M 2030 o - F 10 2 0 - +R M 2030 o - D 22 3 -1 - +R M 2031 o - Ja 26 2 0 - +R M 2031 o - D 14 3 -1 - +R M 2032 o - Ja 18 2 0 - +R M 2032 o - N 28 3 -1 - +R M 2033 o - Ja 9 2 0 - +R M 2033 o - N 20 3 -1 - +R M 2033 o - D 25 2 0 - +R M 2034 o - N 5 3 -1 - +R M 2034 o - D 17 2 0 - +R M 2035 o - O 28 3 -1 - +R M 2035 o - D 9 2 0 - +R M 2036 o - O 19 3 -1 - +R M 2036 o - N 23 2 0 - +R M 2037 o - O 4 3 -1 - +R M 2037 o - N 15 2 0 - +R M 2038 o - S 26 3 -1 - +R M 2038 o - O 31 2 0 - +R M 2039 o - S 18 3 -1 - +R M 2039 o - O 23 2 0 - +R M 2040 o - S 2 3 -1 - +R M 2040 o - O 14 2 0 - +R M 2041 o - Au 25 3 -1 - +R M 2041 o - S 29 2 0 - +R M 2042 o - Au 10 3 -1 - +R M 2042 o - S 21 2 0 - +R M 2043 o - Au 2 3 -1 - +R M 2043 o - S 13 2 0 - +R M 2044 o - Jul 24 3 -1 - +R M 2044 o - Au 28 2 0 - +R M 2045 o - Jul 9 3 -1 - +R M 2045 o - Au 20 2 0 - +R M 2046 o - Jul 1 3 -1 - +R M 2046 o - Au 5 2 0 - +R M 2047 o - Jun 23 3 -1 - +R M 2047 o - Jul 28 2 0 - +R M 2048 o - Jun 7 3 -1 - +R M 2048 o - Jul 19 2 0 - +R M 2049 o - May 30 3 -1 - +R M 2049 o - Jul 4 2 0 - +R M 2050 o - May 15 3 -1 - +R M 2050 o - Jun 26 2 0 - +R M 2051 o - May 7 3 -1 - +R M 2051 o - Jun 18 2 0 - +R M 2052 o - Ap 28 3 -1 - +R M 2052 o - Jun 2 2 0 - +R M 2053 o - Ap 13 3 -1 - +R M 2053 o - May 25 2 0 - +R M 2054 o - Ap 5 3 -1 - +R M 2054 o - May 10 2 0 - +R M 2055 o - Mar 28 3 -1 - +R M 2055 o - May 2 2 0 - +R M 2056 o - Mar 12 3 -1 - +R M 2056 o - Ap 23 2 0 - +R M 2057 o - Mar 4 3 -1 - +R M 2057 o - Ap 8 2 0 - +R M 2058 o - F 17 3 -1 - +R M 2058 o - Mar 31 2 0 - +R M 2059 o - F 9 3 -1 - +R M 2059 o - Mar 23 2 0 - +R M 2060 o - F 1 3 -1 - +R M 2060 o - Mar 7 2 0 - +R M 2061 o - Ja 16 3 -1 - +R M 2061 o - F 27 2 0 - +R M 2062 o - Ja 8 3 -1 - +R M 2062 o - F 12 2 0 - +R M 2062 o - D 31 3 -1 - +R M 2063 o - F 4 2 0 - +R M 2063 o - D 16 3 -1 - +R M 2064 o - Ja 27 2 0 - +R M 2064 o - D 7 3 -1 - +R M 2065 o - Ja 11 2 0 - +R M 2065 o - N 22 3 -1 - +R M 2066 o - Ja 3 2 0 - +R M 2066 o - N 14 3 -1 - +R M 2066 o - D 26 2 0 - +R M 2067 o - N 6 3 -1 - +R M 2067 o - D 11 2 0 - +R M 2068 o - O 21 3 -1 - +R M 2068 o - D 2 2 0 - +R M 2069 o - O 13 3 -1 - +R M 2069 o - N 17 2 0 - +R M 2070 o - O 5 3 -1 - +R M 2070 o - N 9 2 0 - +R M 2071 o - S 20 3 -1 - +R M 2071 o - N 1 2 0 - +R M 2072 o - S 11 3 -1 - +R M 2072 o - O 16 2 0 - +R M 2073 o - Au 27 3 -1 - +R M 2073 o - O 8 2 0 - +R M 2074 o - Au 19 3 -1 - +R M 2074 o - S 30 2 0 - +R M 2075 o - Au 11 3 -1 - +R M 2075 o - S 15 2 0 - +R M 2076 o - Jul 26 3 -1 - +R M 2076 o - S 6 2 0 - +R M 2077 o - Jul 18 3 -1 - +R M 2077 o - Au 22 2 0 - +R M 2078 o - Jul 10 3 -1 - +R M 2078 o - Au 14 2 0 - +R M 2079 o - Jun 25 3 -1 - +R M 2079 o - Au 6 2 0 - +R M 2080 o - Jun 16 3 -1 - +R M 2080 o - Jul 21 2 0 - +R M 2081 o - Jun 1 3 -1 - +R M 2081 o - Jul 13 2 0 - +R M 2082 o - May 24 3 -1 - +R M 2082 o - Jun 28 2 0 - +R M 2083 o - May 16 3 -1 - +R M 2083 o - Jun 20 2 0 - +R M 2084 o - Ap 30 3 -1 - +R M 2084 o - Jun 11 2 0 - +R M 2085 o - Ap 22 3 -1 - +R M 2085 o - May 27 2 0 - +R M 2086 o - Ap 14 3 -1 - +R M 2086 o - May 19 2 0 - +R M 2087 o - Mar 30 3 -1 - +R M 2087 o - May 11 2 0 - +Z Africa/Casablanca -0:30:20 - LMT 1913 O 26 +0 M +00/+01 1984 Mar 16 +1 - +01 1986 +0 M +00/+01 2018 O 28 3 +1 M +01/+00 +Z Africa/El_Aaiun -0:52:48 - LMT 1934 +-1 - -01 1976 Ap 14 +0 M +00/+01 2018 O 28 3 +1 M +01/+00 +Z Africa/Maputo 2:10:20 - LMT 1903 Mar +2 - CAT +R NA 1994 o - Mar 21 0 -1 WAT +R NA 1994 2017 - S Su>=1 2 0 CAT +R NA 1995 2017 - Ap Su>=1 2 -1 WAT +Z Africa/Windhoek 1:8:24 - LMT 1892 F 8 +1:30 - +0130 1903 Mar +2 - SAST 1942 S 20 2 +2 1 SAST 1943 Mar 21 2 +2 - SAST 1990 Mar 21 +2 NA %s +Z Africa/Lagos 0:13:35 - LMT 1905 Jul +0 - GMT 1908 Jul +0:13:35 - LMT 1914 +0:30 - +0030 1919 S +1 - WAT +Z Africa/Sao_Tome 0:26:56 - LMT 1884 +-0:36:45 - LMT 1912 Ja 1 0u +0 - GMT 2018 Ja 1 1 +1 - WAT 2019 Ja 1 2 +0 - GMT +R SA 1942 1943 - S Su>=15 2 1 - +R SA 1943 1944 - Mar Su>=15 2 0 - +Z Africa/Johannesburg 1:52 - LMT 1892 F 8 +1:30 - SAST 1903 Mar +2 SA SAST +R SD 1970 o - May 1 0 1 S +R SD 1970 1985 - O 15 0 0 - +R SD 1971 o - Ap 30 0 1 S +R SD 1972 1985 - Ap lastSu 0 1 S +Z Africa/Khartoum 2:10:8 - LMT 1931 +2 SD CA%sT 2000 Ja 15 12 +3 - EAT 2017 N +2 - CAT +Z Africa/Juba 2:6:28 - LMT 1931 +2 SD CA%sT 2000 Ja 15 12 +3 - EAT 2021 F +2 - CAT +R n 1939 o - Ap 15 23s 1 S +R n 1939 o - N 18 23s 0 - +R n 1940 o - F 25 23s 1 S +R n 1941 o - O 6 0 0 - +R n 1942 o - Mar 9 0 1 S +R n 1942 o - N 2 3 0 - +R n 1943 o - Mar 29 2 1 S +R n 1943 o - Ap 17 2 0 - +R n 1943 o - Ap 25 2 1 S +R n 1943 o - O 4 2 0 - +R n 1944 1945 - Ap M>=1 2 1 S +R n 1944 o - O 8 0 0 - +R n 1945 o - S 16 0 0 - +R n 1977 o - Ap 30 0s 1 S +R n 1977 o - S 24 0s 0 - +R n 1978 o - May 1 0s 1 S +R n 1978 o - O 1 0s 0 - +R n 1988 o - Jun 1 0s 1 S +R n 1988 1990 - S lastSu 0s 0 - +R n 1989 o - Mar 26 0s 1 S +R n 1990 o - May 1 0s 1 S +R n 2005 o - May 1 0s 1 S +R n 2005 o - S 30 1s 0 - +R n 2006 2008 - Mar lastSu 2s 1 S +R n 2006 2008 - O lastSu 2s 0 - +Z Africa/Tunis 0:40:44 - LMT 1881 May 12 +0:9:21 - PMT 1911 Mar 11 +1 n CE%sT +Z Antarctica/Casey 0 - -00 1969 +8 - +08 2009 O 18 2 +11 - +11 2010 Mar 5 2 +8 - +08 2011 O 28 2 +11 - +11 2012 F 21 17u +8 - +08 2016 O 22 +11 - +11 2018 Mar 11 4 +8 - +08 2018 O 7 4 +11 - +11 2019 Mar 17 3 +8 - +08 2019 O 4 3 +11 - +11 2020 Mar 8 3 +8 - +08 2020 O 4 0:1 +11 - +11 +Z Antarctica/Davis 0 - -00 1957 Ja 13 +7 - +07 1964 N +0 - -00 1969 F +7 - +07 2009 O 18 2 +5 - +05 2010 Mar 10 20u +7 - +07 2011 O 28 2 +5 - +05 2012 F 21 20u +7 - +07 +Z Antarctica/Mawson 0 - -00 1954 F 13 +6 - +06 2009 O 18 2 +5 - +05 +R Tr 2005 ma - Mar lastSu 1u 2 +02 +R Tr 2004 ma - O lastSu 1u 0 +00 +Z Antarctica/Troll 0 - -00 2005 F 12 +0 Tr %s +Z Antarctica/Rothera 0 - -00 1976 D +-3 - -03 +Z Asia/Kabul 4:36:48 - LMT 1890 +4 - +04 1945 +4:30 - +0430 +R AM 2011 o - Mar lastSu 2s 1 - +R AM 2011 o - O lastSu 2s 0 - +Z Asia/Yerevan 2:58 - LMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1995 S 24 2s +4 - +04 1997 +4 R +04/+05 2011 +4 AM +04/+05 +R AZ 1997 2015 - Mar lastSu 4 1 - +R AZ 1997 2015 - O lastSu 5 0 - +Z Asia/Baku 3:19:24 - LMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1992 S lastSu 2s +4 - +04 1996 +4 E +04/+05 1997 +4 AZ +04/+05 +R BD 2009 o - Jun 19 23 1 - +R BD 2009 o - D 31 24 0 - +Z Asia/Dhaka 6:1:40 - LMT 1890 +5:53:20 - HMT 1941 O +6:30 - +0630 1942 May 15 +5:30 - +0530 1942 S +6:30 - +0630 1951 S 30 +6 - +06 2009 +6 BD +06/+07 +Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 +5:30 - +0530 1987 O +6 - +06 +Z Indian/Chagos 4:49:40 - LMT 1907 +5 - +05 1996 +6 - +06 +Z Asia/Yangon 6:24:47 - LMT 1880 +6:24:47 - RMT 1920 +6:30 - +0630 1942 May +9 - +09 1945 May 3 +6:30 - +0630 +R Sh 1919 o - Ap 12 24 1 D +R Sh 1919 o - S 30 24 0 S +R Sh 1940 o - Jun 1 0 1 D +R Sh 1940 o - O 12 24 0 S +R Sh 1941 o - Mar 15 0 1 D +R Sh 1941 o - N 1 24 0 S +R Sh 1942 o - Ja 31 0 1 D +R Sh 1945 o - S 1 24 0 S +R Sh 1946 o - May 15 0 1 D +R Sh 1946 o - S 30 24 0 S +R Sh 1947 o - Ap 15 0 1 D +R Sh 1947 o - O 31 24 0 S +R Sh 1948 1949 - May 1 0 1 D +R Sh 1948 1949 - S 30 24 0 S +R CN 1986 o - May 4 2 1 D +R CN 1986 1991 - S Su>=11 2 0 S +R CN 1987 1991 - Ap Su>=11 2 1 D +Z Asia/Shanghai 8:5:43 - LMT 1901 +8 Sh C%sT 1949 May 28 +8 CN C%sT +Z Asia/Urumqi 5:50:20 - LMT 1928 +6 - +06 +R HK 1946 o - Ap 21 0 1 S +R HK 1946 o - D 1 3:30s 0 - +R HK 1947 o - Ap 13 3:30s 1 S +R HK 1947 o - N 30 3:30s 0 - +R HK 1948 o - May 2 3:30s 1 S +R HK 1948 1952 - O Su>=28 3:30s 0 - +R HK 1949 1953 - Ap Su>=1 3:30 1 S +R HK 1953 1964 - O Su>=31 3:30 0 - +R HK 1954 1964 - Mar Su>=18 3:30 1 S +R HK 1965 1976 - Ap Su>=16 3:30 1 S +R HK 1965 1976 - O Su>=16 3:30 0 - +R HK 1973 o - D 30 3:30 1 S +R HK 1979 o - May 13 3:30 1 S +R HK 1979 o - O 21 3:30 0 - +Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 29 17u +8 - HKT 1941 Jun 15 3 +8 1 HKST 1941 O 1 4 +8 0:30 HKWT 1941 D 25 +9 - JST 1945 N 18 2 +8 HK HK%sT +R f 1946 o - May 15 0 1 D +R f 1946 o - O 1 0 0 S +R f 1947 o - Ap 15 0 1 D +R f 1947 o - N 1 0 0 S +R f 1948 1951 - May 1 0 1 D +R f 1948 1951 - O 1 0 0 S +R f 1952 o - Mar 1 0 1 D +R f 1952 1954 - N 1 0 0 S +R f 1953 1959 - Ap 1 0 1 D +R f 1955 1961 - O 1 0 0 S +R f 1960 1961 - Jun 1 0 1 D +R f 1974 1975 - Ap 1 0 1 D +R f 1974 1975 - O 1 0 0 S +R f 1979 o - Jul 1 0 1 D +R f 1979 o - O 1 0 0 S +Z Asia/Taipei 8:6 - LMT 1896 +8 - CST 1937 O +9 - JST 1945 S 21 1 +8 f C%sT +R _ 1942 1943 - Ap 30 23 1 - +R _ 1942 o - N 17 23 0 - +R _ 1943 o - S 30 23 0 S +R _ 1946 o - Ap 30 23s 1 D +R _ 1946 o - S 30 23s 0 S +R _ 1947 o - Ap 19 23s 1 D +R _ 1947 o - N 30 23s 0 S +R _ 1948 o - May 2 23s 1 D +R _ 1948 o - O 31 23s 0 S +R _ 1949 1950 - Ap Sa>=1 23s 1 D +R _ 1949 1950 - O lastSa 23s 0 S +R _ 1951 o - Mar 31 23s 1 D +R _ 1951 o - O 28 23s 0 S +R _ 1952 1953 - Ap Sa>=1 23s 1 D +R _ 1952 o - N 1 23s 0 S +R _ 1953 1954 - O lastSa 23s 0 S +R _ 1954 1956 - Mar Sa>=17 23s 1 D +R _ 1955 o - N 5 23s 0 S +R _ 1956 1964 - N Su>=1 3:30 0 S +R _ 1957 1964 - Mar Su>=18 3:30 1 D +R _ 1965 1973 - Ap Su>=16 3:30 1 D +R _ 1965 1966 - O Su>=16 2:30 0 S +R _ 1967 1976 - O Su>=16 3:30 0 S +R _ 1973 o - D 30 3:30 1 D +R _ 1975 1976 - Ap Su>=16 3:30 1 D +R _ 1979 o - May 13 3:30 1 D +R _ 1979 o - O Su>=16 3:30 0 S +Z Asia/Macau 7:34:10 - LMT 1904 O 30 +8 - CST 1941 D 21 23 +9 _ +09/+10 1945 S 30 24 +8 _ C%sT +R CY 1975 o - Ap 13 0 1 S +R CY 1975 o - O 12 0 0 - +R CY 1976 o - May 15 0 1 S +R CY 1976 o - O 11 0 0 - +R CY 1977 1980 - Ap Su>=1 0 1 S +R CY 1977 o - S 25 0 0 - +R CY 1978 o - O 2 0 0 - +R CY 1979 1997 - S lastSu 0 0 - +R CY 1981 1998 - Mar lastSu 0 1 S +Z Asia/Nicosia 2:13:28 - LMT 1921 N 14 +2 CY EE%sT 1998 S +2 E EE%sT +Z Asia/Famagusta 2:15:48 - LMT 1921 N 14 +2 CY EE%sT 1998 S +2 E EE%sT 2016 S 8 +3 - +03 2017 O 29 1u +2 E EE%sT +Z Asia/Tbilisi 2:59:11 - LMT 1880 +2:59:11 - TBMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1992 +3 e +03/+04 1994 S lastSu +4 e +04/+05 1996 O lastSu +4 1 +05 1997 Mar lastSu +4 e +04/+05 2004 Jun 27 +3 R +03/+04 2005 Mar lastSu 2 +4 - +04 +Z Asia/Dili 8:22:20 - LMT 1912 +8 - +08 1942 F 21 23 +9 - +09 1976 May 3 +8 - +08 2000 S 17 +9 - +09 +Z Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 +5:53:20 - HMT 1870 +5:21:10 - MMT 1906 +5:30 - IST 1941 O +5:30 1 +0630 1942 May 15 +5:30 - IST 1942 S +5:30 1 +0630 1945 O 15 +5:30 - IST +Z Asia/Jakarta 7:7:12 - LMT 1867 Au 10 +7:7:12 - BMT 1923 D 31 16:40u +7:20 - +0720 1932 N +7:30 - +0730 1942 Mar 23 +9 - +09 1945 S 23 +7:30 - +0730 1948 May +8 - +08 1950 May +7:30 - +0730 1964 +7 - WIB +Z Asia/Pontianak 7:17:20 - LMT 1908 May +7:17:20 - PMT 1932 N +7:30 - +0730 1942 Ja 29 +9 - +09 1945 S 23 +7:30 - +0730 1948 May +8 - +08 1950 May +7:30 - +0730 1964 +8 - WITA 1988 +7 - WIB +Z Asia/Makassar 7:57:36 - LMT 1920 +7:57:36 - MMT 1932 N +8 - +08 1942 F 9 +9 - +09 1945 S 23 +8 - WITA +Z Asia/Jayapura 9:22:48 - LMT 1932 N +9 - +09 1944 S +9:30 - +0930 1964 +9 - WIT +R i 1910 o - Ja 1 0 0 - +R i 1977 o - Mar 21 23 1 - +R i 1977 o - O 20 24 0 - +R i 1978 o - Mar 24 24 1 - +R i 1978 o - Au 5 1 0 - +R i 1979 o - May 26 24 1 - +R i 1979 o - S 18 24 0 - +R i 1980 o - Mar 20 24 1 - +R i 1980 o - S 22 24 0 - +R i 1991 o - May 2 24 1 - +R i 1992 1995 - Mar 21 24 1 - +R i 1991 1995 - S 21 24 0 - +R i 1996 o - Mar 20 24 1 - +R i 1996 o - S 20 24 0 - +R i 1997 1999 - Mar 21 24 1 - +R i 1997 1999 - S 21 24 0 - +R i 2000 o - Mar 20 24 1 - +R i 2000 o - S 20 24 0 - +R i 2001 2003 - Mar 21 24 1 - +R i 2001 2003 - S 21 24 0 - +R i 2004 o - Mar 20 24 1 - +R i 2004 o - S 20 24 0 - +R i 2005 o - Mar 21 24 1 - +R i 2005 o - S 21 24 0 - +R i 2008 o - Mar 20 24 1 - +R i 2008 o - S 20 24 0 - +R i 2009 2011 - Mar 21 24 1 - +R i 2009 2011 - S 21 24 0 - +R i 2012 o - Mar 20 24 1 - +R i 2012 o - S 20 24 0 - +R i 2013 2015 - Mar 21 24 1 - +R i 2013 2015 - S 21 24 0 - +R i 2016 o - Mar 20 24 1 - +R i 2016 o - S 20 24 0 - +R i 2017 2019 - Mar 21 24 1 - +R i 2017 2019 - S 21 24 0 - +R i 2020 o - Mar 20 24 1 - +R i 2020 o - S 20 24 0 - +R i 2021 2022 - Mar 21 24 1 - +R i 2021 2022 - S 21 24 0 - +Z Asia/Tehran 3:25:44 - LMT 1916 +3:25:44 - TMT 1935 Jun 13 +3:30 i +0330/+0430 1977 O 20 24 +4 i +04/+05 1979 +3:30 i +0330/+0430 +R IQ 1982 o - May 1 0 1 - +R IQ 1982 1984 - O 1 0 0 - +R IQ 1983 o - Mar 31 0 1 - +R IQ 1984 1985 - Ap 1 0 1 - +R IQ 1985 1990 - S lastSu 1s 0 - +R IQ 1986 1990 - Mar lastSu 1s 1 - +R IQ 1991 2007 - Ap 1 3s 1 - +R IQ 1991 2007 - O 1 3s 0 - +Z Asia/Baghdad 2:57:40 - LMT 1890 +2:57:36 - BMT 1918 +3 - +03 1982 May +3 IQ +03/+04 +R Z 1940 o - May 31 24u 1 D +R Z 1940 o - S 30 24u 0 S +R Z 1940 o - N 16 24u 1 D +R Z 1942 1946 - O 31 24u 0 S +R Z 1943 1944 - Mar 31 24u 1 D +R Z 1945 1946 - Ap 15 24u 1 D +R Z 1948 o - May 22 24u 2 DD +R Z 1948 o - Au 31 24u 1 D +R Z 1948 1949 - O 31 24u 0 S +R Z 1949 o - Ap 30 24u 1 D +R Z 1950 o - Ap 15 24u 1 D +R Z 1950 o - S 14 24u 0 S +R Z 1951 o - Mar 31 24u 1 D +R Z 1951 o - N 10 24u 0 S +R Z 1952 o - Ap 19 24u 1 D +R Z 1952 o - O 18 24u 0 S +R Z 1953 o - Ap 11 24u 1 D +R Z 1953 o - S 12 24u 0 S +R Z 1954 o - Jun 12 24u 1 D +R Z 1954 o - S 11 24u 0 S +R Z 1955 o - Jun 11 24u 1 D +R Z 1955 o - S 10 24u 0 S +R Z 1956 o - Jun 2 24u 1 D +R Z 1956 o - S 29 24u 0 S +R Z 1957 o - Ap 27 24u 1 D +R Z 1957 o - S 21 24u 0 S +R Z 1974 o - Jul 6 24 1 D +R Z 1974 o - O 12 24 0 S +R Z 1975 o - Ap 19 24 1 D +R Z 1975 o - Au 30 24 0 S +R Z 1980 o - Au 2 24s 1 D +R Z 1980 o - S 13 24s 0 S +R Z 1984 o - May 5 24s 1 D +R Z 1984 o - Au 25 24s 0 S +R Z 1985 o - Ap 13 24 1 D +R Z 1985 o - Au 31 24 0 S +R Z 1986 o - May 17 24 1 D +R Z 1986 o - S 6 24 0 S +R Z 1987 o - Ap 14 24 1 D +R Z 1987 o - S 12 24 0 S +R Z 1988 o - Ap 9 24 1 D +R Z 1988 o - S 3 24 0 S +R Z 1989 o - Ap 29 24 1 D +R Z 1989 o - S 2 24 0 S +R Z 1990 o - Mar 24 24 1 D +R Z 1990 o - Au 25 24 0 S +R Z 1991 o - Mar 23 24 1 D +R Z 1991 o - Au 31 24 0 S +R Z 1992 o - Mar 28 24 1 D +R Z 1992 o - S 5 24 0 S +R Z 1993 o - Ap 2 0 1 D +R Z 1993 o - S 5 0 0 S +R Z 1994 o - Ap 1 0 1 D +R Z 1994 o - Au 28 0 0 S +R Z 1995 o - Mar 31 0 1 D +R Z 1995 o - S 3 0 0 S +R Z 1996 o - Mar 14 24 1 D +R Z 1996 o - S 15 24 0 S +R Z 1997 o - Mar 20 24 1 D +R Z 1997 o - S 13 24 0 S +R Z 1998 o - Mar 20 0 1 D +R Z 1998 o - S 6 0 0 S +R Z 1999 o - Ap 2 2 1 D +R Z 1999 o - S 3 2 0 S +R Z 2000 o - Ap 14 2 1 D +R Z 2000 o - O 6 1 0 S +R Z 2001 o - Ap 9 1 1 D +R Z 2001 o - S 24 1 0 S +R Z 2002 o - Mar 29 1 1 D +R Z 2002 o - O 7 1 0 S +R Z 2003 o - Mar 28 1 1 D +R Z 2003 o - O 3 1 0 S +R Z 2004 o - Ap 7 1 1 D +R Z 2004 o - S 22 1 0 S +R Z 2005 2012 - Ap F<=1 2 1 D +R Z 2005 o - O 9 2 0 S +R Z 2006 o - O 1 2 0 S +R Z 2007 o - S 16 2 0 S +R Z 2008 o - O 5 2 0 S +R Z 2009 o - S 27 2 0 S +R Z 2010 o - S 12 2 0 S +R Z 2011 o - O 2 2 0 S +R Z 2012 o - S 23 2 0 S +R Z 2013 ma - Mar F>=23 2 1 D +R Z 2013 ma - O lastSu 2 0 S +Z Asia/Jerusalem 2:20:54 - LMT 1880 +2:20:40 - JMT 1918 +2 Z I%sT +R JP 1948 o - May Sa>=1 24 1 D +R JP 1948 1951 - S Sa>=8 25 0 S +R JP 1949 o - Ap Sa>=1 24 1 D +R JP 1950 1951 - May Sa>=1 24 1 D +Z Asia/Tokyo 9:18:59 - LMT 1887 D 31 15u +9 JP J%sT +R J 1973 o - Jun 6 0 1 S +R J 1973 1975 - O 1 0 0 - +R J 1974 1977 - May 1 0 1 S +R J 1976 o - N 1 0 0 - +R J 1977 o - O 1 0 0 - +R J 1978 o - Ap 30 0 1 S +R J 1978 o - S 30 0 0 - +R J 1985 o - Ap 1 0 1 S +R J 1985 o - O 1 0 0 - +R J 1986 1988 - Ap F>=1 0 1 S +R J 1986 1990 - O F>=1 0 0 - +R J 1989 o - May 8 0 1 S +R J 1990 o - Ap 27 0 1 S +R J 1991 o - Ap 17 0 1 S +R J 1991 o - S 27 0 0 - +R J 1992 o - Ap 10 0 1 S +R J 1992 1993 - O F>=1 0 0 - +R J 1993 1998 - Ap F>=1 0 1 S +R J 1994 o - S F>=15 0 0 - +R J 1995 1998 - S F>=15 0s 0 - +R J 1999 o - Jul 1 0s 1 S +R J 1999 2002 - S lastF 0s 0 - +R J 2000 2001 - Mar lastTh 0s 1 S +R J 2002 2012 - Mar lastTh 24 1 S +R J 2003 o - O 24 0s 0 - +R J 2004 o - O 15 0s 0 - +R J 2005 o - S lastF 0s 0 - +R J 2006 2011 - O lastF 0s 0 - +R J 2013 o - D 20 0 0 - +R J 2014 2021 - Mar lastTh 24 1 S +R J 2014 2022 - O lastF 0s 0 - +R J 2022 o - F lastTh 24 1 S +Z Asia/Amman 2:23:44 - LMT 1931 +2 J EE%sT 2022 O 28 0s +3 - +03 +Z Asia/Almaty 5:7:48 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 2004 O 31 2s +6 - +06 +Z Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1991 S 29 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 1992 Mar 29 2s +5 R +05/+06 2004 O 31 2s +6 - +06 2018 D 21 +5 - +05 +Z Asia/Qostanay 4:14:28 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2004 O 31 2s +6 - +06 +Z Asia/Aqtobe 3:48:40 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2004 O 31 2s +5 - +05 +Z Asia/Aqtau 3:21:4 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1994 S 25 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +Z Asia/Atyrau 3:27:44 - LMT 1924 May 2 +3 - +03 1930 Jun 21 +5 - +05 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1999 Mar 28 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +Z Asia/Oral 3:25:24 - LMT 1924 May 2 +3 - +03 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1989 Mar 26 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1992 Mar 29 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +R KG 1992 1996 - Ap Su>=7 0s 1 - +R KG 1992 1996 - S lastSu 0 0 - +R KG 1997 2005 - Mar lastSu 2:30 1 - +R KG 1997 2004 - O lastSu 2:30 0 - +Z Asia/Bishkek 4:58:24 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1991 Au 31 2 +5 KG +05/+06 2005 Au 12 +6 - +06 +R KR 1948 o - Jun 1 0 1 D +R KR 1948 o - S 12 24 0 S +R KR 1949 o - Ap 3 0 1 D +R KR 1949 1951 - S Sa>=7 24 0 S +R KR 1950 o - Ap 1 0 1 D +R KR 1951 o - May 6 0 1 D +R KR 1955 o - May 5 0 1 D +R KR 1955 o - S 8 24 0 S +R KR 1956 o - May 20 0 1 D +R KR 1956 o - S 29 24 0 S +R KR 1957 1960 - May Su>=1 0 1 D +R KR 1957 1960 - S Sa>=17 24 0 S +R KR 1987 1988 - May Su>=8 2 1 D +R KR 1987 1988 - O Su>=8 3 0 S +Z Asia/Seoul 8:27:52 - LMT 1908 Ap +8:30 - KST 1912 +9 - JST 1945 S 8 +9 KR K%sT 1954 Mar 21 +8:30 KR K%sT 1961 Au 10 +9 KR K%sT +Z Asia/Pyongyang 8:23 - LMT 1908 Ap +8:30 - KST 1912 +9 - JST 1945 Au 24 +9 - KST 2015 Au 15 +8:30 - KST 2018 May 4 23:30 +9 - KST +R l 1920 o - Mar 28 0 1 S +R l 1920 o - O 25 0 0 - +R l 1921 o - Ap 3 0 1 S +R l 1921 o - O 3 0 0 - +R l 1922 o - Mar 26 0 1 S +R l 1922 o - O 8 0 0 - +R l 1923 o - Ap 22 0 1 S +R l 1923 o - S 16 0 0 - +R l 1957 1961 - May 1 0 1 S +R l 1957 1961 - O 1 0 0 - +R l 1972 o - Jun 22 0 1 S +R l 1972 1977 - O 1 0 0 - +R l 1973 1977 - May 1 0 1 S +R l 1978 o - Ap 30 0 1 S +R l 1978 o - S 30 0 0 - +R l 1984 1987 - May 1 0 1 S +R l 1984 1991 - O 16 0 0 - +R l 1988 o - Jun 1 0 1 S +R l 1989 o - May 10 0 1 S +R l 1990 1992 - May 1 0 1 S +R l 1992 o - O 4 0 0 - +R l 1993 2022 - Mar lastSu 0 1 S +R l 1993 1998 - S lastSu 0 0 - +R l 1999 ma - O lastSu 0 0 - +R l 2023 o - Ap 21 0 1 S +R l 2024 ma - Mar lastSu 0 1 S +Z Asia/Beirut 2:22 - LMT 1880 +2 l EE%sT +R NB 1935 1941 - S 14 0 0:20 - +R NB 1935 1941 - D 14 0 0 - +Z Asia/Kuching 7:21:20 - LMT 1926 Mar +7:30 - +0730 1933 +8 NB +08/+0820 1942 F 16 +9 - +09 1945 S 12 +8 - +08 +Z Indian/Maldives 4:54 - LMT 1880 +4:54 - MMT 1960 +5 - +05 +R X 1983 1984 - Ap 1 0 1 - +R X 1983 o - O 1 0 0 - +R X 1985 1998 - Mar lastSu 0 1 - +R X 1984 1998 - S lastSu 0 0 - +R X 2001 o - Ap lastSa 2 1 - +R X 2001 2006 - S lastSa 2 0 - +R X 2002 2006 - Mar lastSa 2 1 - +R X 2015 2016 - Mar lastSa 2 1 - +R X 2015 2016 - S lastSa 0 0 - +Z Asia/Hovd 6:6:36 - LMT 1905 Au +6 - +06 1978 +7 X +07/+08 +Z Asia/Ulaanbaatar 7:7:32 - LMT 1905 Au +7 - +07 1978 +8 X +08/+09 +Z Asia/Choibalsan 7:38 - LMT 1905 Au +7 - +07 1978 +8 - +08 1983 Ap +9 X +09/+10 2008 Mar 31 +8 X +08/+09 +Z Asia/Kathmandu 5:41:16 - LMT 1920 +5:30 - +0530 1986 +5:45 - +0545 +R PK 2002 o - Ap Su>=2 0 1 S +R PK 2002 o - O Su>=2 0 0 - +R PK 2008 o - Jun 1 0 1 S +R PK 2008 2009 - N 1 0 0 - +R PK 2009 o - Ap 15 0 1 S +Z Asia/Karachi 4:28:12 - LMT 1907 +5:30 - +0530 1942 S +5:30 1 +0630 1945 O 15 +5:30 - +0530 1951 S 30 +5 - +05 1971 Mar 26 +5 PK PK%sT +R P 1999 2005 - Ap F>=15 0 1 S +R P 1999 2003 - O F>=15 0 0 - +R P 2004 o - O 1 1 0 - +R P 2005 o - O 4 2 0 - +R P 2006 2007 - Ap 1 0 1 S +R P 2006 o - S 22 0 0 - +R P 2007 o - S 13 2 0 - +R P 2008 2009 - Mar lastF 0 1 S +R P 2008 o - S 1 0 0 - +R P 2009 o - S 4 1 0 - +R P 2010 o - Mar 26 0 1 S +R P 2010 o - Au 11 0 0 - +R P 2011 o - Ap 1 0:1 1 S +R P 2011 o - Au 1 0 0 - +R P 2011 o - Au 30 0 1 S +R P 2011 o - S 30 0 0 - +R P 2012 2014 - Mar lastTh 24 1 S +R P 2012 o - S 21 1 0 - +R P 2013 o - S 27 0 0 - +R P 2014 o - O 24 0 0 - +R P 2015 o - Mar 28 0 1 S +R P 2015 o - O 23 1 0 - +R P 2016 2018 - Mar Sa<=30 1 1 S +R P 2016 2018 - O Sa<=30 1 0 - +R P 2019 o - Mar 29 0 1 S +R P 2019 o - O Sa<=30 0 0 - +R P 2020 2021 - Mar Sa<=30 0 1 S +R P 2020 o - O 24 1 0 - +R P 2021 o - O 29 1 0 - +R P 2022 o - Mar 27 0 1 S +R P 2022 2035 - O Sa<=30 2 0 - +R P 2023 o - Ap 29 2 1 S +R P 2024 o - Ap 13 2 1 S +R P 2025 o - Ap 5 2 1 S +R P 2026 2054 - Mar Sa<=30 2 1 S +R P 2036 o - O 18 2 0 - +R P 2037 o - O 10 2 0 - +R P 2038 o - S 25 2 0 - +R P 2039 o - S 17 2 0 - +R P 2039 o - O 22 2 1 S +R P 2039 2067 - O Sa<=30 2 0 - +R P 2040 o - S 1 2 0 - +R P 2040 o - O 13 2 1 S +R P 2041 o - Au 24 2 0 - +R P 2041 o - S 28 2 1 S +R P 2042 o - Au 16 2 0 - +R P 2042 o - S 20 2 1 S +R P 2043 o - Au 1 2 0 - +R P 2043 o - S 12 2 1 S +R P 2044 o - Jul 23 2 0 - +R P 2044 o - Au 27 2 1 S +R P 2045 o - Jul 15 2 0 - +R P 2045 o - Au 19 2 1 S +R P 2046 o - Jun 30 2 0 - +R P 2046 o - Au 11 2 1 S +R P 2047 o - Jun 22 2 0 - +R P 2047 o - Jul 27 2 1 S +R P 2048 o - Jun 6 2 0 - +R P 2048 o - Jul 18 2 1 S +R P 2049 o - May 29 2 0 - +R P 2049 o - Jul 3 2 1 S +R P 2050 o - May 21 2 0 - +R P 2050 o - Jun 25 2 1 S +R P 2051 o - May 6 2 0 - +R P 2051 o - Jun 17 2 1 S +R P 2052 o - Ap 27 2 0 - +R P 2052 o - Jun 1 2 1 S +R P 2053 o - Ap 12 2 0 - +R P 2053 o - May 24 2 1 S +R P 2054 o - Ap 4 2 0 - +R P 2054 o - May 16 2 1 S +R P 2055 o - May 1 2 1 S +R P 2056 o - Ap 22 2 1 S +R P 2057 o - Ap 7 2 1 S +R P 2058 ma - Mar Sa<=30 2 1 S +R P 2068 o - O 20 2 0 - +R P 2069 o - O 12 2 0 - +R P 2070 o - O 4 2 0 - +R P 2071 o - S 19 2 0 - +R P 2072 o - S 10 2 0 - +R P 2072 o - O 15 2 1 S +R P 2073 o - S 2 2 0 - +R P 2073 o - O 7 2 1 S +R P 2074 o - Au 18 2 0 - +R P 2074 o - S 29 2 1 S +R P 2075 o - Au 10 2 0 - +R P 2075 o - S 14 2 1 S +R P 2075 ma - O Sa<=30 2 0 - +R P 2076 o - Jul 25 2 0 - +R P 2076 o - S 5 2 1 S +R P 2077 o - Jul 17 2 0 - +R P 2077 o - Au 28 2 1 S +R P 2078 o - Jul 9 2 0 - +R P 2078 o - Au 13 2 1 S +R P 2079 o - Jun 24 2 0 - +R P 2079 o - Au 5 2 1 S +R P 2080 o - Jun 15 2 0 - +R P 2080 o - Jul 20 2 1 S +R P 2081 o - Jun 7 2 0 - +R P 2081 o - Jul 12 2 1 S +R P 2082 o - May 23 2 0 - +R P 2082 o - Jul 4 2 1 S +R P 2083 o - May 15 2 0 - +R P 2083 o - Jun 19 2 1 S +R P 2084 o - Ap 29 2 0 - +R P 2084 o - Jun 10 2 1 S +R P 2085 o - Ap 21 2 0 - +R P 2085 o - Jun 2 2 1 S +R P 2086 o - Ap 13 2 0 - +R P 2086 o - May 18 2 1 S +Z Asia/Gaza 2:17:52 - LMT 1900 O +2 Z EET/EEST 1948 May 15 +2 K EE%sT 1967 Jun 5 +2 Z I%sT 1996 +2 J EE%sT 1999 +2 P EE%sT 2008 Au 29 +2 - EET 2008 S +2 P EE%sT 2010 +2 - EET 2010 Mar 27 0:1 +2 P EE%sT 2011 Au +2 - EET 2012 +2 P EE%sT +Z Asia/Hebron 2:20:23 - LMT 1900 O +2 Z EET/EEST 1948 May 15 +2 K EE%sT 1967 Jun 5 +2 Z I%sT 1996 +2 J EE%sT 1999 +2 P EE%sT +R PH 1936 o - N 1 0 1 D +R PH 1937 o - F 1 0 0 S +R PH 1954 o - Ap 12 0 1 D +R PH 1954 o - Jul 1 0 0 S +R PH 1978 o - Mar 22 0 1 D +R PH 1978 o - S 21 0 0 S +Z Asia/Manila -15:56 - LMT 1844 D 31 +8:4 - LMT 1899 May 11 +8 PH P%sT 1942 May +9 - JST 1944 N +8 PH P%sT +Z Asia/Qatar 3:26:8 - LMT 1920 +4 - +04 1972 Jun +3 - +03 +Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 +3 - +03 +Z Asia/Singapore 6:55:25 - LMT 1901 +6:55:25 - SMT 1905 Jun +7 - +07 1933 +7 0:20 +0720 1936 +7:20 - +0720 1941 S +7:30 - +0730 1942 F 16 +9 - +09 1945 S 12 +7:30 - +0730 1981 D 31 16u +8 - +08 +Z Asia/Colombo 5:19:24 - LMT 1880 +5:19:32 - MMT 1906 +5:30 - +0530 1942 Ja 5 +5:30 0:30 +06 1942 S +5:30 1 +0630 1945 O 16 2 +5:30 - +0530 1996 May 25 +6:30 - +0630 1996 O 26 0:30 +6 - +06 2006 Ap 15 0:30 +5:30 - +0530 +R S 1920 1923 - Ap Su>=15 2 1 S +R S 1920 1923 - O Su>=1 2 0 - +R S 1962 o - Ap 29 2 1 S +R S 1962 o - O 1 2 0 - +R S 1963 1965 - May 1 2 1 S +R S 1963 o - S 30 2 0 - +R S 1964 o - O 1 2 0 - +R S 1965 o - S 30 2 0 - +R S 1966 o - Ap 24 2 1 S +R S 1966 1976 - O 1 2 0 - +R S 1967 1978 - May 1 2 1 S +R S 1977 1978 - S 1 2 0 - +R S 1983 1984 - Ap 9 2 1 S +R S 1983 1984 - O 1 2 0 - +R S 1986 o - F 16 2 1 S +R S 1986 o - O 9 2 0 - +R S 1987 o - Mar 1 2 1 S +R S 1987 1988 - O 31 2 0 - +R S 1988 o - Mar 15 2 1 S +R S 1989 o - Mar 31 2 1 S +R S 1989 o - O 1 2 0 - +R S 1990 o - Ap 1 2 1 S +R S 1990 o - S 30 2 0 - +R S 1991 o - Ap 1 0 1 S +R S 1991 1992 - O 1 0 0 - +R S 1992 o - Ap 8 0 1 S +R S 1993 o - Mar 26 0 1 S +R S 1993 o - S 25 0 0 - +R S 1994 1996 - Ap 1 0 1 S +R S 1994 2005 - O 1 0 0 - +R S 1997 1998 - Mar lastM 0 1 S +R S 1999 2006 - Ap 1 0 1 S +R S 2006 o - S 22 0 0 - +R S 2007 o - Mar lastF 0 1 S +R S 2007 o - N F>=1 0 0 - +R S 2008 o - Ap F>=1 0 1 S +R S 2008 o - N 1 0 0 - +R S 2009 o - Mar lastF 0 1 S +R S 2010 2011 - Ap F>=1 0 1 S +R S 2012 2022 - Mar lastF 0 1 S +R S 2009 2022 - O lastF 0 0 - +Z Asia/Damascus 2:25:12 - LMT 1920 +2 S EE%sT 2022 O 28 +3 - +03 +Z Asia/Dushanbe 4:35:12 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 1 +06 1991 S 9 2s +5 - +05 +Z Asia/Bangkok 6:42:4 - LMT 1880 +6:42:4 - BMT 1920 Ap +7 - +07 +Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 R +05/+06 1991 Mar 31 2 +4 R +04/+05 1992 Ja 19 2 +5 - +05 +Z Asia/Dubai 3:41:12 - LMT 1920 +4 - +04 +Z Asia/Samarkand 4:27:53 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1992 +5 - +05 +Z Asia/Tashkent 4:37:11 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2 +5 R +05/+06 1992 +5 - +05 +Z Asia/Ho_Chi_Minh 7:6:30 - LMT 1906 Jul +7:6:30 - PLMT 1911 May +7 - +07 1942 D 31 23 +8 - +08 1945 Mar 14 23 +9 - +09 1945 S 2 +7 - +07 1947 Ap +8 - +08 1955 Jul +7 - +07 1959 D 31 23 +8 - +08 1975 Jun 13 +7 - +07 +R AU 1917 o - Ja 1 2s 1 D +R AU 1917 o - Mar lastSu 2s 0 S +R AU 1942 o - Ja 1 2s 1 D +R AU 1942 o - Mar lastSu 2s 0 S +R AU 1942 o - S 27 2s 1 D +R AU 1943 1944 - Mar lastSu 2s 0 S +R AU 1943 o - O 3 2s 1 D +Z Australia/Darwin 8:43:20 - LMT 1895 F +9 - ACST 1899 May +9:30 AU AC%sT +R AW 1974 o - O lastSu 2s 1 D +R AW 1975 o - Mar Su>=1 2s 0 S +R AW 1983 o - O lastSu 2s 1 D +R AW 1984 o - Mar Su>=1 2s 0 S +R AW 1991 o - N 17 2s 1 D +R AW 1992 o - Mar Su>=1 2s 0 S +R AW 2006 o - D 3 2s 1 D +R AW 2007 2009 - Mar lastSu 2s 0 S +R AW 2007 2008 - O lastSu 2s 1 D +Z Australia/Perth 7:43:24 - LMT 1895 D +8 AU AW%sT 1943 Jul +8 AW AW%sT +Z Australia/Eucla 8:35:28 - LMT 1895 D +8:45 AU +0845/+0945 1943 Jul +8:45 AW +0845/+0945 +R AQ 1971 o - O lastSu 2s 1 D +R AQ 1972 o - F lastSu 2s 0 S +R AQ 1989 1991 - O lastSu 2s 1 D +R AQ 1990 1992 - Mar Su>=1 2s 0 S +R Ho 1992 1993 - O lastSu 2s 1 D +R Ho 1993 1994 - Mar Su>=1 2s 0 S +Z Australia/Brisbane 10:12:8 - LMT 1895 +10 AU AE%sT 1971 +10 AQ AE%sT +Z Australia/Lindeman 9:55:56 - LMT 1895 +10 AU AE%sT 1971 +10 AQ AE%sT 1992 Jul +10 Ho AE%sT +R AS 1971 1985 - O lastSu 2s 1 D +R AS 1986 o - O 19 2s 1 D +R AS 1987 2007 - O lastSu 2s 1 D +R AS 1972 o - F 27 2s 0 S +R AS 1973 1985 - Mar Su>=1 2s 0 S +R AS 1986 1990 - Mar Su>=15 2s 0 S +R AS 1991 o - Mar 3 2s 0 S +R AS 1992 o - Mar 22 2s 0 S +R AS 1993 o - Mar 7 2s 0 S +R AS 1994 o - Mar 20 2s 0 S +R AS 1995 2005 - Mar lastSu 2s 0 S +R AS 2006 o - Ap 2 2s 0 S +R AS 2007 o - Mar lastSu 2s 0 S +R AS 2008 ma - Ap Su>=1 2s 0 S +R AS 2008 ma - O Su>=1 2s 1 D +Z Australia/Adelaide 9:14:20 - LMT 1895 F +9 - ACST 1899 May +9:30 AU AC%sT 1971 +9:30 AS AC%sT +R AT 1916 o - O Su>=1 2s 1 D +R AT 1917 o - Mar lastSu 2s 0 S +R AT 1917 1918 - O Su>=22 2s 1 D +R AT 1918 1919 - Mar Su>=1 2s 0 S +R AT 1967 o - O Su>=1 2s 1 D +R AT 1968 o - Mar Su>=29 2s 0 S +R AT 1968 1985 - O lastSu 2s 1 D +R AT 1969 1971 - Mar Su>=8 2s 0 S +R AT 1972 o - F lastSu 2s 0 S +R AT 1973 1981 - Mar Su>=1 2s 0 S +R AT 1982 1983 - Mar lastSu 2s 0 S +R AT 1984 1986 - Mar Su>=1 2s 0 S +R AT 1986 o - O Su>=15 2s 1 D +R AT 1987 1990 - Mar Su>=15 2s 0 S +R AT 1987 o - O Su>=22 2s 1 D +R AT 1988 1990 - O lastSu 2s 1 D +R AT 1991 1999 - O Su>=1 2s 1 D +R AT 1991 2005 - Mar lastSu 2s 0 S +R AT 2000 o - Au lastSu 2s 1 D +R AT 2001 ma - O Su>=1 2s 1 D +R AT 2006 o - Ap Su>=1 2s 0 S +R AT 2007 o - Mar lastSu 2s 0 S +R AT 2008 ma - Ap Su>=1 2s 0 S +Z Australia/Hobart 9:49:16 - LMT 1895 S +10 AT AE%sT 1919 O 24 +10 AU AE%sT 1967 +10 AT AE%sT +R AV 1971 1985 - O lastSu 2s 1 D +R AV 1972 o - F lastSu 2s 0 S +R AV 1973 1985 - Mar Su>=1 2s 0 S +R AV 1986 1990 - Mar Su>=15 2s 0 S +R AV 1986 1987 - O Su>=15 2s 1 D +R AV 1988 1999 - O lastSu 2s 1 D +R AV 1991 1994 - Mar Su>=1 2s 0 S +R AV 1995 2005 - Mar lastSu 2s 0 S +R AV 2000 o - Au lastSu 2s 1 D +R AV 2001 2007 - O lastSu 2s 1 D +R AV 2006 o - Ap Su>=1 2s 0 S +R AV 2007 o - Mar lastSu 2s 0 S +R AV 2008 ma - Ap Su>=1 2s 0 S +R AV 2008 ma - O Su>=1 2s 1 D +Z Australia/Melbourne 9:39:52 - LMT 1895 F +10 AU AE%sT 1971 +10 AV AE%sT +R AN 1971 1985 - O lastSu 2s 1 D +R AN 1972 o - F 27 2s 0 S +R AN 1973 1981 - Mar Su>=1 2s 0 S +R AN 1982 o - Ap Su>=1 2s 0 S +R AN 1983 1985 - Mar Su>=1 2s 0 S +R AN 1986 1989 - Mar Su>=15 2s 0 S +R AN 1986 o - O 19 2s 1 D +R AN 1987 1999 - O lastSu 2s 1 D +R AN 1990 1995 - Mar Su>=1 2s 0 S +R AN 1996 2005 - Mar lastSu 2s 0 S +R AN 2000 o - Au lastSu 2s 1 D +R AN 2001 2007 - O lastSu 2s 1 D +R AN 2006 o - Ap Su>=1 2s 0 S +R AN 2007 o - Mar lastSu 2s 0 S +R AN 2008 ma - Ap Su>=1 2s 0 S +R AN 2008 ma - O Su>=1 2s 1 D +Z Australia/Sydney 10:4:52 - LMT 1895 F +10 AU AE%sT 1971 +10 AN AE%sT +Z Australia/Broken_Hill 9:25:48 - LMT 1895 F +10 - AEST 1896 Au 23 +9 - ACST 1899 May +9:30 AU AC%sT 1971 +9:30 AN AC%sT 2000 +9:30 AS AC%sT +R LH 1981 1984 - O lastSu 2 1 - +R LH 1982 1985 - Mar Su>=1 2 0 - +R LH 1985 o - O lastSu 2 0:30 - +R LH 1986 1989 - Mar Su>=15 2 0 - +R LH 1986 o - O 19 2 0:30 - +R LH 1987 1999 - O lastSu 2 0:30 - +R LH 1990 1995 - Mar Su>=1 2 0 - +R LH 1996 2005 - Mar lastSu 2 0 - +R LH 2000 o - Au lastSu 2 0:30 - +R LH 2001 2007 - O lastSu 2 0:30 - +R LH 2006 o - Ap Su>=1 2 0 - +R LH 2007 o - Mar lastSu 2 0 - +R LH 2008 ma - Ap Su>=1 2 0 - +R LH 2008 ma - O Su>=1 2 0:30 - +Z Australia/Lord_Howe 10:36:20 - LMT 1895 F +10 - AEST 1981 Mar +10:30 LH +1030/+1130 1985 Jul +10:30 LH +1030/+11 +Z Antarctica/Macquarie 0 - -00 1899 N +10 - AEST 1916 O 1 2 +10 1 AEDT 1917 F +10 AU AE%sT 1919 Ap 1 0s +0 - -00 1948 Mar 25 +10 AU AE%sT 1967 +10 AT AE%sT 2010 +10 1 AEDT 2011 +10 AT AE%sT +R FJ 1998 1999 - N Su>=1 2 1 - +R FJ 1999 2000 - F lastSu 3 0 - +R FJ 2009 o - N 29 2 1 - +R FJ 2010 o - Mar lastSu 3 0 - +R FJ 2010 2013 - O Su>=21 2 1 - +R FJ 2011 o - Mar Su>=1 3 0 - +R FJ 2012 2013 - Ja Su>=18 3 0 - +R FJ 2014 o - Ja Su>=18 2 0 - +R FJ 2014 2018 - N Su>=1 2 1 - +R FJ 2015 2021 - Ja Su>=12 3 0 - +R FJ 2019 o - N Su>=8 2 1 - +R FJ 2020 o - D 20 2 1 - +Z Pacific/Fiji 11:55:44 - LMT 1915 O 26 +12 FJ +12/+13 +Z Pacific/Gambier -8:59:48 - LMT 1912 O +-9 - -09 +Z Pacific/Marquesas -9:18 - LMT 1912 O +-9:30 - -0930 +Z Pacific/Tahiti -9:58:16 - LMT 1912 O +-10 - -10 +R Gu 1959 o - Jun 27 2 1 D +R Gu 1961 o - Ja 29 2 0 S +R Gu 1967 o - S 1 2 1 D +R Gu 1969 o - Ja 26 0:1 0 S +R Gu 1969 o - Jun 22 2 1 D +R Gu 1969 o - Au 31 2 0 S +R Gu 1970 1971 - Ap lastSu 2 1 D +R Gu 1970 1971 - S Su>=1 2 0 S +R Gu 1973 o - D 16 2 1 D +R Gu 1974 o - F 24 2 0 S +R Gu 1976 o - May 26 2 1 D +R Gu 1976 o - Au 22 2:1 0 S +R Gu 1977 o - Ap 24 2 1 D +R Gu 1977 o - Au 28 2 0 S +Z Pacific/Guam -14:21 - LMT 1844 D 31 +9:39 - LMT 1901 +10 - GST 1941 D 10 +9 - +09 1944 Jul 31 +10 Gu G%sT 2000 D 23 +10 - ChST +Z Pacific/Tarawa 11:32:4 - LMT 1901 +12 - +12 +Z Pacific/Kanton 0 - -00 1937 Au 31 +-12 - -12 1979 O +-11 - -11 1994 D 31 +13 - +13 +Z Pacific/Kiritimati -10:29:20 - LMT 1901 +-10:40 - -1040 1979 O +-10 - -10 1994 D 31 +14 - +14 +Z Pacific/Kwajalein 11:9:20 - LMT 1901 +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1944 F 6 +11 - +11 1969 O +-12 - -12 1993 Au 20 24 +12 - +12 +Z Pacific/Kosrae -13:8:4 - LMT 1844 D 31 +10:51:56 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1945 Au +11 - +11 1969 O +12 - +12 1999 +11 - +11 +Z Pacific/Nauru 11:7:40 - LMT 1921 Ja 15 +11:30 - +1130 1942 Au 29 +9 - +09 1945 S 8 +11:30 - +1130 1979 F 10 2 +12 - +12 +R NC 1977 1978 - D Su>=1 0 1 - +R NC 1978 1979 - F 27 0 0 - +R NC 1996 o - D 1 2s 1 - +R NC 1997 o - Mar 2 2s 0 - +Z Pacific/Noumea 11:5:48 - LMT 1912 Ja 13 +11 NC +11/+12 +R NZ 1927 o - N 6 2 1 S +R NZ 1928 o - Mar 4 2 0 M +R NZ 1928 1933 - O Su>=8 2 0:30 S +R NZ 1929 1933 - Mar Su>=15 2 0 M +R NZ 1934 1940 - Ap lastSu 2 0 M +R NZ 1934 1940 - S lastSu 2 0:30 S +R NZ 1946 o - Ja 1 0 0 S +R NZ 1974 o - N Su>=1 2s 1 D +R k 1974 o - N Su>=1 2:45s 1 - +R NZ 1975 o - F lastSu 2s 0 S +R k 1975 o - F lastSu 2:45s 0 - +R NZ 1975 1988 - O lastSu 2s 1 D +R k 1975 1988 - O lastSu 2:45s 1 - +R NZ 1976 1989 - Mar Su>=1 2s 0 S +R k 1976 1989 - Mar Su>=1 2:45s 0 - +R NZ 1989 o - O Su>=8 2s 1 D +R k 1989 o - O Su>=8 2:45s 1 - +R NZ 1990 2006 - O Su>=1 2s 1 D +R k 1990 2006 - O Su>=1 2:45s 1 - +R NZ 1990 2007 - Mar Su>=15 2s 0 S +R k 1990 2007 - Mar Su>=15 2:45s 0 - +R NZ 2007 ma - S lastSu 2s 1 D +R k 2007 ma - S lastSu 2:45s 1 - +R NZ 2008 ma - Ap Su>=1 2s 0 S +R k 2008 ma - Ap Su>=1 2:45s 0 - +Z Pacific/Auckland 11:39:4 - LMT 1868 N 2 +11:30 NZ NZ%sT 1946 +12 NZ NZ%sT +Z Pacific/Chatham 12:13:48 - LMT 1868 N 2 +12:15 - +1215 1946 +12:45 k +1245/+1345 +R CK 1978 o - N 12 0 0:30 - +R CK 1979 1991 - Mar Su>=1 0 0 - +R CK 1979 1990 - O lastSu 0 0:30 - +Z Pacific/Rarotonga 13:20:56 - LMT 1899 D 26 +-10:39:4 - LMT 1952 O 16 +-10:30 - -1030 1978 N 12 +-10 CK -10/-0930 +Z Pacific/Niue -11:19:40 - LMT 1952 O 16 +-11:20 - -1120 1964 Jul +-11 - -11 +Z Pacific/Norfolk 11:11:52 - LMT 1901 +11:12 - +1112 1951 +11:30 - +1130 1974 O 27 2s +11:30 1 +1230 1975 Mar 2 2s +11:30 - +1130 2015 O 4 2s +11 - +11 2019 Jul +11 AN +11/+12 +Z Pacific/Palau -15:2:4 - LMT 1844 D 31 +8:57:56 - LMT 1901 +9 - +09 +Z Pacific/Port_Moresby 9:48:40 - LMT 1880 +9:48:32 - PMMT 1895 +10 - +10 +Z Pacific/Bougainville 10:22:16 - LMT 1880 +9:48:32 - PMMT 1895 +10 - +10 1942 Jul +9 - +09 1945 Au 21 +10 - +10 2014 D 28 2 +11 - +11 +Z Pacific/Pitcairn -8:40:20 - LMT 1901 +-8:30 - -0830 1998 Ap 27 +-8 - -08 +Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 +-11:22:48 - LMT 1911 +-11 - SST +R WS 2010 o - S lastSu 0 1 - +R WS 2011 o - Ap Sa>=1 4 0 - +R WS 2011 o - S lastSa 3 1 - +R WS 2012 2021 - Ap Su>=1 4 0 - +R WS 2012 2020 - S lastSu 3 1 - +Z Pacific/Apia 12:33:4 - LMT 1892 Jul 5 +-11:26:56 - LMT 1911 +-11:30 - -1130 1950 +-11 WS -11/-10 2011 D 29 24 +13 WS +13/+14 +Z Pacific/Guadalcanal 10:39:48 - LMT 1912 O +11 - +11 +Z Pacific/Fakaofo -11:24:56 - LMT 1901 +-11 - -11 2011 D 30 +13 - +13 +R TO 1999 o - O 7 2s 1 - +R TO 2000 o - Mar 19 2s 0 - +R TO 2000 2001 - N Su>=1 2 1 - +R TO 2001 2002 - Ja lastSu 2 0 - +R TO 2016 o - N Su>=1 2 1 - +R TO 2017 o - Ja Su>=15 3 0 - +Z Pacific/Tongatapu 12:19:12 - LMT 1945 S 10 +12:20 - +1220 1961 +13 - +13 1999 +13 TO +13/+14 +R VU 1973 o - D 22 12u 1 - +R VU 1974 o - Mar 30 12u 0 - +R VU 1983 1991 - S Sa>=22 24 1 - +R VU 1984 1991 - Mar Sa>=22 24 0 - +R VU 1992 1993 - Ja Sa>=22 24 0 - +R VU 1992 o - O Sa>=22 24 1 - +Z Pacific/Efate 11:13:16 - LMT 1912 Ja 13 +11 VU +11/+12 +R G 1916 o - May 21 2s 1 BST +R G 1916 o - O 1 2s 0 GMT +R G 1917 o - Ap 8 2s 1 BST +R G 1917 o - S 17 2s 0 GMT +R G 1918 o - Mar 24 2s 1 BST +R G 1918 o - S 30 2s 0 GMT +R G 1919 o - Mar 30 2s 1 BST +R G 1919 o - S 29 2s 0 GMT +R G 1920 o - Mar 28 2s 1 BST +R G 1920 o - O 25 2s 0 GMT +R G 1921 o - Ap 3 2s 1 BST +R G 1921 o - O 3 2s 0 GMT +R G 1922 o - Mar 26 2s 1 BST +R G 1922 o - O 8 2s 0 GMT +R G 1923 o - Ap Su>=16 2s 1 BST +R G 1923 1924 - S Su>=16 2s 0 GMT +R G 1924 o - Ap Su>=9 2s 1 BST +R G 1925 1926 - Ap Su>=16 2s 1 BST +R G 1925 1938 - O Su>=2 2s 0 GMT +R G 1927 o - Ap Su>=9 2s 1 BST +R G 1928 1929 - Ap Su>=16 2s 1 BST +R G 1930 o - Ap Su>=9 2s 1 BST +R G 1931 1932 - Ap Su>=16 2s 1 BST +R G 1933 o - Ap Su>=9 2s 1 BST +R G 1934 o - Ap Su>=16 2s 1 BST +R G 1935 o - Ap Su>=9 2s 1 BST +R G 1936 1937 - Ap Su>=16 2s 1 BST +R G 1938 o - Ap Su>=9 2s 1 BST +R G 1939 o - Ap Su>=16 2s 1 BST +R G 1939 o - N Su>=16 2s 0 GMT +R G 1940 o - F Su>=23 2s 1 BST +R G 1941 o - May Su>=2 1s 2 BDST +R G 1941 1943 - Au Su>=9 1s 1 BST +R G 1942 1944 - Ap Su>=2 1s 2 BDST +R G 1944 o - S Su>=16 1s 1 BST +R G 1945 o - Ap M>=2 1s 2 BDST +R G 1945 o - Jul Su>=9 1s 1 BST +R G 1945 1946 - O Su>=2 2s 0 GMT +R G 1946 o - Ap Su>=9 2s 1 BST +R G 1947 o - Mar 16 2s 1 BST +R G 1947 o - Ap 13 1s 2 BDST +R G 1947 o - Au 10 1s 1 BST +R G 1947 o - N 2 2s 0 GMT +R G 1948 o - Mar 14 2s 1 BST +R G 1948 o - O 31 2s 0 GMT +R G 1949 o - Ap 3 2s 1 BST +R G 1949 o - O 30 2s 0 GMT +R G 1950 1952 - Ap Su>=14 2s 1 BST +R G 1950 1952 - O Su>=21 2s 0 GMT +R G 1953 o - Ap Su>=16 2s 1 BST +R G 1953 1960 - O Su>=2 2s 0 GMT +R G 1954 o - Ap Su>=9 2s 1 BST +R G 1955 1956 - Ap Su>=16 2s 1 BST +R G 1957 o - Ap Su>=9 2s 1 BST +R G 1958 1959 - Ap Su>=16 2s 1 BST +R G 1960 o - Ap Su>=9 2s 1 BST +R G 1961 1963 - Mar lastSu 2s 1 BST +R G 1961 1968 - O Su>=23 2s 0 GMT +R G 1964 1967 - Mar Su>=19 2s 1 BST +R G 1968 o - F 18 2s 1 BST +R G 1972 1980 - Mar Su>=16 2s 1 BST +R G 1972 1980 - O Su>=23 2s 0 GMT +R G 1981 1995 - Mar lastSu 1u 1 BST +R G 1981 1989 - O Su>=23 1u 0 GMT +R G 1990 1995 - O Su>=22 1u 0 GMT +Z Europe/London -0:1:15 - LMT 1847 D +0 G %s 1968 O 27 +1 - BST 1971 O 31 2u +0 G %s 1996 +0 E GMT/BST +R IE 1971 o - O 31 2u -1 - +R IE 1972 1980 - Mar Su>=16 2u 0 - +R IE 1972 1980 - O Su>=23 2u -1 - +R IE 1981 ma - Mar lastSu 1u 0 - +R IE 1981 1989 - O Su>=23 1u -1 - +R IE 1990 1995 - O Su>=22 1u -1 - +R IE 1996 ma - O lastSu 1u -1 - +Z Europe/Dublin -0:25:21 - LMT 1880 Au 2 +-0:25:21 - DMT 1916 May 21 2s +-0:25:21 1 IST 1916 O 1 2s +0 G %s 1921 D 6 +0 G GMT/IST 1940 F 25 2s +0 1 IST 1946 O 6 2s +0 - GMT 1947 Mar 16 2s +0 1 IST 1947 N 2 2s +0 - GMT 1948 Ap 18 2s +0 G GMT/IST 1968 O 27 +1 IE IST/GMT +R E 1977 1980 - Ap Su>=1 1u 1 S +R E 1977 o - S lastSu 1u 0 - +R E 1978 o - O 1 1u 0 - +R E 1979 1995 - S lastSu 1u 0 - +R E 1981 ma - Mar lastSu 1u 1 S +R E 1996 ma - O lastSu 1u 0 - +R W- 1977 1980 - Ap Su>=1 1s 1 S +R W- 1977 o - S lastSu 1s 0 - +R W- 1978 o - O 1 1s 0 - +R W- 1979 1995 - S lastSu 1s 0 - +R W- 1981 ma - Mar lastSu 1s 1 S +R W- 1996 ma - O lastSu 1s 0 - +R c 1916 o - Ap 30 23 1 S +R c 1916 o - O 1 1 0 - +R c 1917 1918 - Ap M>=15 2s 1 S +R c 1917 1918 - S M>=15 2s 0 - +R c 1940 o - Ap 1 2s 1 S +R c 1942 o - N 2 2s 0 - +R c 1943 o - Mar 29 2s 1 S +R c 1943 o - O 4 2s 0 - +R c 1944 1945 - Ap M>=1 2s 1 S +R c 1944 o - O 2 2s 0 - +R c 1945 o - S 16 2s 0 - +R c 1977 1980 - Ap Su>=1 2s 1 S +R c 1977 o - S lastSu 2s 0 - +R c 1978 o - O 1 2s 0 - +R c 1979 1995 - S lastSu 2s 0 - +R c 1981 ma - Mar lastSu 2s 1 S +R c 1996 ma - O lastSu 2s 0 - +R e 1977 1980 - Ap Su>=1 0 1 S +R e 1977 o - S lastSu 0 0 - +R e 1978 o - O 1 0 0 - +R e 1979 1995 - S lastSu 0 0 - +R e 1981 ma - Mar lastSu 0 1 S +R e 1996 ma - O lastSu 0 0 - +R R 1917 o - Jul 1 23 1 MST +R R 1917 o - D 28 0 0 MMT +R R 1918 o - May 31 22 2 MDST +R R 1918 o - S 16 1 1 MST +R R 1919 o - May 31 23 2 MDST +R R 1919 o - Jul 1 0u 1 MSD +R R 1919 o - Au 16 0 0 MSK +R R 1921 o - F 14 23 1 MSD +R R 1921 o - Mar 20 23 2 +05 +R R 1921 o - S 1 0 1 MSD +R R 1921 o - O 1 0 0 - +R R 1981 1984 - Ap 1 0 1 S +R R 1981 1983 - O 1 0 0 - +R R 1984 1995 - S lastSu 2s 0 - +R R 1985 2010 - Mar lastSu 2s 1 S +R R 1996 2010 - O lastSu 2s 0 - +Z WET 0 E WE%sT +Z CET 1 c CE%sT +Z MET 1 c ME%sT +Z EET 2 E EE%sT +R q 1940 o - Jun 16 0 1 S +R q 1942 o - N 2 3 0 - +R q 1943 o - Mar 29 2 1 S +R q 1943 o - Ap 10 3 0 - +R q 1974 o - May 4 0 1 S +R q 1974 o - O 2 0 0 - +R q 1975 o - May 1 0 1 S +R q 1975 o - O 2 0 0 - +R q 1976 o - May 2 0 1 S +R q 1976 o - O 3 0 0 - +R q 1977 o - May 8 0 1 S +R q 1977 o - O 2 0 0 - +R q 1978 o - May 6 0 1 S +R q 1978 o - O 1 0 0 - +R q 1979 o - May 5 0 1 S +R q 1979 o - S 30 0 0 - +R q 1980 o - May 3 0 1 S +R q 1980 o - O 4 0 0 - +R q 1981 o - Ap 26 0 1 S +R q 1981 o - S 27 0 0 - +R q 1982 o - May 2 0 1 S +R q 1982 o - O 3 0 0 - +R q 1983 o - Ap 18 0 1 S +R q 1983 o - O 1 0 0 - +R q 1984 o - Ap 1 0 1 S +Z Europe/Tirane 1:19:20 - LMT 1914 +1 - CET 1940 Jun 16 +1 q CE%sT 1984 Jul +1 E CE%sT +Z Europe/Andorra 0:6:4 - LMT 1901 +0 - WET 1946 S 30 +1 - CET 1985 Mar 31 2 +1 E CE%sT +R a 1920 o - Ap 5 2s 1 S +R a 1920 o - S 13 2s 0 - +R a 1946 o - Ap 14 2s 1 S +R a 1946 o - O 7 2s 0 - +R a 1947 1948 - O Su>=1 2s 0 - +R a 1947 o - Ap 6 2s 1 S +R a 1948 o - Ap 18 2s 1 S +R a 1980 o - Ap 6 0 1 S +R a 1980 o - S 28 0 0 - +Z Europe/Vienna 1:5:21 - LMT 1893 Ap +1 c CE%sT 1920 +1 a CE%sT 1940 Ap 1 2s +1 c CE%sT 1945 Ap 2 2s +1 1 CEST 1945 Ap 12 2s +1 - CET 1946 +1 a CE%sT 1981 +1 E CE%sT +Z Europe/Minsk 1:50:16 - LMT 1880 +1:50 - MMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 Jun 28 +1 c CE%sT 1944 Jul 3 +3 R MSK/MSD 1990 +3 - MSK 1991 Mar 31 2s +2 R EE%sT 2011 Mar 27 2s +3 - +03 +R b 1918 o - Mar 9 0s 1 S +R b 1918 1919 - O Sa>=1 23s 0 - +R b 1919 o - Mar 1 23s 1 S +R b 1920 o - F 14 23s 1 S +R b 1920 o - O 23 23s 0 - +R b 1921 o - Mar 14 23s 1 S +R b 1921 o - O 25 23s 0 - +R b 1922 o - Mar 25 23s 1 S +R b 1922 1927 - O Sa>=1 23s 0 - +R b 1923 o - Ap 21 23s 1 S +R b 1924 o - Mar 29 23s 1 S +R b 1925 o - Ap 4 23s 1 S +R b 1926 o - Ap 17 23s 1 S +R b 1927 o - Ap 9 23s 1 S +R b 1928 o - Ap 14 23s 1 S +R b 1928 1938 - O Su>=2 2s 0 - +R b 1929 o - Ap 21 2s 1 S +R b 1930 o - Ap 13 2s 1 S +R b 1931 o - Ap 19 2s 1 S +R b 1932 o - Ap 3 2s 1 S +R b 1933 o - Mar 26 2s 1 S +R b 1934 o - Ap 8 2s 1 S +R b 1935 o - Mar 31 2s 1 S +R b 1936 o - Ap 19 2s 1 S +R b 1937 o - Ap 4 2s 1 S +R b 1938 o - Mar 27 2s 1 S +R b 1939 o - Ap 16 2s 1 S +R b 1939 o - N 19 2s 0 - +R b 1940 o - F 25 2s 1 S +R b 1944 o - S 17 2s 0 - +R b 1945 o - Ap 2 2s 1 S +R b 1945 o - S 16 2s 0 - +R b 1946 o - May 19 2s 1 S +R b 1946 o - O 7 2s 0 - +Z Europe/Brussels 0:17:30 - LMT 1880 +0:17:30 - BMT 1892 May 1 0:17:30 +0 - WET 1914 N 8 +1 - CET 1916 May +1 c CE%sT 1918 N 11 11u +0 b WE%sT 1940 May 20 2s +1 c CE%sT 1944 S 3 +1 b CE%sT 1977 +1 E CE%sT +R BG 1979 o - Mar 31 23 1 S +R BG 1979 o - O 1 1 0 - +R BG 1980 1982 - Ap Sa>=1 23 1 S +R BG 1980 o - S 29 1 0 - +R BG 1981 o - S 27 2 0 - +Z Europe/Sofia 1:33:16 - LMT 1880 +1:56:56 - IMT 1894 N 30 +2 - EET 1942 N 2 3 +1 c CE%sT 1945 +1 - CET 1945 Ap 2 3 +2 - EET 1979 Mar 31 23 +2 BG EE%sT 1982 S 26 3 +2 c EE%sT 1991 +2 e EE%sT 1997 +2 E EE%sT +R CZ 1945 o - Ap M>=1 2s 1 S +R CZ 1945 o - O 1 2s 0 - +R CZ 1946 o - May 6 2s 1 S +R CZ 1946 1949 - O Su>=1 2s 0 - +R CZ 1947 1948 - Ap Su>=15 2s 1 S +R CZ 1949 o - Ap 9 2s 1 S +Z Europe/Prague 0:57:44 - LMT 1850 +0:57:44 - PMT 1891 O +1 c CE%sT 1945 May 9 +1 CZ CE%sT 1946 D 1 3 +1 -1 GMT 1947 F 23 2 +1 CZ CE%sT 1979 +1 E CE%sT +Z Atlantic/Faroe -0:27:4 - LMT 1908 Ja 11 +0 - WET 1981 +0 E WE%sT +R Th 1991 1992 - Mar lastSu 2 1 D +R Th 1991 1992 - S lastSu 2 0 S +R Th 1993 2006 - Ap Su>=1 2 1 D +R Th 1993 2006 - O lastSu 2 0 S +R Th 2007 ma - Mar Su>=8 2 1 D +R Th 2007 ma - N Su>=1 2 0 S +Z America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 +-3 - -03 1980 Ap 6 2 +-3 E -03/-02 1996 +0 - GMT +Z America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 +-2 - -02 1980 Ap 6 2 +-2 c -02/-01 1981 Mar 29 +-1 E -01/+00 +Z America/Nuuk -3:26:56 - LMT 1916 Jul 28 +-3 - -03 1980 Ap 6 2 +-3 E -03/-02 2023 O 29 1u +-2 E -02/-01 +Z America/Thule -4:35:8 - LMT 1916 Jul 28 +-4 Th A%sT +Z Europe/Tallinn 1:39 - LMT 1880 +1:39 - TMT 1918 F +1 c CE%sT 1919 Jul +1:39 - TMT 1921 May +2 - EET 1940 Au 6 +3 - MSK 1941 S 15 +1 c CE%sT 1944 S 22 +3 R MSK/MSD 1989 Mar 26 2s +2 1 EEST 1989 S 24 2s +2 c EE%sT 1998 S 22 +2 E EE%sT 1999 O 31 4 +2 - EET 2002 F 21 +2 E EE%sT +R FI 1942 o - Ap 2 24 1 S +R FI 1942 o - O 4 1 0 - +R FI 1981 1982 - Mar lastSu 2 1 S +R FI 1981 1982 - S lastSu 3 0 - +Z Europe/Helsinki 1:39:49 - LMT 1878 May 31 +1:39:49 - HMT 1921 May +2 FI EE%sT 1983 +2 E EE%sT +R F 1916 o - Jun 14 23s 1 S +R F 1916 1919 - O Su>=1 23s 0 - +R F 1917 o - Mar 24 23s 1 S +R F 1918 o - Mar 9 23s 1 S +R F 1919 o - Mar 1 23s 1 S +R F 1920 o - F 14 23s 1 S +R F 1920 o - O 23 23s 0 - +R F 1921 o - Mar 14 23s 1 S +R F 1921 o - O 25 23s 0 - +R F 1922 o - Mar 25 23s 1 S +R F 1922 1938 - O Sa>=1 23s 0 - +R F 1923 o - May 26 23s 1 S +R F 1924 o - Mar 29 23s 1 S +R F 1925 o - Ap 4 23s 1 S +R F 1926 o - Ap 17 23s 1 S +R F 1927 o - Ap 9 23s 1 S +R F 1928 o - Ap 14 23s 1 S +R F 1929 o - Ap 20 23s 1 S +R F 1930 o - Ap 12 23s 1 S +R F 1931 o - Ap 18 23s 1 S +R F 1932 o - Ap 2 23s 1 S +R F 1933 o - Mar 25 23s 1 S +R F 1934 o - Ap 7 23s 1 S +R F 1935 o - Mar 30 23s 1 S +R F 1936 o - Ap 18 23s 1 S +R F 1937 o - Ap 3 23s 1 S +R F 1938 o - Mar 26 23s 1 S +R F 1939 o - Ap 15 23s 1 S +R F 1939 o - N 18 23s 0 - +R F 1940 o - F 25 2 1 S +R F 1941 o - May 5 0 2 M +R F 1941 o - O 6 0 1 S +R F 1942 o - Mar 9 0 2 M +R F 1942 o - N 2 3 1 S +R F 1943 o - Mar 29 2 2 M +R F 1943 o - O 4 3 1 S +R F 1944 o - Ap 3 2 2 M +R F 1944 o - O 8 1 1 S +R F 1945 o - Ap 2 2 2 M +R F 1945 o - S 16 3 0 - +R F 1976 o - Mar 28 1 1 S +R F 1976 o - S 26 1 0 - +Z Europe/Paris 0:9:21 - LMT 1891 Mar 16 +0:9:21 - PMT 1911 Mar 11 +0 F WE%sT 1940 Jun 14 23 +1 c CE%sT 1944 Au 25 +0 F WE%sT 1945 S 16 3 +1 F CE%sT 1977 +1 E CE%sT +R DE 1946 o - Ap 14 2s 1 S +R DE 1946 o - O 7 2s 0 - +R DE 1947 1949 - O Su>=1 2s 0 - +R DE 1947 o - Ap 6 3s 1 S +R DE 1947 o - May 11 2s 2 M +R DE 1947 o - Jun 29 3 1 S +R DE 1948 o - Ap 18 2s 1 S +R DE 1949 o - Ap 10 2s 1 S +R So 1945 o - May 24 2 2 M +R So 1945 o - S 24 3 1 S +R So 1945 o - N 18 2s 0 - +Z Europe/Berlin 0:53:28 - LMT 1893 Ap +1 c CE%sT 1945 May 24 2 +1 So CE%sT 1946 +1 DE CE%sT 1980 +1 E CE%sT +Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 +0 G %s 1957 Ap 14 2 +1 - CET 1982 +1 E CE%sT +R g 1932 o - Jul 7 0 1 S +R g 1932 o - S 1 0 0 - +R g 1941 o - Ap 7 0 1 S +R g 1942 o - N 2 3 0 - +R g 1943 o - Mar 30 0 1 S +R g 1943 o - O 4 0 0 - +R g 1952 o - Jul 1 0 1 S +R g 1952 o - N 2 0 0 - +R g 1975 o - Ap 12 0s 1 S +R g 1975 o - N 26 0s 0 - +R g 1976 o - Ap 11 2s 1 S +R g 1976 o - O 10 2s 0 - +R g 1977 1978 - Ap Su>=1 2s 1 S +R g 1977 o - S 26 2s 0 - +R g 1978 o - S 24 4 0 - +R g 1979 o - Ap 1 9 1 S +R g 1979 o - S 29 2 0 - +R g 1980 o - Ap 1 0 1 S +R g 1980 o - S 28 0 0 - +Z Europe/Athens 1:34:52 - LMT 1895 S 14 +1:34:52 - AMT 1916 Jul 28 0:1 +2 g EE%sT 1941 Ap 30 +1 g CE%sT 1944 Ap 4 +2 g EE%sT 1981 +2 E EE%sT +R h 1918 1919 - Ap 15 2 1 S +R h 1918 1920 - S M>=15 3 0 - +R h 1920 o - Ap 5 2 1 S +R h 1945 o - May 1 23 1 S +R h 1945 o - N 1 1 0 - +R h 1946 o - Mar 31 2s 1 S +R h 1946 o - O 7 2 0 - +R h 1947 1949 - Ap Su>=4 2s 1 S +R h 1947 1949 - O Su>=1 2s 0 - +R h 1954 o - May 23 0 1 S +R h 1954 o - O 3 0 0 - +R h 1955 o - May 22 2 1 S +R h 1955 o - O 2 3 0 - +R h 1956 1957 - Jun Su>=1 2 1 S +R h 1956 1957 - S lastSu 3 0 - +R h 1980 o - Ap 6 0 1 S +R h 1980 o - S 28 1 0 - +R h 1981 1983 - Mar lastSu 0 1 S +R h 1981 1983 - S lastSu 1 0 - +Z Europe/Budapest 1:16:20 - LMT 1890 N +1 c CE%sT 1918 +1 h CE%sT 1941 Ap 7 23 +1 c CE%sT 1945 +1 h CE%sT 1984 +1 E CE%sT +R I 1916 o - Jun 3 24 1 S +R I 1916 1917 - S 30 24 0 - +R I 1917 o - Mar 31 24 1 S +R I 1918 o - Mar 9 24 1 S +R I 1918 o - O 6 24 0 - +R I 1919 o - Mar 1 24 1 S +R I 1919 o - O 4 24 0 - +R I 1920 o - Mar 20 24 1 S +R I 1920 o - S 18 24 0 - +R I 1940 o - Jun 14 24 1 S +R I 1942 o - N 2 2s 0 - +R I 1943 o - Mar 29 2s 1 S +R I 1943 o - O 4 2s 0 - +R I 1944 o - Ap 2 2s 1 S +R I 1944 o - S 17 2s 0 - +R I 1945 o - Ap 2 2 1 S +R I 1945 o - S 15 1 0 - +R I 1946 o - Mar 17 2s 1 S +R I 1946 o - O 6 2s 0 - +R I 1947 o - Mar 16 0s 1 S +R I 1947 o - O 5 0s 0 - +R I 1948 o - F 29 2s 1 S +R I 1948 o - O 3 2s 0 - +R I 1966 1968 - May Su>=22 0s 1 S +R I 1966 o - S 24 24 0 - +R I 1967 1969 - S Su>=22 0s 0 - +R I 1969 o - Jun 1 0s 1 S +R I 1970 o - May 31 0s 1 S +R I 1970 o - S lastSu 0s 0 - +R I 1971 1972 - May Su>=22 0s 1 S +R I 1971 o - S lastSu 0s 0 - +R I 1972 o - O 1 0s 0 - +R I 1973 o - Jun 3 0s 1 S +R I 1973 1974 - S lastSu 0s 0 - +R I 1974 o - May 26 0s 1 S +R I 1975 o - Jun 1 0s 1 S +R I 1975 1977 - S lastSu 0s 0 - +R I 1976 o - May 30 0s 1 S +R I 1977 1979 - May Su>=22 0s 1 S +R I 1978 o - O 1 0s 0 - +R I 1979 o - S 30 0s 0 - +Z Europe/Rome 0:49:56 - LMT 1866 D 12 +0:49:56 - RMT 1893 O 31 23u +1 I CE%sT 1943 S 10 +1 c CE%sT 1944 Jun 4 +1 I CE%sT 1980 +1 E CE%sT +R LV 1989 1996 - Mar lastSu 2s 1 S +R LV 1989 1996 - S lastSu 2s 0 - +Z Europe/Riga 1:36:34 - LMT 1880 +1:36:34 - RMT 1918 Ap 15 2 +1:36:34 1 LST 1918 S 16 3 +1:36:34 - RMT 1919 Ap 1 2 +1:36:34 1 LST 1919 May 22 3 +1:36:34 - RMT 1926 May 11 +2 - EET 1940 Au 5 +3 - MSK 1941 Jul +1 c CE%sT 1944 O 13 +3 R MSK/MSD 1989 Mar lastSu 2s +2 1 EEST 1989 S lastSu 2s +2 LV EE%sT 1997 Ja 21 +2 E EE%sT 2000 F 29 +2 - EET 2001 Ja 2 +2 E EE%sT +Z Europe/Vilnius 1:41:16 - LMT 1880 +1:24 - WMT 1917 +1:35:36 - KMT 1919 O 10 +1 - CET 1920 Jul 12 +2 - EET 1920 O 9 +1 - CET 1940 Au 3 +3 - MSK 1941 Jun 24 +1 c CE%sT 1944 Au +3 R MSK/MSD 1989 Mar 26 2s +2 R EE%sT 1991 S 29 2s +2 c EE%sT 1998 +2 - EET 1998 Mar 29 1u +1 E CE%sT 1999 O 31 1u +2 - EET 2003 +2 E EE%sT +R MT 1973 o - Mar 31 0s 1 S +R MT 1973 o - S 29 0s 0 - +R MT 1974 o - Ap 21 0s 1 S +R MT 1974 o - S 16 0s 0 - +R MT 1975 1979 - Ap Su>=15 2 1 S +R MT 1975 1980 - S Su>=15 2 0 - +R MT 1980 o - Mar 31 2 1 S +Z Europe/Malta 0:58:4 - LMT 1893 N 2 +1 I CE%sT 1973 Mar 31 +1 MT CE%sT 1981 +1 E CE%sT +R MD 1997 ma - Mar lastSu 2 1 S +R MD 1997 ma - O lastSu 3 0 - +Z Europe/Chisinau 1:55:20 - LMT 1880 +1:55 - CMT 1918 F 15 +1:44:24 - BMT 1931 Jul 24 +2 z EE%sT 1940 Au 15 +2 1 EEST 1941 Jul 17 +1 c CE%sT 1944 Au 24 +3 R MSK/MSD 1990 May 6 2 +2 R EE%sT 1992 +2 e EE%sT 1997 +2 MD EE%sT +R O 1918 1919 - S 16 2s 0 - +R O 1919 o - Ap 15 2s 1 S +R O 1944 o - Ap 3 2s 1 S +R O 1944 o - O 4 2 0 - +R O 1945 o - Ap 29 0 1 S +R O 1945 o - N 1 0 0 - +R O 1946 o - Ap 14 0s 1 S +R O 1946 o - O 7 2s 0 - +R O 1947 o - May 4 2s 1 S +R O 1947 1949 - O Su>=1 2s 0 - +R O 1948 o - Ap 18 2s 1 S +R O 1949 o - Ap 10 2s 1 S +R O 1957 o - Jun 2 1s 1 S +R O 1957 1958 - S lastSu 1s 0 - +R O 1958 o - Mar 30 1s 1 S +R O 1959 o - May 31 1s 1 S +R O 1959 1961 - O Su>=1 1s 0 - +R O 1960 o - Ap 3 1s 1 S +R O 1961 1964 - May lastSu 1s 1 S +R O 1962 1964 - S lastSu 1s 0 - +Z Europe/Warsaw 1:24 - LMT 1880 +1:24 - WMT 1915 Au 5 +1 c CE%sT 1918 S 16 3 +2 O EE%sT 1922 Jun +1 O CE%sT 1940 Jun 23 2 +1 c CE%sT 1944 O +1 O CE%sT 1977 +1 W- CE%sT 1988 +1 E CE%sT +R p 1916 o - Jun 17 23 1 S +R p 1916 o - N 1 1 0 - +R p 1917 o - F 28 23s 1 S +R p 1917 1921 - O 14 23s 0 - +R p 1918 o - Mar 1 23s 1 S +R p 1919 o - F 28 23s 1 S +R p 1920 o - F 29 23s 1 S +R p 1921 o - F 28 23s 1 S +R p 1924 o - Ap 16 23s 1 S +R p 1924 o - O 14 23s 0 - +R p 1926 o - Ap 17 23s 1 S +R p 1926 1929 - O Sa>=1 23s 0 - +R p 1927 o - Ap 9 23s 1 S +R p 1928 o - Ap 14 23s 1 S +R p 1929 o - Ap 20 23s 1 S +R p 1931 o - Ap 18 23s 1 S +R p 1931 1932 - O Sa>=1 23s 0 - +R p 1932 o - Ap 2 23s 1 S +R p 1934 o - Ap 7 23s 1 S +R p 1934 1938 - O Sa>=1 23s 0 - +R p 1935 o - Mar 30 23s 1 S +R p 1936 o - Ap 18 23s 1 S +R p 1937 o - Ap 3 23s 1 S +R p 1938 o - Mar 26 23s 1 S +R p 1939 o - Ap 15 23s 1 S +R p 1939 o - N 18 23s 0 - +R p 1940 o - F 24 23s 1 S +R p 1940 1941 - O 5 23s 0 - +R p 1941 o - Ap 5 23s 1 S +R p 1942 1945 - Mar Sa>=8 23s 1 S +R p 1942 o - Ap 25 22s 2 M +R p 1942 o - Au 15 22s 1 S +R p 1942 1945 - O Sa>=24 23s 0 - +R p 1943 o - Ap 17 22s 2 M +R p 1943 1945 - Au Sa>=25 22s 1 S +R p 1944 1945 - Ap Sa>=21 22s 2 M +R p 1946 o - Ap Sa>=1 23s 1 S +R p 1946 o - O Sa>=1 23s 0 - +R p 1947 1965 - Ap Su>=1 2s 1 S +R p 1947 1965 - O Su>=1 2s 0 - +R p 1977 o - Mar 27 0s 1 S +R p 1977 o - S 25 0s 0 - +R p 1978 1979 - Ap Su>=1 0s 1 S +R p 1978 o - O 1 0s 0 - +R p 1979 1982 - S lastSu 1s 0 - +R p 1980 o - Mar lastSu 0s 1 S +R p 1981 1982 - Mar lastSu 1s 1 S +R p 1983 o - Mar lastSu 2s 1 S +Z Europe/Lisbon -0:36:45 - LMT 1884 +-0:36:45 - LMT 1912 Ja 1 0u +0 p WE%sT 1966 Ap 3 2 +1 - CET 1976 S 26 1 +0 p WE%sT 1983 S 25 1s +0 W- WE%sT 1992 S 27 1s +1 E CE%sT 1996 Mar 31 1u +0 E WE%sT +Z Atlantic/Azores -1:42:40 - LMT 1884 +-1:54:32 - HMT 1912 Ja 1 2u +-2 p -02/-01 1942 Ap 25 22s +-2 p +00 1942 Au 15 22s +-2 p -02/-01 1943 Ap 17 22s +-2 p +00 1943 Au 28 22s +-2 p -02/-01 1944 Ap 22 22s +-2 p +00 1944 Au 26 22s +-2 p -02/-01 1945 Ap 21 22s +-2 p +00 1945 Au 25 22s +-2 p -02/-01 1966 Ap 3 2 +-1 p -01/+00 1983 S 25 1s +-1 W- -01/+00 1992 S 27 1s +0 E WE%sT 1993 Mar 28 1u +-1 E -01/+00 +Z Atlantic/Madeira -1:7:36 - LMT 1884 +-1:7:36 - FMT 1912 Ja 1 1u +-1 p -01/+00 1942 Ap 25 22s +-1 p +01 1942 Au 15 22s +-1 p -01/+00 1943 Ap 17 22s +-1 p +01 1943 Au 28 22s +-1 p -01/+00 1944 Ap 22 22s +-1 p +01 1944 Au 26 22s +-1 p -01/+00 1945 Ap 21 22s +-1 p +01 1945 Au 25 22s +-1 p -01/+00 1966 Ap 3 2 +0 p WE%sT 1983 S 25 1s +0 E WE%sT +R z 1932 o - May 21 0s 1 S +R z 1932 1939 - O Su>=1 0s 0 - +R z 1933 1939 - Ap Su>=2 0s 1 S +R z 1979 o - May 27 0 1 S +R z 1979 o - S lastSu 0 0 - +R z 1980 o - Ap 5 23 1 S +R z 1980 o - S lastSu 1 0 - +R z 1991 1993 - Mar lastSu 0s 1 S +R z 1991 1993 - S lastSu 0s 0 - +Z Europe/Bucharest 1:44:24 - LMT 1891 O +1:44:24 - BMT 1931 Jul 24 +2 z EE%sT 1981 Mar 29 2s +2 c EE%sT 1991 +2 z EE%sT 1994 +2 e EE%sT 1997 +2 E EE%sT +Z Europe/Kaliningrad 1:22 - LMT 1893 Ap +1 c CE%sT 1945 Ap 10 +2 O EE%sT 1946 Ap 7 +3 R MSK/MSD 1989 Mar 26 2s +2 R EE%sT 2011 Mar 27 2s +3 - +03 2014 O 26 2s +2 - EET +Z Europe/Moscow 2:30:17 - LMT 1880 +2:30:17 - MMT 1916 Jul 3 +2:31:19 R %s 1919 Jul 1 0u +3 R %s 1921 O +3 R MSK/MSD 1922 O +2 - EET 1930 Jun 21 +3 R MSK/MSD 1991 Mar 31 2s +2 R EE%sT 1992 Ja 19 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Simferopol 2:16:24 - LMT 1880 +2:16 - SMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 N +1 c CE%sT 1944 Ap 13 +3 R MSK/MSD 1990 +3 - MSK 1990 Jul 1 2 +2 - EET 1992 Mar 20 +2 c EE%sT 1994 May +3 c MSK/MSD 1996 Mar 31 0s +3 1 MSD 1996 O 27 3s +3 - MSK 1997 Mar lastSu 1u +2 E EE%sT 2014 Mar 30 2 +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Astrakhan 3:12:12 - LMT 1924 May +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 Mar 27 2s +4 - +04 +Z Europe/Volgograd 2:57:40 - LMT 1920 Ja 3 +3 - +03 1930 Jun 21 +4 - +04 1961 N 11 +4 R +04/+05 1988 Mar 27 2s +3 R MSK/MSD 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK 2018 O 28 2s +4 - +04 2020 D 27 2s +3 - MSK +Z Europe/Saratov 3:4:18 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1988 Mar 27 2s +3 R +03/+04 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 D 4 2s +4 - +04 +Z Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R MSK/MSD 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Samara 3:20:20 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 - +04 1935 Ja 27 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +2 R +02/+03 1991 S 29 2s +3 - +03 1991 O 20 3 +4 R +04/+05 2010 Mar 28 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 +Z Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +2 R +02/+03 1992 Ja 19 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 Mar 27 2s +4 - +04 +Z Asia/Yekaterinburg 4:2:33 - LMT 1916 Jul 3 +3:45:5 - PMT 1919 Jul 15 4 +4 - +04 1930 Jun 21 +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2011 Mar 27 2s +6 - +06 2014 O 26 2s +5 - +05 +Z Asia/Omsk 4:53:30 - LMT 1919 N 14 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 +Z Asia/Barnaul 5:35 - LMT 1919 D 10 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 1995 May 28 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 Mar 27 2s +7 - +07 +Z Asia/Novosibirsk 5:31:40 - LMT 1919 D 14 6 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 1993 May 23 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 Jul 24 2s +7 - +07 +Z Asia/Tomsk 5:39:51 - LMT 1919 D 22 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2002 May 1 3 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 May 29 2s +7 - +07 +Z Asia/Novokuznetsk 5:48:48 - LMT 1924 May +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2010 Mar 28 2s +6 R +06/+07 2011 Mar 27 2s +7 - +07 +Z Asia/Krasnoyarsk 6:11:26 - LMT 1920 Ja 6 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2011 Mar 27 2s +8 - +08 2014 O 26 2s +7 - +07 +Z Asia/Irkutsk 6:57:5 - LMT 1880 +6:57:5 - IMT 1920 Ja 25 +7 - +07 1930 Jun 21 +8 R +08/+09 1991 Mar 31 2s +7 R +07/+08 1992 Ja 19 2s +8 R +08/+09 2011 Mar 27 2s +9 - +09 2014 O 26 2s +8 - +08 +Z Asia/Chita 7:33:52 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2011 Mar 27 2s +10 - +10 2014 O 26 2s +8 - +08 2016 Mar 27 2 +9 - +09 +Z Asia/Yakutsk 8:38:58 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2011 Mar 27 2s +10 - +10 2014 O 26 2s +9 - +09 +Z Asia/Vladivostok 8:47:31 - LMT 1922 N 15 +9 - +09 1930 Jun 21 +10 R +10/+11 1991 Mar 31 2s +9 R +09/+10 1992 Ja 19 2s +10 R +10/+11 2011 Mar 27 2s +11 - +11 2014 O 26 2s +10 - +10 +Z Asia/Khandyga 9:2:13 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2004 +10 R +10/+11 2011 Mar 27 2s +11 - +11 2011 S 13 0s +10 - +10 2014 O 26 2s +9 - +09 +Z Asia/Sakhalin 9:30:48 - LMT 1905 Au 23 +9 - +09 1945 Au 25 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 1997 Mar lastSu 2s +10 R +10/+11 2011 Mar 27 2s +11 - +11 2014 O 26 2s +10 - +10 2016 Mar 27 2s +11 - +11 +Z Asia/Magadan 10:3:12 - LMT 1924 May 2 +10 - +10 1930 Jun 21 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2014 O 26 2s +10 - +10 2016 Ap 24 2s +11 - +11 +Z Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 +10 - +10 1930 Jun 21 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2014 O 26 2s +11 - +11 +Z Asia/Ust-Nera 9:32:54 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1981 Ap +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2011 S 13 0s +11 - +11 2014 O 26 2s +10 - +10 +Z Asia/Kamchatka 10:34:36 - LMT 1922 N 10 +11 - +11 1930 Jun 21 +12 R +12/+13 1991 Mar 31 2s +11 R +11/+12 1992 Ja 19 2s +12 R +12/+13 2010 Mar 28 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 +Z Asia/Anadyr 11:49:56 - LMT 1924 May 2 +12 - +12 1930 Jun 21 +13 R +13/+14 1982 Ap 1 0s +12 R +12/+13 1991 Mar 31 2s +11 R +11/+12 1992 Ja 19 2s +12 R +12/+13 2010 Mar 28 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 +Z Europe/Belgrade 1:22 - LMT 1884 +1 - CET 1941 Ap 18 23 +1 c CE%sT 1945 +1 - CET 1945 May 8 2s +1 1 CEST 1945 S 16 2s +1 - CET 1982 N 27 +1 E CE%sT +R s 1918 o - Ap 15 23 1 S +R s 1918 1919 - O 6 24s 0 - +R s 1919 o - Ap 6 23 1 S +R s 1924 o - Ap 16 23 1 S +R s 1924 o - O 4 24s 0 - +R s 1926 o - Ap 17 23 1 S +R s 1926 1929 - O Sa>=1 24s 0 - +R s 1927 o - Ap 9 23 1 S +R s 1928 o - Ap 15 0 1 S +R s 1929 o - Ap 20 23 1 S +R s 1937 o - Jun 16 23 1 S +R s 1937 o - O 2 24s 0 - +R s 1938 o - Ap 2 23 1 S +R s 1938 o - Ap 30 23 2 M +R s 1938 o - O 2 24 1 S +R s 1939 o - O 7 24s 0 - +R s 1942 o - May 2 23 1 S +R s 1942 o - S 1 1 0 - +R s 1943 1946 - Ap Sa>=13 23 1 S +R s 1943 1944 - O Su>=1 1 0 - +R s 1945 1946 - S lastSu 1 0 - +R s 1949 o - Ap 30 23 1 S +R s 1949 o - O 2 1 0 - +R s 1974 1975 - Ap Sa>=12 23 1 S +R s 1974 1975 - O Su>=1 1 0 - +R s 1976 o - Mar 27 23 1 S +R s 1976 1977 - S lastSu 1 0 - +R s 1977 o - Ap 2 23 1 S +R s 1978 o - Ap 2 2s 1 S +R s 1978 o - O 1 2s 0 - +R Sp 1967 o - Jun 3 12 1 S +R Sp 1967 o - O 1 0 0 - +R Sp 1974 o - Jun 24 0 1 S +R Sp 1974 o - S 1 0 0 - +R Sp 1976 1977 - May 1 0 1 S +R Sp 1976 o - Au 1 0 0 - +R Sp 1977 o - S 28 0 0 - +R Sp 1978 o - Jun 1 0 1 S +R Sp 1978 o - Au 4 0 0 - +Z Europe/Madrid -0:14:44 - LMT 1901 Ja 1 0u +0 s WE%sT 1940 Mar 16 23 +1 s CE%sT 1979 +1 E CE%sT +Z Africa/Ceuta -0:21:16 - LMT 1901 Ja 1 0u +0 - WET 1918 May 6 23 +0 1 WEST 1918 O 7 23 +0 - WET 1924 +0 s WE%sT 1929 +0 - WET 1967 +0 Sp WE%sT 1984 Mar 16 +1 - CET 1986 +1 E CE%sT +Z Atlantic/Canary -1:1:36 - LMT 1922 Mar +-1 - -01 1946 S 30 1 +0 - WET 1980 Ap 6 0s +0 1 WEST 1980 S 28 1u +0 E WE%sT +R CH 1941 1942 - May M>=1 1 1 S +R CH 1941 1942 - O M>=1 2 0 - +Z Europe/Zurich 0:34:8 - LMT 1853 Jul 16 +0:29:46 - BMT 1894 Jun +1 CH CE%sT 1981 +1 E CE%sT +R T 1916 o - May 1 0 1 S +R T 1916 o - O 1 0 0 - +R T 1920 o - Mar 28 0 1 S +R T 1920 o - O 25 0 0 - +R T 1921 o - Ap 3 0 1 S +R T 1921 o - O 3 0 0 - +R T 1922 o - Mar 26 0 1 S +R T 1922 o - O 8 0 0 - +R T 1924 o - May 13 0 1 S +R T 1924 1925 - O 1 0 0 - +R T 1925 o - May 1 0 1 S +R T 1940 o - Jul 1 0 1 S +R T 1940 o - O 6 0 0 - +R T 1940 o - D 1 0 1 S +R T 1941 o - S 21 0 0 - +R T 1942 o - Ap 1 0 1 S +R T 1945 o - O 8 0 0 - +R T 1946 o - Jun 1 0 1 S +R T 1946 o - O 1 0 0 - +R T 1947 1948 - Ap Su>=16 0 1 S +R T 1947 1951 - O Su>=2 0 0 - +R T 1949 o - Ap 10 0 1 S +R T 1950 o - Ap 16 0 1 S +R T 1951 o - Ap 22 0 1 S +R T 1962 o - Jul 15 0 1 S +R T 1963 o - O 30 0 0 - +R T 1964 o - May 15 0 1 S +R T 1964 o - O 1 0 0 - +R T 1973 o - Jun 3 1 1 S +R T 1973 1976 - O Su>=31 2 0 - +R T 1974 o - Mar 31 2 1 S +R T 1975 o - Mar 22 2 1 S +R T 1976 o - Mar 21 2 1 S +R T 1977 1978 - Ap Su>=1 2 1 S +R T 1977 1978 - O Su>=15 2 0 - +R T 1978 o - Jun 29 0 0 - +R T 1983 o - Jul 31 2 1 S +R T 1983 o - O 2 2 0 - +R T 1985 o - Ap 20 1s 1 S +R T 1985 o - S 28 1s 0 - +R T 1986 1993 - Mar lastSu 1s 1 S +R T 1986 1995 - S lastSu 1s 0 - +R T 1994 o - Mar 20 1s 1 S +R T 1995 2006 - Mar lastSu 1s 1 S +R T 1996 2006 - O lastSu 1s 0 - +Z Europe/Istanbul 1:55:52 - LMT 1880 +1:56:56 - IMT 1910 O +2 T EE%sT 1978 Jun 29 +3 T +03/+04 1984 N 1 2 +2 T EE%sT 2007 +2 E EE%sT 2011 Mar 27 1u +2 - EET 2011 Mar 28 1u +2 E EE%sT 2014 Mar 30 1u +2 - EET 2014 Mar 31 1u +2 E EE%sT 2015 O 25 1u +2 1 EEST 2015 N 8 1u +2 E EE%sT 2016 S 7 +3 - +03 +Z Europe/Kyiv 2:2:4 - LMT 1880 +2:2:4 - KMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 S 20 +1 c CE%sT 1943 N 6 +3 R MSK/MSD 1990 Jul 1 2 +2 1 EEST 1991 S 29 3 +2 c EE%sT 1996 May 13 +2 E EE%sT +R u 1918 1919 - Mar lastSu 2 1 D +R u 1918 1919 - O lastSu 2 0 S +R u 1942 o - F 9 2 1 W +R u 1945 o - Au 14 23u 1 P +R u 1945 o - S 30 2 0 S +R u 1967 2006 - O lastSu 2 0 S +R u 1967 1973 - Ap lastSu 2 1 D +R u 1974 o - Ja 6 2 1 D +R u 1975 o - F lastSu 2 1 D +R u 1976 1986 - Ap lastSu 2 1 D +R u 1987 2006 - Ap Su>=1 2 1 D +R u 2007 ma - Mar Su>=8 2 1 D +R u 2007 ma - N Su>=1 2 0 S +Z EST -5 - EST +Z MST -7 - MST +Z HST -10 - HST +Z EST5EDT -5 u E%sT +Z CST6CDT -6 u C%sT +Z MST7MDT -7 u M%sT +Z PST8PDT -8 u P%sT +R NY 1920 o - Mar lastSu 2 1 D +R NY 1920 o - O lastSu 2 0 S +R NY 1921 1966 - Ap lastSu 2 1 D +R NY 1921 1954 - S lastSu 2 0 S +R NY 1955 1966 - O lastSu 2 0 S +Z America/New_York -4:56:2 - LMT 1883 N 18 17u +-5 u E%sT 1920 +-5 NY E%sT 1942 +-5 u E%sT 1946 +-5 NY E%sT 1967 +-5 u E%sT +R Ch 1920 o - Jun 13 2 1 D +R Ch 1920 1921 - O lastSu 2 0 S +R Ch 1921 o - Mar lastSu 2 1 D +R Ch 1922 1966 - Ap lastSu 2 1 D +R Ch 1922 1954 - S lastSu 2 0 S +R Ch 1955 1966 - O lastSu 2 0 S +Z America/Chicago -5:50:36 - LMT 1883 N 18 18u +-6 u C%sT 1920 +-6 Ch C%sT 1936 Mar 1 2 +-5 - EST 1936 N 15 2 +-6 Ch C%sT 1942 +-6 u C%sT 1946 +-6 Ch C%sT 1967 +-6 u C%sT +Z America/North_Dakota/Center -6:45:12 - LMT 1883 N 18 19u +-7 u M%sT 1992 O 25 2 +-6 u C%sT +Z America/North_Dakota/New_Salem -6:45:39 - LMT 1883 N 18 19u +-7 u M%sT 2003 O 26 2 +-6 u C%sT +Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 19u +-7 u M%sT 2010 N 7 2 +-6 u C%sT +R De 1920 1921 - Mar lastSu 2 1 D +R De 1920 o - O lastSu 2 0 S +R De 1921 o - May 22 2 0 S +R De 1965 1966 - Ap lastSu 2 1 D +R De 1965 1966 - O lastSu 2 0 S +Z America/Denver -6:59:56 - LMT 1883 N 18 19u +-7 u M%sT 1920 +-7 De M%sT 1942 +-7 u M%sT 1946 +-7 De M%sT 1967 +-7 u M%sT +R CA 1948 o - Mar 14 2:1 1 D +R CA 1949 o - Ja 1 2 0 S +R CA 1950 1966 - Ap lastSu 1 1 D +R CA 1950 1961 - S lastSu 2 0 S +R CA 1962 1966 - O lastSu 2 0 S +Z America/Los_Angeles -7:52:58 - LMT 1883 N 18 20u +-8 u P%sT 1946 +-8 CA P%sT 1967 +-8 u P%sT +Z America/Juneau 15:2:19 - LMT 1867 O 19 15:33:32 +-8:57:41 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1980 Ap 27 2 +-9 u Y%sT 1980 O 26 2 +-8 u P%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Sitka 14:58:47 - LMT 1867 O 19 15:30 +-9:1:13 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55 +-8:46:18 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1983 O 30 2 +-8 - PST 2015 N 1 2 +-9 u AK%sT 2018 N 4 2 +-8 - PST 2019 Ja 20 2 +-9 u AK%sT +Z America/Yakutat 14:41:5 - LMT 1867 O 19 15:12:18 +-9:18:55 - LMT 1900 Au 20 12 +-9 - YST 1942 +-9 u Y%sT 1946 +-9 - YST 1969 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Anchorage 14:0:24 - LMT 1867 O 19 14:31:37 +-9:59:36 - LMT 1900 Au 20 12 +-10 - AST 1942 +-10 u A%sT 1967 Ap +-10 - AHST 1969 +-10 u AH%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Nome 12:58:22 - LMT 1867 O 19 13:29:35 +-11:1:38 - LMT 1900 Au 20 12 +-11 - NST 1942 +-11 u N%sT 1946 +-11 - NST 1967 Ap +-11 - BST 1969 +-11 u B%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35 +-11:46:38 - LMT 1900 Au 20 12 +-11 - NST 1942 +-11 u N%sT 1946 +-11 - NST 1967 Ap +-11 - BST 1969 +-11 u B%sT 1983 O 30 2 +-10 u AH%sT 1983 N 30 +-10 u H%sT +Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12 +-10:30 - HST 1933 Ap 30 2 +-10:30 1 HDT 1933 May 21 12 +-10:30 u H%sT 1947 Jun 8 2 +-10 - HST +Z America/Phoenix -7:28:18 - LMT 1883 N 18 19u +-7 u M%sT 1944 Ja 1 0:1 +-7 - MST 1944 Ap 1 0:1 +-7 u M%sT 1944 O 1 0:1 +-7 - MST 1967 +-7 u M%sT 1968 Mar 21 +-7 - MST +Z America/Boise -7:44:49 - LMT 1883 N 18 20u +-8 u P%sT 1923 May 13 2 +-7 u M%sT 1974 +-7 - MST 1974 F 3 2 +-7 u M%sT +R In 1941 o - Jun 22 2 1 D +R In 1941 1954 - S lastSu 2 0 S +R In 1946 1954 - Ap lastSu 2 1 D +Z America/Indiana/Indianapolis -5:44:38 - LMT 1883 N 18 18u +-6 u C%sT 1920 +-6 In C%sT 1942 +-6 u C%sT 1946 +-6 In C%sT 1955 Ap 24 2 +-5 - EST 1957 S 29 2 +-6 - CST 1958 Ap 27 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 +-5 u E%sT +R Ma 1951 o - Ap lastSu 2 1 D +R Ma 1951 o - S lastSu 2 0 S +R Ma 1954 1960 - Ap lastSu 2 1 D +R Ma 1954 1960 - S lastSu 2 0 S +Z America/Indiana/Marengo -5:45:23 - LMT 1883 N 18 18u +-6 u C%sT 1951 +-6 Ma C%sT 1961 Ap 30 2 +-5 - EST 1969 +-5 u E%sT 1974 Ja 6 2 +-6 1 CDT 1974 O 27 2 +-5 u E%sT 1976 +-5 - EST 2006 +-5 u E%sT +R V 1946 o - Ap lastSu 2 1 D +R V 1946 o - S lastSu 2 0 S +R V 1953 1954 - Ap lastSu 2 1 D +R V 1953 1959 - S lastSu 2 0 S +R V 1955 o - May 1 0 1 D +R V 1956 1963 - Ap lastSu 2 1 D +R V 1960 o - O lastSu 2 0 S +R V 1961 o - S lastSu 2 0 S +R V 1962 1963 - O lastSu 2 0 S +Z America/Indiana/Vincennes -5:50:7 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 V C%sT 1964 Ap 26 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 N 4 2 +-5 u E%sT +R Pe 1955 o - May 1 0 1 D +R Pe 1955 1960 - S lastSu 2 0 S +R Pe 1956 1963 - Ap lastSu 2 1 D +R Pe 1961 1963 - O lastSu 2 0 S +Z America/Indiana/Tell_City -5:47:3 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 Pe C%sT 1964 Ap 26 2 +-5 - EST 1967 O 29 2 +-6 u C%sT 1969 Ap 27 2 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT +R Pi 1955 o - May 1 0 1 D +R Pi 1955 1960 - S lastSu 2 0 S +R Pi 1956 1964 - Ap lastSu 2 1 D +R Pi 1961 1964 - O lastSu 2 0 S +Z America/Indiana/Petersburg -5:49:7 - LMT 1883 N 18 18u +-6 u C%sT 1955 +-6 Pi C%sT 1965 Ap 25 2 +-5 - EST 1966 O 30 2 +-6 u C%sT 1977 O 30 2 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 N 4 2 +-5 u E%sT +R St 1947 1961 - Ap lastSu 2 1 D +R St 1947 1954 - S lastSu 2 0 S +R St 1955 1956 - O lastSu 2 0 S +R St 1957 1958 - S lastSu 2 0 S +R St 1959 1961 - O lastSu 2 0 S +Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 18u +-6 u C%sT 1947 +-6 St C%sT 1962 Ap 29 2 +-5 - EST 1963 O 27 2 +-6 u C%sT 1991 O 27 2 +-5 - EST 2006 Ap 2 2 +-6 u C%sT +R Pu 1946 1960 - Ap lastSu 2 1 D +R Pu 1946 1954 - S lastSu 2 0 S +R Pu 1955 1956 - O lastSu 2 0 S +R Pu 1957 1960 - S lastSu 2 0 S +Z America/Indiana/Winamac -5:46:25 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 Pu C%sT 1961 Ap 30 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 Mar 11 2 +-5 u E%sT +Z America/Indiana/Vevay -5:40:16 - LMT 1883 N 18 18u +-6 u C%sT 1954 Ap 25 2 +-5 - EST 1969 +-5 u E%sT 1973 +-5 - EST 2006 +-5 u E%sT +R v 1921 o - May 1 2 1 D +R v 1921 o - S 1 2 0 S +R v 1941 o - Ap lastSu 2 1 D +R v 1941 o - S lastSu 2 0 S +R v 1946 o - Ap lastSu 0:1 1 D +R v 1946 o - Jun 2 2 0 S +R v 1950 1961 - Ap lastSu 2 1 D +R v 1950 1955 - S lastSu 2 0 S +R v 1956 1961 - O lastSu 2 0 S +Z America/Kentucky/Louisville -5:43:2 - LMT 1883 N 18 18u +-6 u C%sT 1921 +-6 v C%sT 1942 +-6 u C%sT 1946 +-6 v C%sT 1961 Jul 23 2 +-5 - EST 1968 +-5 u E%sT 1974 Ja 6 2 +-6 1 CDT 1974 O 27 2 +-5 u E%sT +Z America/Kentucky/Monticello -5:39:24 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 - CST 1968 +-6 u C%sT 2000 O 29 2 +-5 u E%sT +R Dt 1948 o - Ap lastSu 2 1 D +R Dt 1948 o - S lastSu 2 0 S +Z America/Detroit -5:32:11 - LMT 1905 +-6 - CST 1915 May 15 2 +-5 - EST 1942 +-5 u E%sT 1946 +-5 Dt E%sT 1967 Jun 14 0:1 +-5 u E%sT 1969 +-5 - EST 1973 +-5 u E%sT 1975 +-5 - EST 1975 Ap 27 2 +-5 u E%sT +R Me 1946 o - Ap lastSu 2 1 D +R Me 1946 o - S lastSu 2 0 S +R Me 1966 o - Ap lastSu 2 1 D +R Me 1966 o - O lastSu 2 0 S +Z America/Menominee -5:50:27 - LMT 1885 S 18 12 +-6 u C%sT 1946 +-6 Me C%sT 1969 Ap 27 2 +-5 - EST 1973 Ap 29 2 +-6 u C%sT +R C 1918 o - Ap 14 2 1 D +R C 1918 o - O 27 2 0 S +R C 1942 o - F 9 2 1 W +R C 1945 o - Au 14 23u 1 P +R C 1945 o - S 30 2 0 S +R C 1974 1986 - Ap lastSu 2 1 D +R C 1974 2006 - O lastSu 2 0 S +R C 1987 2006 - Ap Su>=1 2 1 D +R C 2007 ma - Mar Su>=8 2 1 D +R C 2007 ma - N Su>=1 2 0 S +R j 1917 o - Ap 8 2 1 D +R j 1917 o - S 17 2 0 S +R j 1919 o - May 5 23 1 D +R j 1919 o - Au 12 23 0 S +R j 1920 1935 - May Su>=1 23 1 D +R j 1920 1935 - O lastSu 23 0 S +R j 1936 1941 - May M>=9 0 1 D +R j 1936 1941 - O M>=2 0 0 S +R j 1946 1950 - May Su>=8 2 1 D +R j 1946 1950 - O Su>=2 2 0 S +R j 1951 1986 - Ap lastSu 2 1 D +R j 1951 1959 - S lastSu 2 0 S +R j 1960 1986 - O lastSu 2 0 S +R j 1987 o - Ap Su>=1 0:1 1 D +R j 1987 2006 - O lastSu 0:1 0 S +R j 1988 o - Ap Su>=1 0:1 2 DD +R j 1989 2006 - Ap Su>=1 0:1 1 D +R j 2007 2011 - Mar Su>=8 0:1 1 D +R j 2007 2010 - N Su>=1 0:1 0 S +Z America/St_Johns -3:30:52 - LMT 1884 +-3:30:52 j N%sT 1918 +-3:30:52 C N%sT 1919 +-3:30:52 j N%sT 1935 Mar 30 +-3:30 j N%sT 1942 May 11 +-3:30 C N%sT 1946 +-3:30 j N%sT 2011 N +-3:30 C N%sT +Z America/Goose_Bay -4:1:40 - LMT 1884 +-3:30:52 - NST 1918 +-3:30:52 C N%sT 1919 +-3:30:52 - NST 1935 Mar 30 +-3:30 - NST 1936 +-3:30 j N%sT 1942 May 11 +-3:30 C N%sT 1946 +-3:30 j N%sT 1966 Mar 15 2 +-4 j A%sT 2011 N +-4 C A%sT +R H 1916 o - Ap 1 0 1 D +R H 1916 o - O 1 0 0 S +R H 1920 o - May 9 0 1 D +R H 1920 o - Au 29 0 0 S +R H 1921 o - May 6 0 1 D +R H 1921 1922 - S 5 0 0 S +R H 1922 o - Ap 30 0 1 D +R H 1923 1925 - May Su>=1 0 1 D +R H 1923 o - S 4 0 0 S +R H 1924 o - S 15 0 0 S +R H 1925 o - S 28 0 0 S +R H 1926 o - May 16 0 1 D +R H 1926 o - S 13 0 0 S +R H 1927 o - May 1 0 1 D +R H 1927 o - S 26 0 0 S +R H 1928 1931 - May Su>=8 0 1 D +R H 1928 o - S 9 0 0 S +R H 1929 o - S 3 0 0 S +R H 1930 o - S 15 0 0 S +R H 1931 1932 - S M>=24 0 0 S +R H 1932 o - May 1 0 1 D +R H 1933 o - Ap 30 0 1 D +R H 1933 o - O 2 0 0 S +R H 1934 o - May 20 0 1 D +R H 1934 o - S 16 0 0 S +R H 1935 o - Jun 2 0 1 D +R H 1935 o - S 30 0 0 S +R H 1936 o - Jun 1 0 1 D +R H 1936 o - S 14 0 0 S +R H 1937 1938 - May Su>=1 0 1 D +R H 1937 1941 - S M>=24 0 0 S +R H 1939 o - May 28 0 1 D +R H 1940 1941 - May Su>=1 0 1 D +R H 1946 1949 - Ap lastSu 2 1 D +R H 1946 1949 - S lastSu 2 0 S +R H 1951 1954 - Ap lastSu 2 1 D +R H 1951 1954 - S lastSu 2 0 S +R H 1956 1959 - Ap lastSu 2 1 D +R H 1956 1959 - S lastSu 2 0 S +R H 1962 1973 - Ap lastSu 2 1 D +R H 1962 1973 - O lastSu 2 0 S +Z America/Halifax -4:14:24 - LMT 1902 Jun 15 +-4 H A%sT 1918 +-4 C A%sT 1919 +-4 H A%sT 1942 F 9 2s +-4 C A%sT 1946 +-4 H A%sT 1974 +-4 C A%sT +Z America/Glace_Bay -3:59:48 - LMT 1902 Jun 15 +-4 C A%sT 1953 +-4 H A%sT 1954 +-4 - AST 1972 +-4 H A%sT 1974 +-4 C A%sT +R o 1933 1935 - Jun Su>=8 1 1 D +R o 1933 1935 - S Su>=8 1 0 S +R o 1936 1938 - Jun Su>=1 1 1 D +R o 1936 1938 - S Su>=1 1 0 S +R o 1939 o - May 27 1 1 D +R o 1939 1941 - S Sa>=21 1 0 S +R o 1940 o - May 19 1 1 D +R o 1941 o - May 4 1 1 D +R o 1946 1972 - Ap lastSu 2 1 D +R o 1946 1956 - S lastSu 2 0 S +R o 1957 1972 - O lastSu 2 0 S +R o 1993 2006 - Ap Su>=1 0:1 1 D +R o 1993 2006 - O lastSu 0:1 0 S +Z America/Moncton -4:19:8 - LMT 1883 D 9 +-5 - EST 1902 Jun 15 +-4 C A%sT 1933 +-4 o A%sT 1942 +-4 C A%sT 1946 +-4 o A%sT 1973 +-4 C A%sT 1993 +-4 o A%sT 2007 +-4 C A%sT +R t 1919 o - Mar 30 23:30 1 D +R t 1919 o - O 26 0 0 S +R t 1920 o - May 2 2 1 D +R t 1920 o - S 26 0 0 S +R t 1921 o - May 15 2 1 D +R t 1921 o - S 15 2 0 S +R t 1922 1923 - May Su>=8 2 1 D +R t 1922 1926 - S Su>=15 2 0 S +R t 1924 1927 - May Su>=1 2 1 D +R t 1927 1937 - S Su>=25 2 0 S +R t 1928 1937 - Ap Su>=25 2 1 D +R t 1938 1940 - Ap lastSu 2 1 D +R t 1938 1939 - S lastSu 2 0 S +R t 1945 1946 - S lastSu 2 0 S +R t 1946 o - Ap lastSu 2 1 D +R t 1947 1949 - Ap lastSu 0 1 D +R t 1947 1948 - S lastSu 0 0 S +R t 1949 o - N lastSu 0 0 S +R t 1950 1973 - Ap lastSu 2 1 D +R t 1950 o - N lastSu 2 0 S +R t 1951 1956 - S lastSu 2 0 S +R t 1957 1973 - O lastSu 2 0 S +Z America/Toronto -5:17:32 - LMT 1895 +-5 C E%sT 1919 +-5 t E%sT 1942 F 9 2s +-5 C E%sT 1946 +-5 t E%sT 1974 +-5 C E%sT +R W 1916 o - Ap 23 0 1 D +R W 1916 o - S 17 0 0 S +R W 1918 o - Ap 14 2 1 D +R W 1918 o - O 27 2 0 S +R W 1937 o - May 16 2 1 D +R W 1937 o - S 26 2 0 S +R W 1942 o - F 9 2 1 W +R W 1945 o - Au 14 23u 1 P +R W 1945 o - S lastSu 2 0 S +R W 1946 o - May 12 2 1 D +R W 1946 o - O 13 2 0 S +R W 1947 1949 - Ap lastSu 2 1 D +R W 1947 1949 - S lastSu 2 0 S +R W 1950 o - May 1 2 1 D +R W 1950 o - S 30 2 0 S +R W 1951 1960 - Ap lastSu 2 1 D +R W 1951 1958 - S lastSu 2 0 S +R W 1959 o - O lastSu 2 0 S +R W 1960 o - S lastSu 2 0 S +R W 1963 o - Ap lastSu 2 1 D +R W 1963 o - S 22 2 0 S +R W 1966 1986 - Ap lastSu 2s 1 D +R W 1966 2005 - O lastSu 2s 0 S +R W 1987 2005 - Ap Su>=1 2s 1 D +Z America/Winnipeg -6:28:36 - LMT 1887 Jul 16 +-6 W C%sT 2006 +-6 C C%sT +R r 1918 o - Ap 14 2 1 D +R r 1918 o - O 27 2 0 S +R r 1930 1934 - May Su>=1 0 1 D +R r 1930 1934 - O Su>=1 0 0 S +R r 1937 1941 - Ap Su>=8 0 1 D +R r 1937 o - O Su>=8 0 0 S +R r 1938 o - O Su>=1 0 0 S +R r 1939 1941 - O Su>=8 0 0 S +R r 1942 o - F 9 2 1 W +R r 1945 o - Au 14 23u 1 P +R r 1945 o - S lastSu 2 0 S +R r 1946 o - Ap Su>=8 2 1 D +R r 1946 o - O Su>=8 2 0 S +R r 1947 1957 - Ap lastSu 2 1 D +R r 1947 1957 - S lastSu 2 0 S +R r 1959 o - Ap lastSu 2 1 D +R r 1959 o - O lastSu 2 0 S +R Sw 1957 o - Ap lastSu 2 1 D +R Sw 1957 o - O lastSu 2 0 S +R Sw 1959 1961 - Ap lastSu 2 1 D +R Sw 1959 o - O lastSu 2 0 S +R Sw 1960 1961 - S lastSu 2 0 S +Z America/Regina -6:58:36 - LMT 1905 S +-7 r M%sT 1960 Ap lastSu 2 +-6 - CST +Z America/Swift_Current -7:11:20 - LMT 1905 S +-7 C M%sT 1946 Ap lastSu 2 +-7 r M%sT 1950 +-7 Sw M%sT 1972 Ap lastSu 2 +-6 - CST +R Ed 1918 1919 - Ap Su>=8 2 1 D +R Ed 1918 o - O 27 2 0 S +R Ed 1919 o - May 27 2 0 S +R Ed 1920 1923 - Ap lastSu 2 1 D +R Ed 1920 o - O lastSu 2 0 S +R Ed 1921 1923 - S lastSu 2 0 S +R Ed 1942 o - F 9 2 1 W +R Ed 1945 o - Au 14 23u 1 P +R Ed 1945 o - S lastSu 2 0 S +R Ed 1947 o - Ap lastSu 2 1 D +R Ed 1947 o - S lastSu 2 0 S +R Ed 1972 1986 - Ap lastSu 2 1 D +R Ed 1972 2006 - O lastSu 2 0 S +Z America/Edmonton -7:33:52 - LMT 1906 S +-7 Ed M%sT 1987 +-7 C M%sT +R Va 1918 o - Ap 14 2 1 D +R Va 1918 o - O 27 2 0 S +R Va 1942 o - F 9 2 1 W +R Va 1945 o - Au 14 23u 1 P +R Va 1945 o - S 30 2 0 S +R Va 1946 1986 - Ap lastSu 2 1 D +R Va 1946 o - S 29 2 0 S +R Va 1947 1961 - S lastSu 2 0 S +R Va 1962 2006 - O lastSu 2 0 S +Z America/Vancouver -8:12:28 - LMT 1884 +-8 Va P%sT 1987 +-8 C P%sT +Z America/Dawson_Creek -8:0:56 - LMT 1884 +-8 C P%sT 1947 +-8 Va P%sT 1972 Au 30 2 +-7 - MST +Z America/Fort_Nelson -8:10:47 - LMT 1884 +-8 Va P%sT 1946 +-8 - PST 1947 +-8 Va P%sT 1987 +-8 C P%sT 2015 Mar 8 2 +-7 - MST +R Y 1918 o - Ap 14 2 1 D +R Y 1918 o - O 27 2 0 S +R Y 1919 o - May 25 2 1 D +R Y 1919 o - N 1 0 0 S +R Y 1942 o - F 9 2 1 W +R Y 1945 o - Au 14 23u 1 P +R Y 1945 o - S 30 2 0 S +R Y 1972 1986 - Ap lastSu 2 1 D +R Y 1972 2006 - O lastSu 2 0 S +R Y 1987 2006 - Ap Su>=1 2 1 D +R Yu 1965 o - Ap lastSu 0 2 DD +R Yu 1965 o - O lastSu 2 0 S +Z America/Iqaluit 0 - -00 1942 Au +-5 Y E%sT 1999 O 31 2 +-6 C C%sT 2000 O 29 2 +-5 C E%sT +Z America/Resolute 0 - -00 1947 Au 31 +-6 Y C%sT 2000 O 29 2 +-5 - EST 2001 Ap 1 3 +-6 C C%sT 2006 O 29 2 +-5 - EST 2007 Mar 11 3 +-6 C C%sT +Z America/Rankin_Inlet 0 - -00 1957 +-6 Y C%sT 2000 O 29 2 +-5 - EST 2001 Ap 1 3 +-6 C C%sT +Z America/Cambridge_Bay 0 - -00 1920 +-7 Y M%sT 1999 O 31 2 +-6 C C%sT 2000 O 29 2 +-5 - EST 2000 N 5 +-6 - CST 2001 Ap 1 3 +-7 C M%sT +Z America/Inuvik 0 - -00 1953 +-8 Y P%sT 1979 Ap lastSu 2 +-7 Y M%sT 1980 +-7 C M%sT +Z America/Whitehorse -9:0:12 - LMT 1900 Au 20 +-9 Y Y%sT 1965 +-9 Yu Y%sT 1966 F 27 +-8 - PST 1980 +-8 C P%sT 2020 N +-7 - MST +Z America/Dawson -9:17:40 - LMT 1900 Au 20 +-9 Y Y%sT 1965 +-9 Yu Y%sT 1973 O 28 +-8 - PST 1980 +-8 C P%sT 2020 N +-7 - MST +R m 1931 o - May 1 23 1 D +R m 1931 o - O 1 0 0 S +R m 1939 o - F 5 0 1 D +R m 1939 o - Jun 25 0 0 S +R m 1940 o - D 9 0 1 D +R m 1941 o - Ap 1 0 0 S +R m 1943 o - D 16 0 1 W +R m 1944 o - May 1 0 0 S +R m 1950 o - F 12 0 1 D +R m 1950 o - Jul 30 0 0 S +R m 1996 2000 - Ap Su>=1 2 1 D +R m 1996 2000 - O lastSu 2 0 S +R m 2001 o - May Su>=1 2 1 D +R m 2001 o - S lastSu 2 0 S +R m 2002 2022 - Ap Su>=1 2 1 D +R m 2002 2022 - O lastSu 2 0 S +Z America/Cancun -5:47:4 - LMT 1922 Ja 1 6u +-6 - CST 1981 D 23 +-5 m E%sT 1998 Au 2 2 +-6 m C%sT 2015 F 1 2 +-5 - EST +Z America/Merida -5:58:28 - LMT 1922 Ja 1 6u +-6 - CST 1981 D 23 +-5 - EST 1982 D 2 +-6 m C%sT +Z America/Matamoros -6:30 - LMT 1922 Ja 1 6u +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT 2010 +-6 u C%sT +Z America/Monterrey -6:41:16 - LMT 1922 Ja 1 6u +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT +Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 m C%sT 2001 S 30 2 +-6 - CST 2002 F 20 +-6 m C%sT +Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2010 +-7 u M%sT 2022 O 30 2 +-6 - CST 2022 N 30 +-7 u M%sT +Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2010 +-7 u M%sT 2022 O 30 2 +-6 - CST 2022 N 30 +-6 u C%sT +Z America/Chihuahua -7:4:20 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2022 O 30 2 +-6 - CST +Z America/Hermosillo -7:23:52 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT 1999 +-7 - MST +Z America/Mazatlan -7:5:40 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT +Z America/Bahia_Banderas -7:1 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT 2010 Ap 4 2 +-6 m C%sT +Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 7u +-7 - MST 1924 +-8 - PST 1927 Jun 10 23 +-7 - MST 1930 N 15 +-8 - PST 1931 Ap +-8 1 PDT 1931 S 30 +-8 - PST 1942 Ap 24 +-8 1 PWT 1945 Au 14 23u +-8 1 PPT 1945 N 12 +-8 - PST 1948 Ap 5 +-8 1 PDT 1949 Ja 14 +-8 - PST 1954 +-8 CA P%sT 1961 +-8 - PST 1976 +-8 u P%sT 1996 +-8 m P%sT 2001 +-8 u P%sT 2002 F 20 +-8 m P%sT 2010 +-8 u P%sT +R BB 1942 o - Ap 19 5u 1 D +R BB 1942 o - Au 31 6u 0 S +R BB 1943 o - May 2 5u 1 D +R BB 1943 o - S 5 6u 0 S +R BB 1944 o - Ap 10 5u 0:30 - +R BB 1944 o - S 10 6u 0 S +R BB 1977 o - Jun 12 2 1 D +R BB 1977 1978 - O Su>=1 2 0 S +R BB 1978 1980 - Ap Su>=15 2 1 D +R BB 1979 o - S 30 2 0 S +R BB 1980 o - S 25 2 0 S +Z America/Barbados -3:58:29 - LMT 1911 Au 28 +-4 BB A%sT 1944 +-4 BB AST/-0330 1945 +-4 BB A%sT +R BZ 1918 1941 - O Sa>=1 24 0:30 -0530 +R BZ 1919 1942 - F Sa>=8 24 0 CST +R BZ 1942 o - Jun 27 24 1 CWT +R BZ 1945 o - Au 14 23u 1 CPT +R BZ 1945 o - D 15 24 0 CST +R BZ 1947 1967 - O Sa>=1 24 0:30 -0530 +R BZ 1948 1968 - F Sa>=8 24 0 CST +R BZ 1973 o - D 5 0 1 CDT +R BZ 1974 o - F 9 0 0 CST +R BZ 1982 o - D 18 0 1 CDT +R BZ 1983 o - F 12 0 0 CST +Z America/Belize -5:52:48 - LMT 1912 Ap +-6 BZ %s +R Be 1917 o - Ap 5 24 1 - +R Be 1917 o - S 30 24 0 - +R Be 1918 o - Ap 13 24 1 - +R Be 1918 o - S 15 24 0 S +R Be 1942 o - Ja 11 2 1 D +R Be 1942 o - O 18 2 0 S +R Be 1943 o - Mar 21 2 1 D +R Be 1943 o - O 31 2 0 S +R Be 1944 1945 - Mar Su>=8 2 1 D +R Be 1944 1945 - N Su>=1 2 0 S +R Be 1947 o - May Su>=15 2 1 D +R Be 1947 o - S Su>=8 2 0 S +R Be 1948 1952 - May Su>=22 2 1 D +R Be 1948 1952 - S Su>=1 2 0 S +R Be 1956 o - May Su>=22 2 1 D +R Be 1956 o - O lastSu 2 0 S +Z Atlantic/Bermuda -4:19:18 - LMT 1890 +-4:19:18 Be BMT/BST 1930 Ja 1 2 +-4 Be A%sT 1974 Ap 28 2 +-4 C A%sT 1976 +-4 u A%sT +R CR 1979 1980 - F lastSu 0 1 D +R CR 1979 1980 - Jun Su>=1 0 0 S +R CR 1991 1992 - Ja Sa>=15 0 1 D +R CR 1991 o - Jul 1 0 0 S +R CR 1992 o - Mar 15 0 0 S +Z America/Costa_Rica -5:36:13 - LMT 1890 +-5:36:13 - SJMT 1921 Ja 15 +-6 CR C%sT +R Q 1928 o - Jun 10 0 1 D +R Q 1928 o - O 10 0 0 S +R Q 1940 1942 - Jun Su>=1 0 1 D +R Q 1940 1942 - S Su>=1 0 0 S +R Q 1945 1946 - Jun Su>=1 0 1 D +R Q 1945 1946 - S Su>=1 0 0 S +R Q 1965 o - Jun 1 0 1 D +R Q 1965 o - S 30 0 0 S +R Q 1966 o - May 29 0 1 D +R Q 1966 o - O 2 0 0 S +R Q 1967 o - Ap 8 0 1 D +R Q 1967 1968 - S Su>=8 0 0 S +R Q 1968 o - Ap 14 0 1 D +R Q 1969 1977 - Ap lastSu 0 1 D +R Q 1969 1971 - O lastSu 0 0 S +R Q 1972 1974 - O 8 0 0 S +R Q 1975 1977 - O lastSu 0 0 S +R Q 1978 o - May 7 0 1 D +R Q 1978 1990 - O Su>=8 0 0 S +R Q 1979 1980 - Mar Su>=15 0 1 D +R Q 1981 1985 - May Su>=5 0 1 D +R Q 1986 1989 - Mar Su>=14 0 1 D +R Q 1990 1997 - Ap Su>=1 0 1 D +R Q 1991 1995 - O Su>=8 0s 0 S +R Q 1996 o - O 6 0s 0 S +R Q 1997 o - O 12 0s 0 S +R Q 1998 1999 - Mar lastSu 0s 1 D +R Q 1998 2003 - O lastSu 0s 0 S +R Q 2000 2003 - Ap Su>=1 0s 1 D +R Q 2004 o - Mar lastSu 0s 1 D +R Q 2006 2010 - O lastSu 0s 0 S +R Q 2007 o - Mar Su>=8 0s 1 D +R Q 2008 o - Mar Su>=15 0s 1 D +R Q 2009 2010 - Mar Su>=8 0s 1 D +R Q 2011 o - Mar Su>=15 0s 1 D +R Q 2011 o - N 13 0s 0 S +R Q 2012 o - Ap 1 0s 1 D +R Q 2012 ma - N Su>=1 0s 0 S +R Q 2013 ma - Mar Su>=8 0s 1 D +Z America/Havana -5:29:28 - LMT 1890 +-5:29:36 - HMT 1925 Jul 19 12 +-5 Q C%sT +R DO 1966 o - O 30 0 1 EDT +R DO 1967 o - F 28 0 0 EST +R DO 1969 1973 - O lastSu 0 0:30 -0430 +R DO 1970 o - F 21 0 0 EST +R DO 1971 o - Ja 20 0 0 EST +R DO 1972 1974 - Ja 21 0 0 EST +Z America/Santo_Domingo -4:39:36 - LMT 1890 +-4:40 - SDMT 1933 Ap 1 12 +-5 DO %s 1974 O 27 +-4 - AST 2000 O 29 2 +-5 u E%sT 2000 D 3 1 +-4 - AST +R SV 1987 1988 - May Su>=1 0 1 D +R SV 1987 1988 - S lastSu 0 0 S +Z America/El_Salvador -5:56:48 - LMT 1921 +-6 SV C%sT +R GT 1973 o - N 25 0 1 D +R GT 1974 o - F 24 0 0 S +R GT 1983 o - May 21 0 1 D +R GT 1983 o - S 22 0 0 S +R GT 1991 o - Mar 23 0 1 D +R GT 1991 o - S 7 0 0 S +R GT 2006 o - Ap 30 0 1 D +R GT 2006 o - O 1 0 0 S +Z America/Guatemala -6:2:4 - LMT 1918 O 5 +-6 GT C%sT +R HT 1983 o - May 8 0 1 D +R HT 1984 1987 - Ap lastSu 0 1 D +R HT 1983 1987 - O lastSu 0 0 S +R HT 1988 1997 - Ap Su>=1 1s 1 D +R HT 1988 1997 - O lastSu 1s 0 S +R HT 2005 2006 - Ap Su>=1 0 1 D +R HT 2005 2006 - O lastSu 0 0 S +R HT 2012 2015 - Mar Su>=8 2 1 D +R HT 2012 2015 - N Su>=1 2 0 S +R HT 2017 ma - Mar Su>=8 2 1 D +R HT 2017 ma - N Su>=1 2 0 S +Z America/Port-au-Prince -4:49:20 - LMT 1890 +-4:49 - PPMT 1917 Ja 24 12 +-5 HT E%sT +R HN 1987 1988 - May Su>=1 0 1 D +R HN 1987 1988 - S lastSu 0 0 S +R HN 2006 o - May Su>=1 0 1 D +R HN 2006 o - Au M>=1 0 0 S +Z America/Tegucigalpa -5:48:52 - LMT 1921 Ap +-6 HN C%sT +Z America/Jamaica -5:7:10 - LMT 1890 +-5:7:10 - KMT 1912 F +-5 - EST 1974 +-5 u E%sT 1984 +-5 - EST +Z America/Martinique -4:4:20 - LMT 1890 +-4:4:20 - FFMT 1911 May +-4 - AST 1980 Ap 6 +-4 1 ADT 1980 S 28 +-4 - AST +R NI 1979 1980 - Mar Su>=16 0 1 D +R NI 1979 1980 - Jun M>=23 0 0 S +R NI 2005 o - Ap 10 0 1 D +R NI 2005 o - O Su>=1 0 0 S +R NI 2006 o - Ap 30 2 1 D +R NI 2006 o - O Su>=1 1 0 S +Z America/Managua -5:45:8 - LMT 1890 +-5:45:12 - MMT 1934 Jun 23 +-6 - CST 1973 May +-5 - EST 1975 F 16 +-6 NI C%sT 1992 Ja 1 4 +-5 - EST 1992 S 24 +-6 - CST 1993 +-5 - EST 1997 +-6 NI C%sT +Z America/Panama -5:18:8 - LMT 1890 +-5:19:36 - CMT 1908 Ap 22 +-5 - EST +Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12 +-4 - AST 1942 May 3 +-4 u A%sT 1946 +-4 - AST +Z America/Miquelon -3:44:40 - LMT 1911 May 15 +-4 - AST 1980 May +-3 - -03 1987 +-3 C -03/-02 +Z America/Grand_Turk -4:44:32 - LMT 1890 +-5:7:10 - KMT 1912 F +-5 - EST 1979 +-5 u E%sT 2015 Mar 8 2 +-4 - AST 2018 Mar 11 3 +-5 u E%sT +R A 1930 o - D 1 0 1 - +R A 1931 o - Ap 1 0 0 - +R A 1931 o - O 15 0 1 - +R A 1932 1940 - Mar 1 0 0 - +R A 1932 1939 - N 1 0 1 - +R A 1940 o - Jul 1 0 1 - +R A 1941 o - Jun 15 0 0 - +R A 1941 o - O 15 0 1 - +R A 1943 o - Au 1 0 0 - +R A 1943 o - O 15 0 1 - +R A 1946 o - Mar 1 0 0 - +R A 1946 o - O 1 0 1 - +R A 1963 o - O 1 0 0 - +R A 1963 o - D 15 0 1 - +R A 1964 1966 - Mar 1 0 0 - +R A 1964 1966 - O 15 0 1 - +R A 1967 o - Ap 2 0 0 - +R A 1967 1968 - O Su>=1 0 1 - +R A 1968 1969 - Ap Su>=1 0 0 - +R A 1974 o - Ja 23 0 1 - +R A 1974 o - May 1 0 0 - +R A 1988 o - D 1 0 1 - +R A 1989 1993 - Mar Su>=1 0 0 - +R A 1989 1992 - O Su>=15 0 1 - +R A 1999 o - O Su>=1 0 1 - +R A 2000 o - Mar 3 0 0 - +R A 2007 o - D 30 0 1 - +R A 2008 2009 - Mar Su>=15 0 0 - +R A 2008 o - O Su>=15 0 1 - +Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 +Z America/Argentina/Cordoba -4:16:48 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 +Z America/Argentina/Salta -4:21:40 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Tucuman -4:20:52 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 13 +-3 A -03/-02 +Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar +-4 - -04 1991 May 7 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/San_Juan -4:34:4 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar +-4 - -04 1991 May 7 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 31 +-4 - -04 2004 Jul 25 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Jujuy -4:21:12 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 Mar 4 +-4 - -04 1990 O 28 +-4 1 -03 1991 Mar 17 +-4 - -04 1991 O 6 +-3 1 -02 1992 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Catamarca -4:23:8 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Mendoza -4:35:16 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 Mar 4 +-4 - -04 1990 O 15 +-4 1 -03 1991 Mar +-4 - -04 1991 O 15 +-4 1 -03 1992 Mar +-4 - -04 1992 O 18 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 23 +-4 - -04 2004 S 26 +-3 A -03/-02 2008 O 18 +-3 - -03 +R Sa 2008 2009 - Mar Su>=8 0 0 - +R Sa 2007 2008 - O Su>=8 0 1 - +Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 +-3 1 -02 1990 Mar 14 +-4 - -04 1990 O 15 +-4 1 -03 1991 Mar +-4 - -04 1991 Jun +-3 - -03 1999 O 3 +-4 1 -03 2000 Mar 3 +-3 - -03 2004 May 31 +-4 - -04 2004 Jul 25 +-3 A -03/-02 2008 Ja 21 +-4 Sa -04/-03 2009 O 11 +-3 - -03 +Z America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Ushuaia -4:33:12 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 30 +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/La_Paz -4:32:36 - LMT 1890 +-4:32:36 - CMT 1931 O 15 +-4:32:36 1 BST 1932 Mar 21 +-4 - -04 +R B 1931 o - O 3 11 1 - +R B 1932 1933 - Ap 1 0 0 - +R B 1932 o - O 3 0 1 - +R B 1949 1952 - D 1 0 1 - +R B 1950 o - Ap 16 1 0 - +R B 1951 1952 - Ap 1 0 0 - +R B 1953 o - Mar 1 0 0 - +R B 1963 o - D 9 0 1 - +R B 1964 o - Mar 1 0 0 - +R B 1965 o - Ja 31 0 1 - +R B 1965 o - Mar 31 0 0 - +R B 1965 o - D 1 0 1 - +R B 1966 1968 - Mar 1 0 0 - +R B 1966 1967 - N 1 0 1 - +R B 1985 o - N 2 0 1 - +R B 1986 o - Mar 15 0 0 - +R B 1986 o - O 25 0 1 - +R B 1987 o - F 14 0 0 - +R B 1987 o - O 25 0 1 - +R B 1988 o - F 7 0 0 - +R B 1988 o - O 16 0 1 - +R B 1989 o - Ja 29 0 0 - +R B 1989 o - O 15 0 1 - +R B 1990 o - F 11 0 0 - +R B 1990 o - O 21 0 1 - +R B 1991 o - F 17 0 0 - +R B 1991 o - O 20 0 1 - +R B 1992 o - F 9 0 0 - +R B 1992 o - O 25 0 1 - +R B 1993 o - Ja 31 0 0 - +R B 1993 1995 - O Su>=11 0 1 - +R B 1994 1995 - F Su>=15 0 0 - +R B 1996 o - F 11 0 0 - +R B 1996 o - O 6 0 1 - +R B 1997 o - F 16 0 0 - +R B 1997 o - O 6 0 1 - +R B 1998 o - Mar 1 0 0 - +R B 1998 o - O 11 0 1 - +R B 1999 o - F 21 0 0 - +R B 1999 o - O 3 0 1 - +R B 2000 o - F 27 0 0 - +R B 2000 2001 - O Su>=8 0 1 - +R B 2001 2006 - F Su>=15 0 0 - +R B 2002 o - N 3 0 1 - +R B 2003 o - O 19 0 1 - +R B 2004 o - N 2 0 1 - +R B 2005 o - O 16 0 1 - +R B 2006 o - N 5 0 1 - +R B 2007 o - F 25 0 0 - +R B 2007 o - O Su>=8 0 1 - +R B 2008 2017 - O Su>=15 0 1 - +R B 2008 2011 - F Su>=15 0 0 - +R B 2012 o - F Su>=22 0 0 - +R B 2013 2014 - F Su>=15 0 0 - +R B 2015 o - F Su>=22 0 0 - +R B 2016 2019 - F Su>=15 0 0 - +R B 2018 o - N Su>=1 0 1 - +Z America/Noronha -2:9:40 - LMT 1914 +-2 B -02/-01 1990 S 17 +-2 - -02 1999 S 30 +-2 B -02/-01 2000 O 15 +-2 - -02 2001 S 13 +-2 B -02/-01 2002 O +-2 - -02 +Z America/Belem -3:13:56 - LMT 1914 +-3 B -03/-02 1988 S 12 +-3 - -03 +Z America/Santarem -3:38:48 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 2008 Jun 24 +-3 - -03 +Z America/Fortaleza -2:34 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 22 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Recife -2:19:36 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 15 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Araguaina -3:12:48 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1995 S 14 +-3 B -03/-02 2003 S 24 +-3 - -03 2012 O 21 +-3 B -03/-02 2013 S +-3 - -03 +Z America/Maceio -2:22:52 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1995 O 13 +-3 B -03/-02 1996 S 4 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 22 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Bahia -2:34:4 - LMT 1914 +-3 B -03/-02 2003 S 24 +-3 - -03 2011 O 16 +-3 B -03/-02 2012 O 21 +-3 - -03 +Z America/Sao_Paulo -3:6:28 - LMT 1914 +-3 B -03/-02 1963 O 23 +-3 1 -02 1964 +-3 B -03/-02 +Z America/Campo_Grande -3:38:28 - LMT 1914 +-4 B -04/-03 +Z America/Cuiaba -3:44:20 - LMT 1914 +-4 B -04/-03 2003 S 24 +-4 - -04 2004 O +-4 B -04/-03 +Z America/Porto_Velho -4:15:36 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 +Z America/Boa_Vista -4:2:40 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 1999 S 30 +-4 B -04/-03 2000 O 15 +-4 - -04 +Z America/Manaus -4:0:4 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 1993 S 28 +-4 B -04/-03 1994 S 22 +-4 - -04 +Z America/Eirunepe -4:39:28 - LMT 1914 +-5 B -05/-04 1988 S 12 +-5 - -05 1993 S 28 +-5 B -05/-04 1994 S 22 +-5 - -05 2008 Jun 24 +-4 - -04 2013 N 10 +-5 - -05 +Z America/Rio_Branco -4:31:12 - LMT 1914 +-5 B -05/-04 1988 S 12 +-5 - -05 2008 Jun 24 +-4 - -04 2013 N 10 +-5 - -05 +R x 1927 1931 - S 1 0 1 - +R x 1928 1932 - Ap 1 0 0 - +R x 1968 o - N 3 4u 1 - +R x 1969 o - Mar 30 3u 0 - +R x 1969 o - N 23 4u 1 - +R x 1970 o - Mar 29 3u 0 - +R x 1971 o - Mar 14 3u 0 - +R x 1970 1972 - O Su>=9 4u 1 - +R x 1972 1986 - Mar Su>=9 3u 0 - +R x 1973 o - S 30 4u 1 - +R x 1974 1987 - O Su>=9 4u 1 - +R x 1987 o - Ap 12 3u 0 - +R x 1988 1990 - Mar Su>=9 3u 0 - +R x 1988 1989 - O Su>=9 4u 1 - +R x 1990 o - S 16 4u 1 - +R x 1991 1996 - Mar Su>=9 3u 0 - +R x 1991 1997 - O Su>=9 4u 1 - +R x 1997 o - Mar 30 3u 0 - +R x 1998 o - Mar Su>=9 3u 0 - +R x 1998 o - S 27 4u 1 - +R x 1999 o - Ap 4 3u 0 - +R x 1999 2010 - O Su>=9 4u 1 - +R x 2000 2007 - Mar Su>=9 3u 0 - +R x 2008 o - Mar 30 3u 0 - +R x 2009 o - Mar Su>=9 3u 0 - +R x 2010 o - Ap Su>=1 3u 0 - +R x 2011 o - May Su>=2 3u 0 - +R x 2011 o - Au Su>=16 4u 1 - +R x 2012 2014 - Ap Su>=23 3u 0 - +R x 2012 2014 - S Su>=2 4u 1 - +R x 2016 2018 - May Su>=9 3u 0 - +R x 2016 2018 - Au Su>=9 4u 1 - +R x 2019 ma - Ap Su>=2 3u 0 - +R x 2019 2021 - S Su>=2 4u 1 - +R x 2022 o - S Su>=9 4u 1 - +R x 2023 ma - S Su>=2 4u 1 - +Z America/Santiago -4:42:45 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:45 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1946 Jul 14 24 +-4 1 -03 1946 Au 28 24 +-5 1 -04 1947 Mar 31 24 +-5 - -05 1947 May 21 23 +-4 x -04/-03 +Z America/Punta_Arenas -4:43:40 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:45 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1946 Au 28 24 +-5 1 -04 1947 Mar 31 24 +-5 - -05 1947 May 21 23 +-4 x -04/-03 2016 D 4 +-3 - -03 +Z Pacific/Easter -7:17:28 - LMT 1890 +-7:17:28 - EMT 1932 S +-7 x -07/-06 1982 Mar 14 3u +-6 x -06/-05 +Z Antarctica/Palmer 0 - -00 1965 +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1982 May +-4 x -04/-03 2016 D 4 +-3 - -03 +R CO 1992 o - May 3 0 1 - +R CO 1993 o - F 6 24 0 - +Z America/Bogota -4:56:16 - LMT 1884 Mar 13 +-4:56:16 - BMT 1914 N 23 +-5 CO -05/-04 +R EC 1992 o - N 28 0 1 - +R EC 1993 o - F 5 0 0 - +Z America/Guayaquil -5:19:20 - LMT 1890 +-5:14 - QMT 1931 +-5 EC -05/-04 +Z Pacific/Galapagos -5:58:24 - LMT 1931 +-5 - -05 1986 +-6 EC -06/-05 +R FK 1937 1938 - S lastSu 0 1 - +R FK 1938 1942 - Mar Su>=19 0 0 - +R FK 1939 o - O 1 0 1 - +R FK 1940 1942 - S lastSu 0 1 - +R FK 1943 o - Ja 1 0 0 - +R FK 1983 o - S lastSu 0 1 - +R FK 1984 1985 - Ap lastSu 0 0 - +R FK 1984 o - S 16 0 1 - +R FK 1985 2000 - S Su>=9 0 1 - +R FK 1986 2000 - Ap Su>=16 0 0 - +R FK 2001 2010 - Ap Su>=15 2 0 - +R FK 2001 2010 - S Su>=1 2 1 - +Z Atlantic/Stanley -3:51:24 - LMT 1890 +-3:51:24 - SMT 1912 Mar 12 +-4 FK -04/-03 1983 May +-3 FK -03/-02 1985 S 15 +-4 FK -04/-03 2010 S 5 2 +-3 - -03 +Z America/Cayenne -3:29:20 - LMT 1911 Jul +-4 - -04 1967 O +-3 - -03 +Z America/Guyana -3:52:39 - LMT 1911 Au +-4 - -04 1915 Mar +-3:45 - -0345 1975 Au +-3 - -03 1992 Mar 29 1 +-4 - -04 +R y 1975 1988 - O 1 0 1 - +R y 1975 1978 - Mar 1 0 0 - +R y 1979 1991 - Ap 1 0 0 - +R y 1989 o - O 22 0 1 - +R y 1990 o - O 1 0 1 - +R y 1991 o - O 6 0 1 - +R y 1992 o - Mar 1 0 0 - +R y 1992 o - O 5 0 1 - +R y 1993 o - Mar 31 0 0 - +R y 1993 1995 - O 1 0 1 - +R y 1994 1995 - F lastSu 0 0 - +R y 1996 o - Mar 1 0 0 - +R y 1996 2001 - O Su>=1 0 1 - +R y 1997 o - F lastSu 0 0 - +R y 1998 2001 - Mar Su>=1 0 0 - +R y 2002 2004 - Ap Su>=1 0 0 - +R y 2002 2003 - S Su>=1 0 1 - +R y 2004 2009 - O Su>=15 0 1 - +R y 2005 2009 - Mar Su>=8 0 0 - +R y 2010 ma - O Su>=1 0 1 - +R y 2010 2012 - Ap Su>=8 0 0 - +R y 2013 ma - Mar Su>=22 0 0 - +Z America/Asuncion -3:50:40 - LMT 1890 +-3:50:40 - AMT 1931 O 10 +-4 - -04 1972 O +-3 - -03 1974 Ap +-4 y -04/-03 +R PE 1938 o - Ja 1 0 1 - +R PE 1938 o - Ap 1 0 0 - +R PE 1938 1939 - S lastSu 0 1 - +R PE 1939 1940 - Mar Su>=24 0 0 - +R PE 1986 1987 - Ja 1 0 1 - +R PE 1986 1987 - Ap 1 0 0 - +R PE 1990 o - Ja 1 0 1 - +R PE 1990 o - Ap 1 0 0 - +R PE 1994 o - Ja 1 0 1 - +R PE 1994 o - Ap 1 0 0 - +Z America/Lima -5:8:12 - LMT 1890 +-5:8:36 - LMT 1908 Jul 28 +-5 PE -05/-04 +Z Atlantic/South_Georgia -2:26:8 - LMT 1890 +-2 - -02 +Z America/Paramaribo -3:40:40 - LMT 1911 +-3:40:52 - PMT 1935 +-3:40:36 - PMT 1945 O +-3:30 - -0330 1984 O +-3 - -03 +R U 1923 1925 - O 1 0 0:30 - +R U 1924 1926 - Ap 1 0 0 - +R U 1933 1938 - O lastSu 0 0:30 - +R U 1934 1941 - Mar lastSa 24 0 - +R U 1939 o - O 1 0 0:30 - +R U 1940 o - O 27 0 0:30 - +R U 1941 o - Au 1 0 0:30 - +R U 1942 o - D 14 0 0:30 - +R U 1943 o - Mar 14 0 0 - +R U 1959 o - May 24 0 0:30 - +R U 1959 o - N 15 0 0 - +R U 1960 o - Ja 17 0 1 - +R U 1960 o - Mar 6 0 0 - +R U 1965 o - Ap 4 0 1 - +R U 1965 o - S 26 0 0 - +R U 1968 o - May 27 0 0:30 - +R U 1968 o - D 1 0 0 - +R U 1970 o - Ap 25 0 1 - +R U 1970 o - Jun 14 0 0 - +R U 1972 o - Ap 23 0 1 - +R U 1972 o - Jul 16 0 0 - +R U 1974 o - Ja 13 0 1:30 - +R U 1974 o - Mar 10 0 0:30 - +R U 1974 o - S 1 0 0 - +R U 1974 o - D 22 0 1 - +R U 1975 o - Mar 30 0 0 - +R U 1976 o - D 19 0 1 - +R U 1977 o - Mar 6 0 0 - +R U 1977 o - D 4 0 1 - +R U 1978 1979 - Mar Su>=1 0 0 - +R U 1978 o - D 17 0 1 - +R U 1979 o - Ap 29 0 1 - +R U 1980 o - Mar 16 0 0 - +R U 1987 o - D 14 0 1 - +R U 1988 o - F 28 0 0 - +R U 1988 o - D 11 0 1 - +R U 1989 o - Mar 5 0 0 - +R U 1989 o - O 29 0 1 - +R U 1990 o - F 25 0 0 - +R U 1990 1991 - O Su>=21 0 1 - +R U 1991 1992 - Mar Su>=1 0 0 - +R U 1992 o - O 18 0 1 - +R U 1993 o - F 28 0 0 - +R U 2004 o - S 19 0 1 - +R U 2005 o - Mar 27 2 0 - +R U 2005 o - O 9 2 1 - +R U 2006 2015 - Mar Su>=8 2 0 - +R U 2006 2014 - O Su>=1 2 1 - +Z America/Montevideo -3:44:51 - LMT 1908 Jun 10 +-3:44:51 - MMT 1920 May +-4 - -04 1923 O +-3:30 U -0330/-03 1942 D 14 +-3 U -03/-0230 1960 +-3 U -03/-02 1968 +-3 U -03/-0230 1970 +-3 U -03/-02 1974 +-3 U -03/-0130 1974 Mar 10 +-3 U -03/-0230 1974 D 22 +-3 U -03/-02 +Z America/Caracas -4:27:44 - LMT 1890 +-4:27:40 - CMT 1912 F 12 +-4:30 - -0430 1965 +-4 - -04 2007 D 9 3 +-4:30 - -0430 2016 May 1 2:30 +-4 - -04 +Z Etc/UTC 0 - UTC +Z Etc/GMT 0 - GMT +L Etc/GMT GMT +Z Etc/GMT-14 14 - +14 +Z Etc/GMT-13 13 - +13 +Z Etc/GMT-12 12 - +12 +Z Etc/GMT-11 11 - +11 +Z Etc/GMT-10 10 - +10 +Z Etc/GMT-9 9 - +09 +Z Etc/GMT-8 8 - +08 +Z Etc/GMT-7 7 - +07 +Z Etc/GMT-6 6 - +06 +Z Etc/GMT-5 5 - +05 +Z Etc/GMT-4 4 - +04 +Z Etc/GMT-3 3 - +03 +Z Etc/GMT-2 2 - +02 +Z Etc/GMT-1 1 - +01 +Z Etc/GMT+1 -1 - -01 +Z Etc/GMT+2 -2 - -02 +Z Etc/GMT+3 -3 - -03 +Z Etc/GMT+4 -4 - -04 +Z Etc/GMT+5 -5 - -05 +Z Etc/GMT+6 -6 - -06 +Z Etc/GMT+7 -7 - -07 +Z Etc/GMT+8 -8 - -08 +Z Etc/GMT+9 -9 - -09 +Z Etc/GMT+10 -10 - -10 +Z Etc/GMT+11 -11 - -11 +Z Etc/GMT+12 -12 - -12 +Z Factory 0 - -00 +L Australia/Sydney Australia/ACT +L Australia/Lord_Howe Australia/LHI +L Australia/Sydney Australia/NSW +L Australia/Darwin Australia/North +L Australia/Brisbane Australia/Queensland +L Australia/Adelaide Australia/South +L Australia/Hobart Australia/Tasmania +L Australia/Melbourne Australia/Victoria +L Australia/Perth Australia/West +L Australia/Broken_Hill Australia/Yancowinna +L America/Rio_Branco Brazil/Acre +L America/Noronha Brazil/DeNoronha +L America/Sao_Paulo Brazil/East +L America/Manaus Brazil/West +L America/Halifax Canada/Atlantic +L America/Winnipeg Canada/Central +L America/Toronto Canada/Eastern +L America/Edmonton Canada/Mountain +L America/St_Johns Canada/Newfoundland +L America/Vancouver Canada/Pacific +L America/Regina Canada/Saskatchewan +L America/Whitehorse Canada/Yukon +L America/Santiago Chile/Continental +L Pacific/Easter Chile/EasterIsland +L America/Havana Cuba +L Africa/Cairo Egypt +L Europe/Dublin Eire +L Etc/GMT Etc/GMT+0 +L Etc/GMT Etc/GMT-0 +L Etc/GMT Etc/GMT0 +L Etc/GMT Etc/Greenwich +L Etc/UTC Etc/UCT +L Etc/UTC Etc/Universal +L Etc/UTC Etc/Zulu +L Europe/London GB +L Europe/London GB-Eire +L Etc/GMT GMT+0 +L Etc/GMT GMT-0 +L Etc/GMT GMT0 +L Etc/GMT Greenwich +L Asia/Hong_Kong Hongkong +L Africa/Abidjan Iceland +L Asia/Tehran Iran +L Asia/Jerusalem Israel +L America/Jamaica Jamaica +L Asia/Tokyo Japan +L Pacific/Kwajalein Kwajalein +L Africa/Tripoli Libya +L America/Tijuana Mexico/BajaNorte +L America/Mazatlan Mexico/BajaSur +L America/Mexico_City Mexico/General +L Pacific/Auckland NZ +L Pacific/Chatham NZ-CHAT +L America/Denver Navajo +L Asia/Shanghai PRC +L Europe/Warsaw Poland +L Europe/Lisbon Portugal +L Asia/Taipei ROC +L Asia/Seoul ROK +L Asia/Singapore Singapore +L Europe/Istanbul Turkey +L Etc/UTC UCT +L America/Anchorage US/Alaska +L America/Adak US/Aleutian +L America/Phoenix US/Arizona +L America/Chicago US/Central +L America/Indiana/Indianapolis US/East-Indiana +L America/New_York US/Eastern +L Pacific/Honolulu US/Hawaii +L America/Indiana/Knox US/Indiana-Starke +L America/Detroit US/Michigan +L America/Denver US/Mountain +L America/Los_Angeles US/Pacific +L Pacific/Pago_Pago US/Samoa +L Etc/UTC UTC +L Etc/UTC Universal +L Europe/Moscow W-SU +L Etc/UTC Zulu +L America/Argentina/Buenos_Aires America/Buenos_Aires +L America/Argentina/Catamarca America/Catamarca +L America/Argentina/Cordoba America/Cordoba +L America/Indiana/Indianapolis America/Indianapolis +L America/Argentina/Jujuy America/Jujuy +L America/Indiana/Knox America/Knox_IN +L America/Kentucky/Louisville America/Louisville +L America/Argentina/Mendoza America/Mendoza +L America/Puerto_Rico America/Virgin +L Pacific/Pago_Pago Pacific/Samoa +L Africa/Abidjan Africa/Accra +L Africa/Nairobi Africa/Addis_Ababa +L Africa/Nairobi Africa/Asmara +L Africa/Abidjan Africa/Bamako +L Africa/Lagos Africa/Bangui +L Africa/Abidjan Africa/Banjul +L Africa/Maputo Africa/Blantyre +L Africa/Lagos Africa/Brazzaville +L Africa/Maputo Africa/Bujumbura +L Africa/Abidjan Africa/Conakry +L Africa/Abidjan Africa/Dakar +L Africa/Nairobi Africa/Dar_es_Salaam +L Africa/Nairobi Africa/Djibouti +L Africa/Lagos Africa/Douala +L Africa/Abidjan Africa/Freetown +L Africa/Maputo Africa/Gaborone +L Africa/Maputo Africa/Harare +L Africa/Nairobi Africa/Kampala +L Africa/Maputo Africa/Kigali +L Africa/Lagos Africa/Kinshasa +L Africa/Lagos Africa/Libreville +L Africa/Abidjan Africa/Lome +L Africa/Lagos Africa/Luanda +L Africa/Maputo Africa/Lubumbashi +L Africa/Maputo Africa/Lusaka +L Africa/Lagos Africa/Malabo +L Africa/Johannesburg Africa/Maseru +L Africa/Johannesburg Africa/Mbabane +L Africa/Nairobi Africa/Mogadishu +L Africa/Lagos Africa/Niamey +L Africa/Abidjan Africa/Nouakchott +L Africa/Abidjan Africa/Ouagadougou +L Africa/Lagos Africa/Porto-Novo +L America/Puerto_Rico America/Anguilla +L America/Puerto_Rico America/Antigua +L America/Puerto_Rico America/Aruba +L America/Panama America/Atikokan +L America/Puerto_Rico America/Blanc-Sablon +L America/Panama America/Cayman +L America/Phoenix America/Creston +L America/Puerto_Rico America/Curacao +L America/Puerto_Rico America/Dominica +L America/Puerto_Rico America/Grenada +L America/Puerto_Rico America/Guadeloupe +L America/Puerto_Rico America/Kralendijk +L America/Puerto_Rico America/Lower_Princes +L America/Puerto_Rico America/Marigot +L America/Puerto_Rico America/Montserrat +L America/Toronto America/Nassau +L America/Puerto_Rico America/Port_of_Spain +L America/Puerto_Rico America/St_Barthelemy +L America/Puerto_Rico America/St_Kitts +L America/Puerto_Rico America/St_Lucia +L America/Puerto_Rico America/St_Thomas +L America/Puerto_Rico America/St_Vincent +L America/Puerto_Rico America/Tortola +L Pacific/Port_Moresby Antarctica/DumontDUrville +L Pacific/Auckland Antarctica/McMurdo +L Asia/Riyadh Antarctica/Syowa +L Asia/Urumqi Antarctica/Vostok +L Europe/Berlin Arctic/Longyearbyen +L Asia/Riyadh Asia/Aden +L Asia/Qatar Asia/Bahrain +L Asia/Kuching Asia/Brunei +L Asia/Singapore Asia/Kuala_Lumpur +L Asia/Riyadh Asia/Kuwait +L Asia/Dubai Asia/Muscat +L Asia/Bangkok Asia/Phnom_Penh +L Asia/Bangkok Asia/Vientiane +L Africa/Abidjan Atlantic/Reykjavik +L Africa/Abidjan Atlantic/St_Helena +L Europe/Brussels Europe/Amsterdam +L Europe/Prague Europe/Bratislava +L Europe/Zurich Europe/Busingen +L Europe/Berlin Europe/Copenhagen +L Europe/London Europe/Guernsey +L Europe/London Europe/Isle_of_Man +L Europe/London Europe/Jersey +L Europe/Belgrade Europe/Ljubljana +L Europe/Brussels Europe/Luxembourg +L Europe/Helsinki Europe/Mariehamn +L Europe/Paris Europe/Monaco +L Europe/Berlin Europe/Oslo +L Europe/Belgrade Europe/Podgorica +L Europe/Rome Europe/San_Marino +L Europe/Belgrade Europe/Sarajevo +L Europe/Belgrade Europe/Skopje +L Europe/Berlin Europe/Stockholm +L Europe/Zurich Europe/Vaduz +L Europe/Rome Europe/Vatican +L Europe/Belgrade Europe/Zagreb +L Africa/Nairobi Indian/Antananarivo +L Asia/Bangkok Indian/Christmas +L Asia/Yangon Indian/Cocos +L Africa/Nairobi Indian/Comoro +L Indian/Maldives Indian/Kerguelen +L Asia/Dubai Indian/Mahe +L Africa/Nairobi Indian/Mayotte +L Asia/Dubai Indian/Reunion +L Pacific/Port_Moresby Pacific/Chuuk +L Pacific/Tarawa Pacific/Funafuti +L Pacific/Tarawa Pacific/Majuro +L Pacific/Pago_Pago Pacific/Midway +L Pacific/Guadalcanal Pacific/Pohnpei +L Pacific/Guam Pacific/Saipan +L Pacific/Tarawa Pacific/Wake +L Pacific/Tarawa Pacific/Wallis +L Africa/Abidjan Africa/Timbuktu +L America/Argentina/Catamarca America/Argentina/ComodRivadavia +L America/Adak America/Atka +L America/Panama America/Coral_Harbour +L America/Tijuana America/Ensenada +L America/Indiana/Indianapolis America/Fort_Wayne +L America/Toronto America/Montreal +L America/Toronto America/Nipigon +L America/Iqaluit America/Pangnirtung +L America/Rio_Branco America/Porto_Acre +L America/Winnipeg America/Rainy_River +L America/Argentina/Cordoba America/Rosario +L America/Tijuana America/Santa_Isabel +L America/Denver America/Shiprock +L America/Toronto America/Thunder_Bay +L America/Edmonton America/Yellowknife +L Pacific/Auckland Antarctica/South_Pole +L Asia/Shanghai Asia/Chongqing +L Asia/Shanghai Asia/Harbin +L Asia/Urumqi Asia/Kashgar +L Asia/Jerusalem Asia/Tel_Aviv +L Europe/Berlin Atlantic/Jan_Mayen +L Australia/Sydney Australia/Canberra +L Australia/Hobart Australia/Currie +L Europe/London Europe/Belfast +L Europe/Chisinau Europe/Tiraspol +L Europe/Kyiv Europe/Uzhgorod +L Europe/Kyiv Europe/Zaporozhye +L Pacific/Kanton Pacific/Enderbury +L Pacific/Honolulu Pacific/Johnston +L Pacific/Port_Moresby Pacific/Yap +L Africa/Nairobi Africa/Asmera +L America/Nuuk America/Godthab +L Asia/Ashgabat Asia/Ashkhabad +L Asia/Kolkata Asia/Calcutta +L Asia/Shanghai Asia/Chungking +L Asia/Dhaka Asia/Dacca +L Europe/Istanbul Asia/Istanbul +L Asia/Kathmandu Asia/Katmandu +L Asia/Macau Asia/Macao +L Asia/Yangon Asia/Rangoon +L Asia/Ho_Chi_Minh Asia/Saigon +L Asia/Thimphu Asia/Thimbu +L Asia/Makassar Asia/Ujung_Pandang +L Asia/Ulaanbaatar Asia/Ulan_Bator +L Atlantic/Faroe Atlantic/Faeroe +L Europe/Kyiv Europe/Kiev +L Asia/Nicosia Europe/Nicosia +L Pacific/Guadalcanal Pacific/Ponape +L Pacific/Port_Moresby Pacific/Truk diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone.tab b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone.tab new file mode 100644 index 0000000000000000000000000000000000000000..dbcb61793eebe1c6ba5c5fbe8a878e627d39b55d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone.tab @@ -0,0 +1,448 @@ +# tzdb timezone descriptions (deprecated version) +# +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# +# From Paul Eggert (2021-09-20): +# This file is intended as a backward-compatibility aid for older programs. +# New programs should use zone1970.tab. This file is like zone1970.tab (see +# zone1970.tab's comments), but with the following additional restrictions: +# +# 1. This file contains only ASCII characters. +# 2. The first data column contains exactly one country code. +# +# Because of (2), each row stands for an area that is the intersection +# of a region identified by a country code and of a timezone where civil +# clocks have agreed since 1970; this is a narrower definition than +# that of zone1970.tab. +# +# Unlike zone1970.tab, a row's third column can be a Link from +# 'backward' instead of a Zone. +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#country- +#code coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE +2518+05518 Asia/Dubai +AF +3431+06912 Asia/Kabul +AG +1703-06148 America/Antigua +AI +1812-06304 America/Anguilla +AL +4120+01950 Europe/Tirane +AM +4011+04430 Asia/Yerevan +AO -0848+01314 Africa/Luanda +AQ -7750+16636 Antarctica/McMurdo New Zealand time - McMurdo, South Pole +AQ -6617+11031 Antarctica/Casey Casey +AQ -6835+07758 Antarctica/Davis Davis +AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville +AQ -6736+06253 Antarctica/Mawson Mawson +AQ -6448-06406 Antarctica/Palmer Palmer +AQ -6734-06808 Antarctica/Rothera Rothera +AQ -690022+0393524 Antarctica/Syowa Syowa +AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok +AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) +AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF) +AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) +AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) +AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) +AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) +AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) +AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) +AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) +AS -1416-17042 Pacific/Pago_Pago +AT +4813+01620 Europe/Vienna +AU -3133+15905 Australia/Lord_Howe Lord Howe Island +AU -5430+15857 Antarctica/Macquarie Macquarie Island +AU -4253+14719 Australia/Hobart Tasmania +AU -3749+14458 Australia/Melbourne Victoria +AU -3352+15113 Australia/Sydney New South Wales (most areas) +AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) +AU -2728+15302 Australia/Brisbane Queensland (most areas) +AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) +AU -3455+13835 Australia/Adelaide South Australia +AU -1228+13050 Australia/Darwin Northern Territory +AU -3157+11551 Australia/Perth Western Australia (most areas) +AU -3143+12852 Australia/Eucla Western Australia (Eucla) +AW +1230-06958 America/Aruba +AX +6006+01957 Europe/Mariehamn +AZ +4023+04951 Asia/Baku +BA +4352+01825 Europe/Sarajevo +BB +1306-05937 America/Barbados +BD +2343+09025 Asia/Dhaka +BE +5050+00420 Europe/Brussels +BF +1222-00131 Africa/Ouagadougou +BG +4241+02319 Europe/Sofia +BH +2623+05035 Asia/Bahrain +BI -0323+02922 Africa/Bujumbura +BJ +0629+00237 Africa/Porto-Novo +BL +1753-06251 America/St_Barthelemy +BM +3217-06446 Atlantic/Bermuda +BN +0456+11455 Asia/Brunei +BO -1630-06809 America/La_Paz +BQ +120903-0681636 America/Kralendijk +BR -0351-03225 America/Noronha Atlantic islands +BR -0127-04829 America/Belem Para (east); Amapa +BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) +BR -0803-03454 America/Recife Pernambuco +BR -0712-04812 America/Araguaina Tocantins +BR -0940-03543 America/Maceio Alagoas, Sergipe +BR -1259-03831 America/Bahia Bahia +BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) +BR -2027-05437 America/Campo_Grande Mato Grosso do Sul +BR -1535-05605 America/Cuiaba Mato Grosso +BR -0226-05452 America/Santarem Para (west) +BR -0846-06354 America/Porto_Velho Rondonia +BR +0249-06040 America/Boa_Vista Roraima +BR -0308-06001 America/Manaus Amazonas (east) +BR -0640-06952 America/Eirunepe Amazonas (west) +BR -0958-06748 America/Rio_Branco Acre +BS +2505-07721 America/Nassau +BT +2728+08939 Asia/Thimphu +BW -2439+02555 Africa/Gaborone +BY +5354+02734 Europe/Minsk +BZ +1730-08812 America/Belize +CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) +CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) +CA +4606-06447 America/Moncton Atlantic - New Brunswick +CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) +CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) +CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) +CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +744144-0944945 America/Resolute Central - NU (Resolute) +CA +624900-0920459 America/Rankin_Inlet Central - NU (central) +CA +5024-10439 America/Regina CST - SK (most areas) +CA +5017-10750 America/Swift_Current CST - SK (midwest) +CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +4906-11631 America/Creston MST - BC (Creston) +CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) +CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) +CA +6043-13503 America/Whitehorse MST - Yukon (east) +CA +6404-13925 America/Dawson MST - Yukon (west) +CA +4916-12307 America/Vancouver Pacific - BC (most areas) +CC -1210+09655 Indian/Cocos +CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west) +CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east) +CF +0422+01835 Africa/Bangui +CG -0416+01517 Africa/Brazzaville +CH +4723+00832 Europe/Zurich +CI +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago most of Chile +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +CM +0403+00942 Africa/Douala +CN +3114+12128 Asia/Shanghai Beijing Time +CN +4348+08735 Asia/Urumqi Xinjiang Time +CO +0436-07405 America/Bogota +CR +0956-08405 America/Costa_Rica +CU +2308-08222 America/Havana +CV +1455-02331 Atlantic/Cape_Verde +CW +1211-06900 America/Curacao +CX -1025+10543 Indian/Christmas +CY +3510+03322 Asia/Nicosia most of Cyprus +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ +5005+01426 Europe/Prague +DE +5230+01322 Europe/Berlin most of Germany +DE +4742+00841 Europe/Busingen Busingen +DJ +1136+04309 Africa/Djibouti +DK +5540+01235 Europe/Copenhagen +DM +1518-06124 America/Dominica +DO +1828-06954 America/Santo_Domingo +DZ +3647+00303 Africa/Algiers +EC -0210-07950 America/Guayaquil Ecuador (mainland) +EC -0054-08936 Pacific/Galapagos Galapagos Islands +EE +5925+02445 Europe/Tallinn +EG +3003+03115 Africa/Cairo +EH +2709-01312 Africa/El_Aaiun +ER +1520+03853 Africa/Asmara +ES +4024-00341 Europe/Madrid Spain (mainland) +ES +3553-00519 Africa/Ceuta Ceuta, Melilla +ES +2806-01524 Atlantic/Canary Canary Islands +ET +0902+03842 Africa/Addis_Ababa +FI +6010+02458 Europe/Helsinki +FJ -1808+17825 Pacific/Fiji +FK -5142-05751 Atlantic/Stanley +FM +0725+15147 Pacific/Chuuk Chuuk/Truk, Yap +FM +0658+15813 Pacific/Pohnpei Pohnpei/Ponape +FM +0519+16259 Pacific/Kosrae Kosrae +FO +6201-00646 Atlantic/Faroe +FR +4852+00220 Europe/Paris +GA +0023+00927 Africa/Libreville +GB +513030-0000731 Europe/London +GD +1203-06145 America/Grenada +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GG +492717-0023210 Europe/Guernsey +GH +0533-00013 Africa/Accra +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk most of Greenland +GL +7646-01840 America/Danmarkshavn National Park (east coast) +GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit +GL +7634-06847 America/Thule Thule/Pituffik +GM +1328-01639 Africa/Banjul +GN +0931-01343 Africa/Conakry +GP +1614-06132 America/Guadeloupe +GQ +0345+00847 Africa/Malabo +GR +3758+02343 Europe/Athens +GS -5416-03632 Atlantic/South_Georgia +GT +1438-09031 America/Guatemala +GU +1328+14445 Pacific/Guam +GW +1151-01535 Africa/Bissau +GY +0648-05810 America/Guyana +HK +2217+11409 Asia/Hong_Kong +HN +1406-08713 America/Tegucigalpa +HR +4548+01558 Europe/Zagreb +HT +1832-07220 America/Port-au-Prince +HU +4730+01905 Europe/Budapest +ID -0610+10648 Asia/Jakarta Java, Sumatra +ID -0002+10920 Asia/Pontianak Borneo (west, central) +ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +IE +5320-00615 Europe/Dublin +IL +314650+0351326 Asia/Jerusalem +IM +5409-00428 Europe/Isle_of_Man +IN +2232+08822 Asia/Kolkata +IO -0720+07225 Indian/Chagos +IQ +3321+04425 Asia/Baghdad +IR +3540+05126 Asia/Tehran +IS +6409-02151 Atlantic/Reykjavik +IT +4154+01229 Europe/Rome +JE +491101-0020624 Europe/Jersey +JM +175805-0764736 America/Jamaica +JO +3157+03556 Asia/Amman +JP +353916+1394441 Asia/Tokyo +KE -0117+03649 Africa/Nairobi +KG +4254+07436 Asia/Bishkek +KH +1133+10455 Asia/Phnom_Penh +KI +0125+17300 Pacific/Tarawa Gilbert Islands +KI -0247-17143 Pacific/Kanton Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KM -1141+04316 Indian/Comoro +KN +1718-06243 America/St_Kitts +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KW +2920+04759 Asia/Kuwait +KY +1918-08123 America/Cayman +KZ +4315+07657 Asia/Almaty most of Kazakhstan +KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay +KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe +KZ +4431+05016 Asia/Aqtau Mangghystau/Mankistau +KZ +4707+05156 Asia/Atyrau Atyrau/Atirau/Gur'yev +KZ +5113+05121 Asia/Oral West Kazakhstan +LA +1758+10236 Asia/Vientiane +LB +3353+03530 Asia/Beirut +LC +1401-06100 America/St_Lucia +LI +4709+00931 Europe/Vaduz +LK +0656+07951 Asia/Colombo +LR +0618-01047 Africa/Monrovia +LS -2928+02730 Africa/Maseru +LT +5441+02519 Europe/Vilnius +LU +4936+00609 Europe/Luxembourg +LV +5657+02406 Europe/Riga +LY +3254+01311 Africa/Tripoli +MA +3339-00735 Africa/Casablanca +MC +4342+00723 Europe/Monaco +MD +4700+02850 Europe/Chisinau +ME +4226+01916 Europe/Podgorica +MF +1804-06305 America/Marigot +MG -1855+04731 Indian/Antananarivo +MH +0709+17112 Pacific/Majuro most of Marshall Islands +MH +0905+16720 Pacific/Kwajalein Kwajalein +MK +4159+02126 Europe/Skopje +ML +1239-00800 Africa/Bamako +MM +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar most of Mongolia +MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan +MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar +MO +221150+1133230 Asia/Macau +MP +1512+14545 Pacific/Saipan +MQ +1436-06105 America/Martinique +MR +1806-01557 Africa/Nouakchott +MS +1643-06213 America/Montserrat +MT +3554+01431 Europe/Malta +MU -2010+05730 Indian/Mauritius +MV +0410+07330 Indian/Maldives +MW -1547+03500 Africa/Blantyre +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatan +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo Leon, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahia de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California +MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) +MY +0133+11020 Asia/Kuching Sabah, Sarawak +MZ -2558+03235 Africa/Maputo +NA -2234+01706 Africa/Windhoek +NC -2216+16627 Pacific/Noumea +NE +1331+00207 Africa/Niamey +NF -2903+16758 Pacific/Norfolk +NG +0627+00324 Africa/Lagos +NI +1209-08617 America/Managua +NL +5222+00454 Europe/Amsterdam +NO +5955+01045 Europe/Oslo +NP +2743+08519 Asia/Kathmandu +NR -0031+16655 Pacific/Nauru +NU -1901-16955 Pacific/Niue +NZ -3652+17446 Pacific/Auckland most of New Zealand +NZ -4357-17633 Pacific/Chatham Chatham Islands +OM +2336+05835 Asia/Muscat +PA +0858-07932 America/Panama +PE -1203-07703 America/Lima +PF -1732-14934 Pacific/Tahiti Society Islands +PF -0900-13930 Pacific/Marquesas Marquesas Islands +PF -2308-13457 Pacific/Gambier Gambier Islands +PG -0930+14710 Pacific/Port_Moresby most of Papua New Guinea +PG -0613+15534 Pacific/Bougainville Bougainville +PH +1435+12100 Asia/Manila +PK +2452+06703 Asia/Karachi +PL +5215+02100 Europe/Warsaw +PM +4703-05620 America/Miquelon +PN -2504-13005 Pacific/Pitcairn +PR +182806-0660622 America/Puerto_Rico +PS +3130+03428 Asia/Gaza Gaza Strip +PS +313200+0350542 Asia/Hebron West Bank +PT +3843-00908 Europe/Lisbon Portugal (mainland) +PT +3238-01654 Atlantic/Madeira Madeira Islands +PT +3744-02540 Atlantic/Azores Azores +PW +0720+13429 Pacific/Palau +PY -2516-05740 America/Asuncion +QA +2517+05132 Asia/Qatar +RE -2052+05528 Indian/Reunion +RO +4426+02606 Europe/Bucharest +RS +4450+02030 Europe/Belgrade +RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad +RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area +# The obsolescent zone.tab format cannot represent Europe/Simferopol well. +# Put it in RU section and list as UA. See "territorial claims" above. +# Programs should use zone1970.tab instead; see above. +UA +4457+03406 Europe/Simferopol Crimea +RU +5836+04939 Europe/Kirov MSK+00 - Kirov +RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd +RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +5134+04602 Europe/Saratov MSK+01 - Saratov +RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk +RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia +RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals +RU +5500+07324 Asia/Omsk MSK+03 - Omsk +RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk +RU +5322+08345 Asia/Barnaul MSK+04 - Altai +RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk +RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo +RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area +RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia +RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky +RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River +RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky +RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River +RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky +RU +5934+15048 Asia/Magadan MSK+08 - Magadan +RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +RW -0157+03004 Africa/Kigali +SA +2438+04643 Asia/Riyadh +SB -0932+16012 Pacific/Guadalcanal +SC -0440+05528 Indian/Mahe +SD +1536+03232 Africa/Khartoum +SE +5920+01803 Europe/Stockholm +SG +0117+10351 Asia/Singapore +SH -1555-00542 Atlantic/St_Helena +SI +4603+01431 Europe/Ljubljana +SJ +7800+01600 Arctic/Longyearbyen +SK +4809+01707 Europe/Bratislava +SL +0830-01315 Africa/Freetown +SM +4355+01228 Europe/San_Marino +SN +1440-01726 Africa/Dakar +SO +0204+04522 Africa/Mogadishu +SR +0550-05510 America/Paramaribo +SS +0451+03137 Africa/Juba +ST +0020+00644 Africa/Sao_Tome +SV +1342-08912 America/El_Salvador +SX +180305-0630250 America/Lower_Princes +SY +3330+03618 Asia/Damascus +SZ -2618+03106 Africa/Mbabane +TC +2128-07108 America/Grand_Turk +TD +1207+01503 Africa/Ndjamena +TF -492110+0701303 Indian/Kerguelen +TG +0608+00113 Africa/Lome +TH +1345+10031 Asia/Bangkok +TJ +3835+06848 Asia/Dushanbe +TK -0922-17114 Pacific/Fakaofo +TL -0833+12535 Asia/Dili +TM +3757+05823 Asia/Ashgabat +TN +3648+01011 Africa/Tunis +TO -210800-1751200 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TT +1039-06131 America/Port_of_Spain +TV -0831+17913 Pacific/Funafuti +TW +2503+12130 Asia/Taipei +TZ -0648+03917 Africa/Dar_es_Salaam +UA +5026+03031 Europe/Kyiv most of Ukraine +UG +0019+03225 Africa/Kampala +UM +2813-17722 Pacific/Midway Midway Islands +UM +1917+16637 Pacific/Wake Wake Island +US +404251-0740023 America/New_York Eastern (most areas) +US +421953-0830245 America/Detroit Eastern - MI (most areas) +US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) +US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) +US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) +US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) +US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) +US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) +US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) +US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) +US +415100-0873900 America/Chicago Central (most areas) +US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) +US +411745-0863730 America/Indiana/Knox Central - IN (Starke) +US +450628-0873651 America/Menominee Central - MI (Wisconsin border) +US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) +US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) +US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) +US +394421-1045903 America/Denver Mountain (most areas) +US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +332654-1120424 America/Phoenix MST - AZ (except Navajo) +US +340308-1181434 America/Los_Angeles Pacific +US +611305-1495401 America/Anchorage Alaska (most areas) +US +581807-1342511 America/Juneau Alaska - Juneau area +US +571035-1351807 America/Sitka Alaska - Sitka area +US +550737-1313435 America/Metlakatla Alaska - Annette Island +US +593249-1394338 America/Yakutat Alaska - Yakutat +US +643004-1652423 America/Nome Alaska (west) +US +515248-1763929 America/Adak Alaska - western Aleutians +US +211825-1575130 Pacific/Honolulu Hawaii +UY -345433-0561245 America/Montevideo +UZ +3940+06648 Asia/Samarkand Uzbekistan (west) +UZ +4120+06918 Asia/Tashkent Uzbekistan (east) +VA +415408+0122711 Europe/Vatican +VC +1309-06114 America/St_Vincent +VE +1030-06656 America/Caracas +VG +1827-06437 America/Tortola +VI +1821-06456 America/St_Thomas +VN +1045+10640 Asia/Ho_Chi_Minh +VU -1740+16825 Pacific/Efate +WF -1318-17610 Pacific/Wallis +WS -1350-17144 Pacific/Apia +YE +1245+04512 Asia/Aden +YT -1247+04514 Indian/Mayotte +ZA -2615+02800 Africa/Johannesburg +ZM -1525+02817 Africa/Lusaka +ZW -1750+03103 Africa/Harare diff --git a/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone1970.tab b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone1970.tab new file mode 100644 index 0000000000000000000000000000000000000000..1f1cecb848560c0ccff116090e23b0b811925496 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/pytz/zoneinfo/zone1970.tab @@ -0,0 +1,374 @@ +# tzdb timezone descriptions +# +# This file is in the public domain. +# +# From Paul Eggert (2018-06-27): +# This file contains a table where each row stands for a timezone where +# civil timestamps have agreed since 1970. Columns are separated by +# a single tab. Lines beginning with '#' are comments. All text uses +# UTF-8 encoding. The columns of the table are as follows: +# +# 1. The countries that overlap the timezone, as a comma-separated list +# of ISO 3166 2-character country codes. See the file 'iso3166.tab'. +# 2. Latitude and longitude of the timezone's principal location +# in ISO 6709 sign-degrees-minutes-seconds format, +# either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS, +# first latitude (+ is north), then longitude (+ is east). +# 3. Timezone name used in value of TZ environment variable. +# Please see the theory.html file for how these names are chosen. +# If multiple timezones overlap a country, each has a row in the +# table, with each column 1 containing the country code. +# 4. Comments; present if and only if countries have multiple timezones, +# and useful only for those countries. For example, the comments +# for the row with countries CH,DE,LI and name Europe/Zurich +# are useful only for DE, since CH and LI have no other timezones. +# +# If a timezone covers multiple countries, the most-populous city is used, +# and that country is listed first in column 1; any other countries +# are listed alphabetically by country code. The table is sorted +# first by country code, then (if possible) by an order within the +# country that (1) makes some geographical sense, and (2) puts the +# most populous timezones first, where that does not contradict (1). +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#country- +#codes coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet, Scattered Is +AF +3431+06912 Asia/Kabul +AL +4120+01950 Europe/Tirane +AM +4011+04430 Asia/Yerevan +AQ -6617+11031 Antarctica/Casey Casey +AQ -6835+07758 Antarctica/Davis Davis +AQ -6736+06253 Antarctica/Mawson Mawson +AQ -6448-06406 Antarctica/Palmer Palmer +AQ -6734-06808 Antarctica/Rothera Rothera +AQ -720041+0023206 Antarctica/Troll Troll +AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) +AR -3124-06411 America/Argentina/Cordoba most areas: CB, CC, CN, ER, FM, MN, SE, SF +AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) +AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) +AR -2649-06513 America/Argentina/Tucuman Tucumán (TM) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) +AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) +AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) +AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) +AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) +AS,UM -1416-17042 Pacific/Pago_Pago Midway +AT +4813+01620 Europe/Vienna +AU -3133+15905 Australia/Lord_Howe Lord Howe Island +AU -5430+15857 Antarctica/Macquarie Macquarie Island +AU -4253+14719 Australia/Hobart Tasmania +AU -3749+14458 Australia/Melbourne Victoria +AU -3352+15113 Australia/Sydney New South Wales (most areas) +AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) +AU -2728+15302 Australia/Brisbane Queensland (most areas) +AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) +AU -3455+13835 Australia/Adelaide South Australia +AU -1228+13050 Australia/Darwin Northern Territory +AU -3157+11551 Australia/Perth Western Australia (most areas) +AU -3143+12852 Australia/Eucla Western Australia (Eucla) +AZ +4023+04951 Asia/Baku +BB +1306-05937 America/Barbados +BD +2343+09025 Asia/Dhaka +BE,LU,NL +5050+00420 Europe/Brussels +BG +4241+02319 Europe/Sofia +BM +3217-06446 Atlantic/Bermuda +BO -1630-06809 America/La_Paz +BR -0351-03225 America/Noronha Atlantic islands +BR -0127-04829 America/Belem Pará (east); Amapá +BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) +BR -0803-03454 America/Recife Pernambuco +BR -0712-04812 America/Araguaina Tocantins +BR -0940-03543 America/Maceio Alagoas, Sergipe +BR -1259-03831 America/Bahia Bahia +BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) +BR -2027-05437 America/Campo_Grande Mato Grosso do Sul +BR -1535-05605 America/Cuiaba Mato Grosso +BR -0226-05452 America/Santarem Pará (west) +BR -0846-06354 America/Porto_Velho Rondônia +BR +0249-06040 America/Boa_Vista Roraima +BR -0308-06001 America/Manaus Amazonas (east) +BR -0640-06952 America/Eirunepe Amazonas (west) +BR -0958-06748 America/Rio_Branco Acre +BT +2728+08939 Asia/Thimphu +BY +5354+02734 Europe/Minsk +BZ +1730-08812 America/Belize +CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) +CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) +CA +4606-06447 America/Moncton Atlantic - New Brunswick +CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) +CA,BS +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) +CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +744144-0944945 America/Resolute Central - NU (Resolute) +CA +624900-0920459 America/Rankin_Inlet Central - NU (central) +CA +5024-10439 America/Regina CST - SK (most areas) +CA +5017-10750 America/Swift_Current CST - SK (midwest) +CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) +CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) +CA +6043-13503 America/Whitehorse MST - Yukon (east) +CA +6404-13925 America/Dawson MST - Yukon (west) +CA +4916-12307 America/Vancouver Pacific - BC (most areas) +CH,DE,LI +4723+00832 Europe/Zurich Büsingen +CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago most of Chile +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +CN +3114+12128 Asia/Shanghai Beijing Time +CN,AQ +4348+08735 Asia/Urumqi Xinjiang Time, Vostok +CO +0436-07405 America/Bogota +CR +0956-08405 America/Costa_Rica +CU +2308-08222 America/Havana +CV +1455-02331 Atlantic/Cape_Verde +CY +3510+03322 Asia/Nicosia most of Cyprus +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ,SK +5005+01426 Europe/Prague +DE,DK,NO,SE,SJ +5230+01322 Europe/Berlin most of Germany +DO +1828-06954 America/Santo_Domingo +DZ +3647+00303 Africa/Algiers +EC -0210-07950 America/Guayaquil Ecuador (mainland) +EC -0054-08936 Pacific/Galapagos Galápagos Islands +EE +5925+02445 Europe/Tallinn +EG +3003+03115 Africa/Cairo +EH +2709-01312 Africa/El_Aaiun +ES +4024-00341 Europe/Madrid Spain (mainland) +ES +3553-00519 Africa/Ceuta Ceuta, Melilla +ES +2806-01524 Atlantic/Canary Canary Islands +FI,AX +6010+02458 Europe/Helsinki +FJ -1808+17825 Pacific/Fiji +FK -5142-05751 Atlantic/Stanley +FM +0519+16259 Pacific/Kosrae Kosrae +FO +6201-00646 Atlantic/Faroe +FR,MC +4852+00220 Europe/Paris +GB,GG,IM,JE +513030-0000731 Europe/London +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk most of Greenland +GL +7646-01840 America/Danmarkshavn National Park (east coast) +GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit +GL +7634-06847 America/Thule Thule/Pituffik +GR +3758+02343 Europe/Athens +GS -5416-03632 Atlantic/South_Georgia +GT +1438-09031 America/Guatemala +GU,MP +1328+14445 Pacific/Guam +GW +1151-01535 Africa/Bissau +GY +0648-05810 America/Guyana +HK +2217+11409 Asia/Hong_Kong +HN +1406-08713 America/Tegucigalpa +HT +1832-07220 America/Port-au-Prince +HU +4730+01905 Europe/Budapest +ID -0610+10648 Asia/Jakarta Java, Sumatra +ID -0002+10920 Asia/Pontianak Borneo (west, central) +ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +IE +5320-00615 Europe/Dublin +IL +314650+0351326 Asia/Jerusalem +IN +2232+08822 Asia/Kolkata +IO -0720+07225 Indian/Chagos +IQ +3321+04425 Asia/Baghdad +IR +3540+05126 Asia/Tehran +IT,SM,VA +4154+01229 Europe/Rome +JM +175805-0764736 America/Jamaica +JO +3157+03556 Asia/Amman +JP +353916+1394441 Asia/Tokyo +KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi +KG +4254+07436 Asia/Bishkek +KI,MH,TV,UM,WF +0125+17300 Pacific/Tarawa Gilberts, Marshalls, Wake +KI -0247-17143 Pacific/Kanton Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KZ +4315+07657 Asia/Almaty most of Kazakhstan +KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay +KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe +KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau +KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev +KZ +5113+05121 Asia/Oral West Kazakhstan +LB +3353+03530 Asia/Beirut +LK +0656+07951 Asia/Colombo +LR +0618-01047 Africa/Monrovia +LT +5441+02519 Europe/Vilnius +LV +5657+02406 Europe/Riga +LY +3254+01311 Africa/Tripoli +MA +3339-00735 Africa/Casablanca +MD +4700+02850 Europe/Chisinau +MH +0905+16720 Pacific/Kwajalein Kwajalein +MM,CC +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar most of Mongolia +MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan +MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar +MO +221150+1133230 Asia/Macau +MQ +1436-06105 America/Martinique +MT +3554+01431 Europe/Malta +MU -2010+05730 Indian/Mauritius +MV,TF +0410+07330 Indian/Maldives Kerguelen, St Paul I, Amsterdam I +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatán +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo León, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo León, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahía de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California +MY,BN +0133+11020 Asia/Kuching Sabah, Sarawak +MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time +NA -2234+01706 Africa/Windhoek +NC -2216+16627 Pacific/Noumea +NF -2903+16758 Pacific/Norfolk +NG,AO,BJ,CD,CF,CG,CM,GA,GQ,NE +0627+00324 Africa/Lagos West Africa Time +NI +1209-08617 America/Managua +NP +2743+08519 Asia/Kathmandu +NR -0031+16655 Pacific/Nauru +NU -1901-16955 Pacific/Niue +NZ,AQ -3652+17446 Pacific/Auckland New Zealand time +NZ -4357-17633 Pacific/Chatham Chatham Islands +PA,CA,KY +0858-07932 America/Panama EST - ON (Atikokan), NU (Coral H) +PE -1203-07703 America/Lima +PF -1732-14934 Pacific/Tahiti Society Islands +PF -0900-13930 Pacific/Marquesas Marquesas Islands +PF -2308-13457 Pacific/Gambier Gambier Islands +PG,AQ,FM -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas), Chuuk, Yap, Dumont d'Urville +PG -0613+15534 Pacific/Bougainville Bougainville +PH +1435+12100 Asia/Manila +PK +2452+06703 Asia/Karachi +PL +5215+02100 Europe/Warsaw +PM +4703-05620 America/Miquelon +PN -2504-13005 Pacific/Pitcairn +PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST +PS +3130+03428 Asia/Gaza Gaza Strip +PS +313200+0350542 Asia/Hebron West Bank +PT +3843-00908 Europe/Lisbon Portugal (mainland) +PT +3238-01654 Atlantic/Madeira Madeira Islands +PT +3744-02540 Atlantic/Azores Azores +PW +0720+13429 Pacific/Palau +PY -2516-05740 America/Asuncion +QA,BH +2517+05132 Asia/Qatar +RO +4426+02606 Europe/Bucharest +RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade +RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad +RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area +# Mention RU and UA alphabetically. See "territorial claims" above. +RU,UA +4457+03406 Europe/Simferopol Crimea +RU +5836+04939 Europe/Kirov MSK+00 - Kirov +RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd +RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +5134+04602 Europe/Saratov MSK+01 - Saratov +RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk +RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia +RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals +RU +5500+07324 Asia/Omsk MSK+03 - Omsk +RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk +RU +5322+08345 Asia/Barnaul MSK+04 - Altai +RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk +RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo +RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area +RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia +RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky +RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River +RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky +RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River +RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky +RU +5934+15048 Asia/Magadan MSK+08 - Magadan +RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa +SB,FM -0932+16012 Pacific/Guadalcanal Pohnpei +SD +1536+03232 Africa/Khartoum +SG,MY +0117+10351 Asia/Singapore peninsular Malaysia +SR +0550-05510 America/Paramaribo +SS +0451+03137 Africa/Juba +ST +0020+00644 Africa/Sao_Tome +SV +1342-08912 America/El_Salvador +SY +3330+03618 Asia/Damascus +TC +2128-07108 America/Grand_Turk +TD +1207+01503 Africa/Ndjamena +TH,CX,KH,LA,VN +1345+10031 Asia/Bangkok north Vietnam +TJ +3835+06848 Asia/Dushanbe +TK -0922-17114 Pacific/Fakaofo +TL -0833+12535 Asia/Dili +TM +3757+05823 Asia/Ashgabat +TN +3648+01011 Africa/Tunis +TO -210800-1751200 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TW +2503+12130 Asia/Taipei +UA +5026+03031 Europe/Kyiv most of Ukraine +US +404251-0740023 America/New_York Eastern (most areas) +US +421953-0830245 America/Detroit Eastern - MI (most areas) +US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) +US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) +US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) +US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) +US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) +US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) +US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) +US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) +US +415100-0873900 America/Chicago Central (most areas) +US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) +US +411745-0863730 America/Indiana/Knox Central - IN (Starke) +US +450628-0873651 America/Menominee Central - MI (Wisconsin border) +US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) +US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) +US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) +US +394421-1045903 America/Denver Mountain (most areas) +US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US,CA +332654-1120424 America/Phoenix MST - AZ (most areas), Creston BC +US +340308-1181434 America/Los_Angeles Pacific +US +611305-1495401 America/Anchorage Alaska (most areas) +US +581807-1342511 America/Juneau Alaska - Juneau area +US +571035-1351807 America/Sitka Alaska - Sitka area +US +550737-1313435 America/Metlakatla Alaska - Annette Island +US +593249-1394338 America/Yakutat Alaska - Yakutat +US +643004-1652423 America/Nome Alaska (west) +US +515248-1763929 America/Adak Alaska - western Aleutians +US +211825-1575130 Pacific/Honolulu Hawaii +UY -345433-0561245 America/Montevideo +UZ +3940+06648 Asia/Samarkand Uzbekistan (west) +UZ +4120+06918 Asia/Tashkent Uzbekistan (east) +VE +1030-06656 America/Caracas +VN +1045+10640 Asia/Ho_Chi_Minh south Vietnam +VU -1740+16825 Pacific/Efate +WS -1350-17144 Pacific/Apia +ZA,LS,SZ -2615+02800 Africa/Johannesburg +# +# The next section contains experimental tab-separated comments for +# use by user agents like tzselect that identify continents and oceans. +# +# For example, the comment "#@AQ<tab>Antarctica/" means the country code +# AQ is in the continent Antarctica regardless of the Zone name, +# so Pacific/Auckland should be listed under Antarctica as well as +# under the Pacific because its line's country codes include AQ. +# +# If more than one country code is affected each is listed separated +# by commas, e.g., #@IS,SH<tab>Atlantic/". If a country code is in +# more than one continent or ocean, each is listed separated by +# commas, e.g., the second column of "#@CY,TR<tab>Asia/,Europe/". +# +# These experimental comments are present only for country codes where +# the continent or ocean is not already obvious from the Zone name. +# For example, there is no such comment for RU since it already +# corresponds to Zone names starting with both "Europe/" and "Asia/". +# +#@AQ Antarctica/ +#@IS,SH Atlantic/ +#@CY,TR Asia/,Europe/ +#@SJ Arctic/ +#@CC,CX,KM,MG,YT Indian/ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..de09f408cec1f6d08308ea79fcff9e156468325c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2014 Kenneth Reitz. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..975ce567fcd85dbf86a7ecdfa1d91cd77010f526 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/METADATA @@ -0,0 +1,245 @@ +Metadata-Version: 2.1 +Name: requests-oauthlib +Version: 1.3.1 +Summary: OAuthlib authentication support for Requests. +Home-page: https://github.com/requests/requests-oauthlib +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: ISC +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: BSD License +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: oauthlib (>=3.0.0) +Requires-Dist: requests (>=2.0.0) +Provides-Extra: rsa +Requires-Dist: oauthlib[signedtoken] (>=3.0.0) ; extra == 'rsa' + +Requests-OAuthlib |build-status| |coverage-status| |docs| +========================================================= + +This project provides first-class OAuth library support for `Requests <http://python-requests.org>`_. + +The OAuth 1 workflow +-------------------- + +OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, +requests_oauthlib hides most of these and let you focus at the task at hand. + +Accessing protected resources using requests_oauthlib is as simple as: + +.. code-block:: pycon + + >>> from requests_oauthlib import OAuth1Session + >>> twitter = OAuth1Session('client_key', + client_secret='client_secret', + resource_owner_key='resource_owner_key', + resource_owner_secret='resource_owner_secret') + >>> url = 'https://api.twitter.com/1/account/settings.json' + >>> r = twitter.get(url) + +Before accessing resources you will need to obtain a few credentials from your +provider (e.g. Twitter) and authorization from the user for whom you wish to +retrieve resources for. You can read all about this in the full +`OAuth 1 workflow guide on RTD <https://requests-oauthlib.readthedocs.io/en/latest/oauth1_workflow.html>`_. + +The OAuth 2 workflow +-------------------- + +OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most +common being the Authorization Code Grant, also known as the WebApplication +flow. + +Fetching a protected resource after obtaining an access token can be extremely +simple. However, before accessing resources you will need to obtain a few +credentials from your provider (e.g. Google) and authorization from the user +for whom you wish to retrieve resources for. You can read all about this in the +full `OAuth 2 workflow guide on RTD <https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html>`_. + +Installation +------------- + +To install requests and requests_oauthlib you can use pip: + +.. code-block:: bash + + $ pip install requests requests_oauthlib + +.. |build-status| image:: https://github.com/requests/requests-oauthlib/actions/workflows/run-tests.yml/badge.svg + :target: https://github.com/requests/requests-oauthlib/actions +.. |coverage-status| image:: https://img.shields.io/coveralls/requests/requests-oauthlib.svg + :target: https://coveralls.io/r/requests/requests-oauthlib +.. |docs| image:: https://readthedocs.org/projects/requests-oauthlib/badge/ + :alt: Documentation Status + :scale: 100% + :target: https://requests-oauthlib.readthedocs.io/ + + +History +------- + +v1.3.1 (21 January 2022) +++++++++++++++++++++++++ + +- Add initial support for OAuth Mutual TLS (draft-ietf-oauth-mtls) +- Add eBay compliance fix +- Add Spotify OAuth 2 Tutorial +- Add support for python 3.8, 3.9 +- Fixed LinkedIn Compliance Fixes +- Fixed ReadTheDocs Documentation and sphinx errors +- Moved pipeline to GitHub Actions + +v1.3.0 (6 November 2019) +++++++++++++++++++++++++ + +- Instagram compliance fix +- Added ``force_querystring`` argument to fetch_token() method on OAuth2Session + +v1.2.0 (14 January 2019) +++++++++++++++++++++++++ + +- This project now depends on OAuthlib 3.0.0 and above. It does **not** support + versions of OAuthlib before 3.0.0. +- Updated oauth2 tests to use 'sess' for an OAuth2Session instance instead of `auth` + because OAuth2Session objects and methods acceept an `auth` paramether which is + typically an instance of `requests.auth.HTTPBasicAuth` +- `OAuth2Session.fetch_token` previously tried to guess how and where to provide + "client" and "user" credentials incorrectly. This was incompatible with some + OAuth servers and incompatible with breaking changes in oauthlib that seek to + correctly provide the `client_id`. The older implementation also did not raise + the correct exceptions when username and password are not present on Legacy + clients. +- Avoid automatic netrc authentication for OAuth2Session. + +v1.1.0 (9 January 2019) ++++++++++++++++++++++++ + +- Adjusted version specifier for ``oauthlib`` dependency: this project is + not yet compatible with ``oauthlib`` 3.0.0. +- Dropped dependency on ``nose``. +- Minor changes to clean up the code and make it more readable/maintainable. + +v1.0.0 (4 June 2018) +++++++++++++++++++++ + +- **Removed support for Python 2.6 and Python 3.3.** + This project now supports Python 2.7, and Python 3.4 and above. +- Added several examples to the documentation. +- Added plentymarkets compliance fix. +- Added a ``token`` property to OAuth1Session, to match the corresponding + ``token`` property on OAuth2Session. + +v0.8.0 (14 February 2017) ++++++++++++++++++++++++++ + +- Added Fitbit compliance fix. +- Fixed an issue where newlines in the response body for the access token + request would cause errors when trying to extract the token. +- Fixed an issue introduced in v0.7.0 where users passing ``auth`` to several + methods would encounter conflicts with the ``client_id`` and + ``client_secret``-derived auth. The user-supplied ``auth`` argument is now + used in preference to those options. + +v0.7.0 (22 September 2016) +++++++++++++++++++++++++++ + +- Allowed ``OAuth2Session.request`` to take the ``client_id`` and + ``client_secret`` parameters for the purposes of automatic token refresh, + which may need them. + +v0.6.2 (12 July 2016) ++++++++++++++++++++++ + +- Use ``client_id`` and ``client_secret`` for the Authorization header if + provided. +- Allow explicit bypass of the Authorization header by setting ``auth=False``. +- Pass through the ``proxies`` kwarg when refreshing tokens. +- Miscellaneous cleanups. + +v0.6.1 (19 February 2016) ++++++++++++++++++++++++++ + +- Fixed a bug when sending authorization in headers with no username and + password present. +- Make sure we clear the session token before obtaining a new one. +- Some improvements to the Slack compliance fix. +- Avoid timing problems around token refresh. +- Allow passing arbitrary arguments to requests when calling + ``fetch_request_token`` and ``fetch_access_token``. + +v0.6.0 (14 December 2015) ++++++++++++++++++++++++++ + +- Add compliance fix for Slack. +- Add compliance fix for Mailchimp. +- ``TokenRequestDenied`` exceptions now carry the entire response, not just the + status code. +- Pass through keyword arguments when refreshing tokens automatically. +- Send authorization in headers, not just body, to maximize compatibility. +- More getters/setters available for OAuth2 session client values. +- Allow sending custom headers when refreshing tokens, and set some defaults. + + +v0.5.0 (4 May 2015) ++++++++++++++++++++ +- Fix ``TypeError`` being raised instead of ``TokenMissing`` error. +- Raise requests exceptions on 4XX and 5XX responses in the OAuth2 flow. +- Avoid ``AttributeError`` when initializing the ``OAuth2Session`` class + without complete client information. + +v0.4.2 (16 October 2014) +++++++++++++++++++++++++ +- New ``authorized`` property on OAuth1Session and OAuth2Session, which allows + you to easily determine if the session is already authorized with OAuth tokens + or not. +- New ``TokenMissing`` and ``VerifierMissing`` exception classes for OAuth1Session: + this will make it easier to catch and identify these exceptions. + +v0.4.1 (6 June 2014) +++++++++++++++++++++ +- New install target ``[rsa]`` for people using OAuth1 RSA-SHA1 signature + method. +- Fixed bug in OAuth2 where supplied state param was not used in auth url. +- OAuth2 HTTPS checking can be disabled by setting environment variable + ``OAUTHLIB_INSECURE_TRANSPORT``. +- OAuth1 now re-authorize upon redirects. +- OAuth1 token fetching now raise a detailed error message when the + response body is incorrectly encoded or the request was denied. +- Added support for custom OAuth1 clients. +- OAuth2 compliance fix for Sina Weibo. +- Multiple fixes to facebook compliance fix. +- Compliance fixes now re-encode body properly as bytes in Python 3. +- Logging now properly done under ``requests_oauthlib`` namespace instead + of piggybacking on oauthlib namespace. +- Logging introduced for OAuth1 auth and session. + +v0.4.0 (29 September 2013) +++++++++++++++++++++++++++ +- OAuth1Session methods only return unicode strings. #55. +- Renamed requests_oauthlib.core to requests_oauthlib.oauth1_auth for consistency. #79. +- Added Facebook compliance fix and access_token_response hook to OAuth2Session. #63. +- Added LinkedIn compliance fix. +- Added refresh_token_response compliance hook, invoked before parsing the refresh token. +- Correctly limit compliance hooks to running only once! +- Content type guessing should only be done when no content type is given +- OAuth1 now updates r.headers instead of replacing it with non case insensitive dict +- Remove last use of Response.content (in OAuth1Session). #44. +- State param can now be supplied in OAuth2Session.authorize_url + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..86c5aeb4e9160b3599f0cf3a249ba2d606cc316f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/RECORD @@ -0,0 +1,36 @@ +requests_oauthlib-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +requests_oauthlib-1.3.1.dist-info/LICENSE,sha256=rgGEavrYqCkf5qCJZvMBWvmo_2ddhLmB-Xk8Ei94dug,745 +requests_oauthlib-1.3.1.dist-info/METADATA,sha256=xlgyoPqiXskknzuvbDx1-CiMjbjCpJ2OkxM_uQgQ6lo,10105 +requests_oauthlib-1.3.1.dist-info/RECORD,, +requests_oauthlib-1.3.1.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110 +requests_oauthlib-1.3.1.dist-info/top_level.txt,sha256=vx1R42DWBO64h6iu8Gco0F01TVTPWXSRWBaV1GwVRTQ,18 +requests_oauthlib/__init__.py,sha256=j3FXxxzppgvMvHj2v9csJtfEXt5QWeUODk6TmKTtopE,529 +requests_oauthlib/__pycache__/__init__.cpython-310.pyc,, +requests_oauthlib/__pycache__/oauth1_auth.cpython-310.pyc,, +requests_oauthlib/__pycache__/oauth1_session.cpython-310.pyc,, +requests_oauthlib/__pycache__/oauth2_auth.cpython-310.pyc,, +requests_oauthlib/__pycache__/oauth2_session.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__init__.py,sha256=M0zZXYmddhdiVVtazEC23tmPYP4MDaeBabKh9FiAyGc,398 +requests_oauthlib/compliance_fixes/__pycache__/__init__.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/douban.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/ebay.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/facebook.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/fitbit.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/instagram.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/mailchimp.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/plentymarkets.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/slack.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/__pycache__/weibo.cpython-310.pyc,, +requests_oauthlib/compliance_fixes/douban.py,sha256=Ilfc1jTjCD66rPFrPf97g2D8Gb-MjoNuXqSGmaBVAn0,472 +requests_oauthlib/compliance_fixes/ebay.py,sha256=bLaGRBG4Pkoac2V4gme1-3pbRYcxvfAGyPID7K6xIZ8,890 +requests_oauthlib/compliance_fixes/facebook.py,sha256=V6_2BQnyBKcwTWDRqDTbJQcJj4Rd_XMTAlDgGiFTQf4,1119 +requests_oauthlib/compliance_fixes/fitbit.py,sha256=rgA4MrYKHqeNOfCGL0pdG3kgum6rzh1QMvgIHL_EOAE,905 +requests_oauthlib/compliance_fixes/instagram.py,sha256=LO55o9VrmeegJOCzz2-QqMlneXS6YY_33ulA_-cG1pI,948 +requests_oauthlib/compliance_fixes/mailchimp.py,sha256=nTdyttxiTxdAzbC72XZb1_uV4ebVOUvQDpDbAmBTqvQ,757 +requests_oauthlib/compliance_fixes/plentymarkets.py,sha256=HnROrco-Z9EvGEjHw3fn-7UxxC8G2GKB8Yjda3es7Yw,796 +requests_oauthlib/compliance_fixes/slack.py,sha256=YDz9DQ3ukNgbyy1X4JIPAhTKKMwMf8R8THxnzhm79zE,1453 +requests_oauthlib/compliance_fixes/weibo.py,sha256=yMvmc2xGWsaxZZNT3XYdJhDuxXJ99N6rO0n3d2cP9MA,444 +requests_oauthlib/oauth1_auth.py,sha256=yq-3SxMvPa1Ux-dm_a2mC32TDKdGGT2XJJuu3d4QtRo,3737 +requests_oauthlib/oauth1_session.py,sha256=JPThdYoaDbc-I6aH7-UZKvFZ6B1ySvBlUkMqa6TcLpE,17055 +requests_oauthlib/oauth2_auth.py,sha256=uYT7ueHDG9TYR73yIFCX8TbquOz44p21lQYPCVw4gn8,1548 +requests_oauthlib/oauth2_session.py,sha256=lIuu5PbiVYfSrEiJ38H4QWh0maKEqwVUc3sU6hXXXmE,21992 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..0b18a281107a0448a9980396d9d324ea2aa7a7f8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..55d4f9073fa48c720fbd093474efb8b1e18bcf02 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib-1.3.1.dist-info/top_level.txt @@ -0,0 +1 @@ +requests_oauthlib diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0d3e49f99134375de6d06fd1af5f705c86e118a5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__init__.py @@ -0,0 +1,19 @@ +import logging + +from .oauth1_auth import OAuth1 +from .oauth1_session import OAuth1Session +from .oauth2_auth import OAuth2 +from .oauth2_session import OAuth2Session, TokenUpdated + +__version__ = "1.3.1" + +import requests + +if requests.__version__ < "2.0.0": + msg = ( + "You are using requests version %s, which is older than " + "requests-oauthlib expects, please upgrade to 2.0.0 or later." + ) + raise Warning(msg % requests.__version__) + +logging.getLogger("requests_oauthlib").addHandler(logging.NullHandler()) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d5395322f97ff5fcfb93f413224b0dbbc893982 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_auth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18d55da7178e26b8123b038283cdd23a76ba3c0b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_auth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_session.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_session.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1159ef5535616dfc3a6b68e718ca96dfd30b965 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth1_session.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_auth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9961ef8ab8e9d5b866c1a9f99aaf8b3cad7ffa4c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_auth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_session.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_session.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b162a2f0be635de7c12d9654974710e189423bb1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/__pycache__/oauth2_session.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0e8e3ac84f7e8948bfe542da86756270118e8407 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__init__.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import + +from .facebook import facebook_compliance_fix +from .fitbit import fitbit_compliance_fix +from .slack import slack_compliance_fix +from .instagram import instagram_compliance_fix +from .mailchimp import mailchimp_compliance_fix +from .weibo import weibo_compliance_fix +from .plentymarkets import plentymarkets_compliance_fix +from .ebay import ebay_compliance_fix diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22f8cb8e3f5cac8c51881136975a009aa459bb9d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/douban.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/douban.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..262ee7664f29e44bb25c22c76b712deea16fcf19 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/douban.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/ebay.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/ebay.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0df141d78e73f16cd9e8b51a4e2666619d037d7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/ebay.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/facebook.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/facebook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2c86b720867d63f1bd5cf677c4306bbfb658f76 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/facebook.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/fitbit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/fitbit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fa120f084bc743a12f984661272f0803c31ce63 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/fitbit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/instagram.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/instagram.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1b67b22289e32684ac0b7c4ea432d8c2df146c5e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/instagram.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/mailchimp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/mailchimp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4b23b624f04b710d4b6a75e52fd566af4916825 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/mailchimp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/plentymarkets.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/plentymarkets.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..098477f6a3995bfbd87fbbe66035cc19ebfade8b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/plentymarkets.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/slack.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/slack.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f58cdf16fd600d9236d1711fd5e9234c194a931 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/slack.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/weibo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/weibo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36a71ed6a3d903baa6d8916eb65b8292d6078782 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/__pycache__/weibo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/douban.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/douban.py new file mode 100644 index 0000000000000000000000000000000000000000..ecc57b08181dead8405b59b551b2fd06e2cfe207 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/douban.py @@ -0,0 +1,17 @@ +import json + +from oauthlib.common import to_unicode + + +def douban_compliance_fix(session): + def fix_token_type(r): + token = json.loads(r.text) + token.setdefault("token_type", "Bearer") + fixed_token = json.dumps(token) + r._content = to_unicode(fixed_token).encode("utf-8") + return r + + session._client_default_token_placement = "query" + session.register_compliance_hook("access_token_response", fix_token_type) + + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/ebay.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/ebay.py new file mode 100644 index 0000000000000000000000000000000000000000..4aa423b3fe8b5f403280a4ad37f8d4b4ae9b1291 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/ebay.py @@ -0,0 +1,23 @@ +import json +from oauthlib.common import to_unicode + + +def ebay_compliance_fix(session): + def _compliance_fix(response): + token = json.loads(response.text) + + # eBay responds with non-compliant token types. + # https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html + # https://developer.ebay.com/api-docs/static/oauth-auth-code-grant-request.html + # Modify these to be "Bearer". + if token.get("token_type") in ["Application Access Token", "User Access Token"]: + token["token_type"] = "Bearer" + fixed_token = json.dumps(token) + response._content = to_unicode(fixed_token).encode("utf-8") + + return response + + session.register_compliance_hook("access_token_response", _compliance_fix) + session.register_compliance_hook("refresh_token_response", _compliance_fix) + + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/facebook.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/facebook.py new file mode 100644 index 0000000000000000000000000000000000000000..90e792127280d67262d6120b7711a2dd90e85171 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/facebook.py @@ -0,0 +1,33 @@ +from json import dumps + +try: + from urlparse import parse_qsl +except ImportError: + from urllib.parse import parse_qsl + +from oauthlib.common import to_unicode + + +def facebook_compliance_fix(session): + def _compliance_fix(r): + # if Facebook claims to be sending us json, let's trust them. + if "application/json" in r.headers.get("content-type", {}): + return r + + # Facebook returns a content-type of text/plain when sending their + # x-www-form-urlencoded responses, along with a 200. If not, let's + # assume we're getting JSON and bail on the fix. + if "text/plain" in r.headers.get("content-type", {}) and r.status_code == 200: + token = dict(parse_qsl(r.text, keep_blank_values=True)) + else: + return r + + expires = token.get("expires") + if expires is not None: + token["expires_in"] = expires + token["token_type"] = "Bearer" + r._content = to_unicode(dumps(token)).encode("UTF-8") + return r + + session.register_compliance_hook("access_token_response", _compliance_fix) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/fitbit.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/fitbit.py new file mode 100644 index 0000000000000000000000000000000000000000..7e6270240173dee3dbc3fe4486dafcaa84f067fb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/fitbit.py @@ -0,0 +1,25 @@ +""" +The Fitbit API breaks from the OAuth2 RFC standard by returning an "errors" +object list, rather than a single "error" string. This puts hooks in place so +that oauthlib can process an error in the results from access token and refresh +token responses. This is necessary to prevent getting the generic red herring +MissingTokenError. +""" + +from json import loads, dumps + +from oauthlib.common import to_unicode + + +def fitbit_compliance_fix(session): + def _missing_error(r): + token = loads(r.text) + if "errors" in token: + # Set the error to the first one we have + token["error"] = token["errors"][0]["errorType"] + r._content = to_unicode(dumps(token)).encode("UTF-8") + return r + + session.register_compliance_hook("access_token_response", _missing_error) + session.register_compliance_hook("refresh_token_response", _missing_error) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/instagram.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/instagram.py new file mode 100644 index 0000000000000000000000000000000000000000..4e07fe08b57575e7578cc8ec22bcfdda2db83c37 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/instagram.py @@ -0,0 +1,26 @@ +try: + from urlparse import urlparse, parse_qs +except ImportError: + from urllib.parse import urlparse, parse_qs + +from oauthlib.common import add_params_to_uri + + +def instagram_compliance_fix(session): + def _non_compliant_param_name(url, headers, data): + # If the user has already specified the token in the URL + # then there's nothing to do. + # If the specified token is different from ``session.access_token``, + # we assume the user intends to override the access token. + url_query = dict(parse_qs(urlparse(url).query)) + token = url_query.get("access_token") + if token: + # Nothing to do, just return. + return url, headers, data + + token = [("access_token", session.access_token)] + url = add_params_to_uri(url, token) + return url, headers, data + + session.register_compliance_hook("protected_request", _non_compliant_param_name) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/mailchimp.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/mailchimp.py new file mode 100644 index 0000000000000000000000000000000000000000..c69ce9fdae691948c623d7f6e1e5122d95e2fcf3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/mailchimp.py @@ -0,0 +1,23 @@ +import json + +from oauthlib.common import to_unicode + + +def mailchimp_compliance_fix(session): + def _null_scope(r): + token = json.loads(r.text) + if "scope" in token and token["scope"] is None: + token.pop("scope") + r._content = to_unicode(json.dumps(token)).encode("utf-8") + return r + + def _non_zero_expiration(r): + token = json.loads(r.text) + if "expires_in" in token and token["expires_in"] == 0: + token["expires_in"] = 3600 + r._content = to_unicode(json.dumps(token)).encode("utf-8") + return r + + session.register_compliance_hook("access_token_response", _null_scope) + session.register_compliance_hook("access_token_response", _non_zero_expiration) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/plentymarkets.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/plentymarkets.py new file mode 100644 index 0000000000000000000000000000000000000000..9f605f058cc1045268c8722cd8cceeb8988e8233 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/plentymarkets.py @@ -0,0 +1,29 @@ +from json import dumps, loads +import re + +from oauthlib.common import to_unicode + + +def plentymarkets_compliance_fix(session): + def _to_snake_case(n): + return re.sub("(.)([A-Z][a-z]+)", r"\1_\2", n).lower() + + def _compliance_fix(r): + # Plenty returns the Token in CamelCase instead of _ + if ( + "application/json" in r.headers.get("content-type", {}) + and r.status_code == 200 + ): + token = loads(r.text) + else: + return r + + fixed_token = {} + for k, v in token.items(): + fixed_token[_to_snake_case(k)] = v + + r._content = to_unicode(dumps(fixed_token)).encode("UTF-8") + return r + + session.register_compliance_hook("access_token_response", _compliance_fix) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/slack.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/slack.py new file mode 100644 index 0000000000000000000000000000000000000000..3f574b03adf7ba0f5ca05eca312e48209e7ff139 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/slack.py @@ -0,0 +1,37 @@ +try: + from urlparse import urlparse, parse_qs +except ImportError: + from urllib.parse import urlparse, parse_qs + +from oauthlib.common import add_params_to_uri + + +def slack_compliance_fix(session): + def _non_compliant_param_name(url, headers, data): + # If the user has already specified the token, either in the URL + # or in a data dictionary, then there's nothing to do. + # If the specified token is different from ``session.access_token``, + # we assume the user intends to override the access token. + url_query = dict(parse_qs(urlparse(url).query)) + token = url_query.get("token") + if not token and isinstance(data, dict): + token = data.get("token") + + if token: + # Nothing to do, just return. + return url, headers, data + + if not data: + data = {"token": session.access_token} + elif isinstance(data, dict): + data["token"] = session.access_token + else: + # ``data`` is something other than a dict: maybe a stream, + # maybe a file object, maybe something else. We can't easily + # modify it, so we'll set the token by modifying the URL instead. + token = [("token", session.access_token)] + url = add_params_to_uri(url, token) + return url, headers, data + + session.register_compliance_hook("protected_request", _non_compliant_param_name) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/weibo.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/weibo.py new file mode 100644 index 0000000000000000000000000000000000000000..6733abeb15b2a4e512c773498ca2f07c7ef4d09c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/compliance_fixes/weibo.py @@ -0,0 +1,15 @@ +from json import loads, dumps + +from oauthlib.common import to_unicode + + +def weibo_compliance_fix(session): + def _missing_token_type(r): + token = loads(r.text) + token["token_type"] = "Bearer" + r._content = to_unicode(dumps(token)).encode("UTF-8") + return r + + session._client.default_token_placement = "query" + session.register_compliance_hook("access_token_response", _missing_token_type) + return session diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_auth.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_auth.py new file mode 100644 index 0000000000000000000000000000000000000000..cfbbd5902c488da3ca169f1776b932c1bccf35c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_auth.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import logging + +from oauthlib.common import extract_params +from oauthlib.oauth1 import Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER +from oauthlib.oauth1 import SIGNATURE_TYPE_BODY +from requests.compat import is_py3 +from requests.utils import to_native_string +from requests.auth import AuthBase + +CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded" +CONTENT_TYPE_MULTI_PART = "multipart/form-data" + +if is_py3: + unicode = str + +log = logging.getLogger(__name__) + +# OBS!: Correct signing of requests are conditional on invoking OAuth1 +# as the last step of preparing a request, or at least having the +# content-type set properly. +class OAuth1(AuthBase): + """Signs the request using OAuth 1 (RFC5849)""" + + client_class = Client + + def __init__( + self, + client_key, + client_secret=None, + resource_owner_key=None, + resource_owner_secret=None, + callback_uri=None, + signature_method=SIGNATURE_HMAC, + signature_type=SIGNATURE_TYPE_AUTH_HEADER, + rsa_key=None, + verifier=None, + decoding="utf-8", + client_class=None, + force_include_body=False, + **kwargs + ): + + try: + signature_type = signature_type.upper() + except AttributeError: + pass + + client_class = client_class or self.client_class + + self.force_include_body = force_include_body + + self.client = client_class( + client_key, + client_secret, + resource_owner_key, + resource_owner_secret, + callback_uri, + signature_method, + signature_type, + rsa_key, + verifier, + decoding=decoding, + **kwargs + ) + + def __call__(self, r): + """Add OAuth parameters to the request. + + Parameters may be included from the body if the content-type is + urlencoded, if no content type is set a guess is made. + """ + # Overwriting url is safe here as request will not modify it past + # this point. + log.debug("Signing request %s using client %s", r, self.client) + + content_type = r.headers.get("Content-Type", "") + if ( + not content_type + and extract_params(r.body) + or self.client.signature_type == SIGNATURE_TYPE_BODY + ): + content_type = CONTENT_TYPE_FORM_URLENCODED + if not isinstance(content_type, unicode): + content_type = content_type.decode("utf-8") + + is_form_encoded = CONTENT_TYPE_FORM_URLENCODED in content_type + + log.debug( + "Including body in call to sign: %s", + is_form_encoded or self.force_include_body, + ) + + if is_form_encoded: + r.headers["Content-Type"] = CONTENT_TYPE_FORM_URLENCODED + r.url, headers, r.body = self.client.sign( + unicode(r.url), unicode(r.method), r.body or "", r.headers + ) + elif self.force_include_body: + # To allow custom clients to work on non form encoded bodies. + r.url, headers, r.body = self.client.sign( + unicode(r.url), unicode(r.method), r.body or "", r.headers + ) + else: + # Omit body data in the signing of non form-encoded requests + r.url, headers, _ = self.client.sign( + unicode(r.url), unicode(r.method), None, r.headers + ) + + r.prepare_headers(headers) + r.url = to_native_string(r.url) + log.debug("Updated url: %s", r.url) + log.debug("Updated headers: %s", headers) + log.debug("Updated body: %r", r.body) + return r diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_session.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_session.py new file mode 100644 index 0000000000000000000000000000000000000000..88f2853ca083ca810da1b9eaa93295105492a3e8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth1_session.py @@ -0,0 +1,400 @@ +from __future__ import unicode_literals + +try: + from urlparse import urlparse +except ImportError: + from urllib.parse import urlparse + +import logging + +from oauthlib.common import add_params_to_uri +from oauthlib.common import urldecode as _urldecode +from oauthlib.oauth1 import SIGNATURE_HMAC, SIGNATURE_RSA, SIGNATURE_TYPE_AUTH_HEADER +import requests + +from . import OAuth1 + + +log = logging.getLogger(__name__) + + +def urldecode(body): + """Parse query or json to python dictionary""" + try: + return _urldecode(body) + except Exception: + import json + + return json.loads(body) + + +class TokenRequestDenied(ValueError): + def __init__(self, message, response): + super(TokenRequestDenied, self).__init__(message) + self.response = response + + @property + def status_code(self): + """For backwards-compatibility purposes""" + return self.response.status_code + + +class TokenMissing(ValueError): + def __init__(self, message, response): + super(TokenMissing, self).__init__(message) + self.response = response + + +class VerifierMissing(ValueError): + pass + + +class OAuth1Session(requests.Session): + """Request signing and convenience methods for the oauth dance. + + What is the difference between OAuth1Session and OAuth1? + + OAuth1Session actually uses OAuth1 internally and its purpose is to assist + in the OAuth workflow through convenience methods to prepare authorization + URLs and parse the various token and redirection responses. It also provide + rudimentary validation of responses. + + An example of the OAuth workflow using a basic CLI app and Twitter. + + >>> # Credentials obtained during the registration. + >>> client_key = 'client key' + >>> client_secret = 'secret' + >>> callback_uri = 'https://127.0.0.1/callback' + >>> + >>> # Endpoints found in the OAuth provider API documentation + >>> request_token_url = 'https://api.twitter.com/oauth/request_token' + >>> authorization_url = 'https://api.twitter.com/oauth/authorize' + >>> access_token_url = 'https://api.twitter.com/oauth/access_token' + >>> + >>> oauth_session = OAuth1Session(client_key,client_secret=client_secret, callback_uri=callback_uri) + >>> + >>> # First step, fetch the request token. + >>> oauth_session.fetch_request_token(request_token_url) + { + 'oauth_token': 'kjerht2309u', + 'oauth_token_secret': 'lsdajfh923874', + } + >>> + >>> # Second step. Follow this link and authorize + >>> oauth_session.authorization_url(authorization_url) + 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&oauth_callback=https%3A%2F%2F127.0.0.1%2Fcallback' + >>> + >>> # Third step. Fetch the access token + >>> redirect_response = raw_input('Paste the full redirect URL here.') + >>> oauth_session.parse_authorization_response(redirect_response) + { + 'oauth_token: 'kjerht2309u', + 'oauth_token_secret: 'lsdajfh923874', + 'oauth_verifier: 'w34o8967345', + } + >>> oauth_session.fetch_access_token(access_token_url) + { + 'oauth_token': 'sdf0o9823sjdfsdf', + 'oauth_token_secret': '2kjshdfp92i34asdasd', + } + >>> # Done. You can now make OAuth requests. + >>> status_url = 'http://api.twitter.com/1/statuses/update.json' + >>> new_status = {'status': 'hello world!'} + >>> oauth_session.post(status_url, data=new_status) + <Response [200]> + """ + + def __init__( + self, + client_key, + client_secret=None, + resource_owner_key=None, + resource_owner_secret=None, + callback_uri=None, + signature_method=SIGNATURE_HMAC, + signature_type=SIGNATURE_TYPE_AUTH_HEADER, + rsa_key=None, + verifier=None, + client_class=None, + force_include_body=False, + **kwargs + ): + """Construct the OAuth 1 session. + + :param client_key: A client specific identifier. + :param client_secret: A client specific secret used to create HMAC and + plaintext signatures. + :param resource_owner_key: A resource owner key, also referred to as + request token or access token depending on + when in the workflow it is used. + :param resource_owner_secret: A resource owner secret obtained with + either a request or access token. Often + referred to as token secret. + :param callback_uri: The URL the user is redirect back to after + authorization. + :param signature_method: Signature methods determine how the OAuth + signature is created. The three options are + oauthlib.oauth1.SIGNATURE_HMAC (default), + oauthlib.oauth1.SIGNATURE_RSA and + oauthlib.oauth1.SIGNATURE_PLAIN. + :param signature_type: Signature type decides where the OAuth + parameters are added. Either in the + Authorization header (default) or to the URL + query parameters or the request body. Defined as + oauthlib.oauth1.SIGNATURE_TYPE_AUTH_HEADER, + oauthlib.oauth1.SIGNATURE_TYPE_QUERY and + oauthlib.oauth1.SIGNATURE_TYPE_BODY + respectively. + :param rsa_key: The private RSA key as a string. Can only be used with + signature_method=oauthlib.oauth1.SIGNATURE_RSA. + :param verifier: A verifier string to prove authorization was granted. + :param client_class: A subclass of `oauthlib.oauth1.Client` to use with + `requests_oauthlib.OAuth1` instead of the default + :param force_include_body: Always include the request body in the + signature creation. + :param **kwargs: Additional keyword arguments passed to `OAuth1` + """ + super(OAuth1Session, self).__init__() + self._client = OAuth1( + client_key, + client_secret=client_secret, + resource_owner_key=resource_owner_key, + resource_owner_secret=resource_owner_secret, + callback_uri=callback_uri, + signature_method=signature_method, + signature_type=signature_type, + rsa_key=rsa_key, + verifier=verifier, + client_class=client_class, + force_include_body=force_include_body, + **kwargs + ) + self.auth = self._client + + @property + def token(self): + oauth_token = self._client.client.resource_owner_key + oauth_token_secret = self._client.client.resource_owner_secret + oauth_verifier = self._client.client.verifier + + token_dict = {} + if oauth_token: + token_dict["oauth_token"] = oauth_token + if oauth_token_secret: + token_dict["oauth_token_secret"] = oauth_token_secret + if oauth_verifier: + token_dict["oauth_verifier"] = oauth_verifier + + return token_dict + + @token.setter + def token(self, value): + self._populate_attributes(value) + + @property + def authorized(self): + """Boolean that indicates whether this session has an OAuth token + or not. If `self.authorized` is True, you can reasonably expect + OAuth-protected requests to the resource to succeed. If + `self.authorized` is False, you need the user to go through the OAuth + authentication dance before OAuth-protected requests to the resource + will succeed. + """ + if self._client.client.signature_method == SIGNATURE_RSA: + # RSA only uses resource_owner_key + return bool(self._client.client.resource_owner_key) + else: + # other methods of authentication use all three pieces + return ( + bool(self._client.client.client_secret) + and bool(self._client.client.resource_owner_key) + and bool(self._client.client.resource_owner_secret) + ) + + def authorization_url(self, url, request_token=None, **kwargs): + """Create an authorization URL by appending request_token and optional + kwargs to url. + + This is the second step in the OAuth 1 workflow. The user should be + redirected to this authorization URL, grant access to you, and then + be redirected back to you. The redirection back can either be specified + during client registration or by supplying a callback URI per request. + + :param url: The authorization endpoint URL. + :param request_token: The previously obtained request token. + :param kwargs: Optional parameters to append to the URL. + :returns: The authorization URL with new parameters embedded. + + An example using a registered default callback URI. + + >>> request_token_url = 'https://api.twitter.com/oauth/request_token' + >>> authorization_url = 'https://api.twitter.com/oauth/authorize' + >>> oauth_session = OAuth1Session('client-key', client_secret='secret') + >>> oauth_session.fetch_request_token(request_token_url) + { + 'oauth_token': 'sdf0o9823sjdfsdf', + 'oauth_token_secret': '2kjshdfp92i34asdasd', + } + >>> oauth_session.authorization_url(authorization_url) + 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf' + >>> oauth_session.authorization_url(authorization_url, foo='bar') + 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&foo=bar' + + An example using an explicit callback URI. + + >>> request_token_url = 'https://api.twitter.com/oauth/request_token' + >>> authorization_url = 'https://api.twitter.com/oauth/authorize' + >>> oauth_session = OAuth1Session('client-key', client_secret='secret', callback_uri='https://127.0.0.1/callback') + >>> oauth_session.fetch_request_token(request_token_url) + { + 'oauth_token': 'sdf0o9823sjdfsdf', + 'oauth_token_secret': '2kjshdfp92i34asdasd', + } + >>> oauth_session.authorization_url(authorization_url) + 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&oauth_callback=https%3A%2F%2F127.0.0.1%2Fcallback' + """ + kwargs["oauth_token"] = request_token or self._client.client.resource_owner_key + log.debug("Adding parameters %s to url %s", kwargs, url) + return add_params_to_uri(url, kwargs.items()) + + def fetch_request_token(self, url, realm=None, **request_kwargs): + r"""Fetch a request token. + + This is the first step in the OAuth 1 workflow. A request token is + obtained by making a signed post request to url. The token is then + parsed from the application/x-www-form-urlencoded response and ready + to be used to construct an authorization url. + + :param url: The request token endpoint URL. + :param realm: A list of realms to request access to. + :param \*\*request_kwargs: Optional arguments passed to ''post'' + function in ''requests.Session'' + :returns: The response in dict format. + + Note that a previously set callback_uri will be reset for your + convenience, or else signature creation will be incorrect on + consecutive requests. + + >>> request_token_url = 'https://api.twitter.com/oauth/request_token' + >>> oauth_session = OAuth1Session('client-key', client_secret='secret') + >>> oauth_session.fetch_request_token(request_token_url) + { + 'oauth_token': 'sdf0o9823sjdfsdf', + 'oauth_token_secret': '2kjshdfp92i34asdasd', + } + """ + self._client.client.realm = " ".join(realm) if realm else None + token = self._fetch_token(url, **request_kwargs) + log.debug("Resetting callback_uri and realm (not needed in next phase).") + self._client.client.callback_uri = None + self._client.client.realm = None + return token + + def fetch_access_token(self, url, verifier=None, **request_kwargs): + """Fetch an access token. + + This is the final step in the OAuth 1 workflow. An access token is + obtained using all previously obtained credentials, including the + verifier from the authorization step. + + Note that a previously set verifier will be reset for your + convenience, or else signature creation will be incorrect on + consecutive requests. + + >>> access_token_url = 'https://api.twitter.com/oauth/access_token' + >>> redirect_response = 'https://127.0.0.1/callback?oauth_token=kjerht2309uf&oauth_token_secret=lsdajfh923874&oauth_verifier=w34o8967345' + >>> oauth_session = OAuth1Session('client-key', client_secret='secret') + >>> oauth_session.parse_authorization_response(redirect_response) + { + 'oauth_token: 'kjerht2309u', + 'oauth_token_secret: 'lsdajfh923874', + 'oauth_verifier: 'w34o8967345', + } + >>> oauth_session.fetch_access_token(access_token_url) + { + 'oauth_token': 'sdf0o9823sjdfsdf', + 'oauth_token_secret': '2kjshdfp92i34asdasd', + } + """ + if verifier: + self._client.client.verifier = verifier + if not getattr(self._client.client, "verifier", None): + raise VerifierMissing("No client verifier has been set.") + token = self._fetch_token(url, **request_kwargs) + log.debug("Resetting verifier attribute, should not be used anymore.") + self._client.client.verifier = None + return token + + def parse_authorization_response(self, url): + """Extract parameters from the post authorization redirect response URL. + + :param url: The full URL that resulted from the user being redirected + back from the OAuth provider to you, the client. + :returns: A dict of parameters extracted from the URL. + + >>> redirect_response = 'https://127.0.0.1/callback?oauth_token=kjerht2309uf&oauth_token_secret=lsdajfh923874&oauth_verifier=w34o8967345' + >>> oauth_session = OAuth1Session('client-key', client_secret='secret') + >>> oauth_session.parse_authorization_response(redirect_response) + { + 'oauth_token: 'kjerht2309u', + 'oauth_token_secret: 'lsdajfh923874', + 'oauth_verifier: 'w34o8967345', + } + """ + log.debug("Parsing token from query part of url %s", url) + token = dict(urldecode(urlparse(url).query)) + log.debug("Updating internal client token attribute.") + self._populate_attributes(token) + self.token = token + return token + + def _populate_attributes(self, token): + if "oauth_token" in token: + self._client.client.resource_owner_key = token["oauth_token"] + else: + raise TokenMissing( + "Response does not contain a token: {resp}".format(resp=token), token + ) + if "oauth_token_secret" in token: + self._client.client.resource_owner_secret = token["oauth_token_secret"] + if "oauth_verifier" in token: + self._client.client.verifier = token["oauth_verifier"] + + def _fetch_token(self, url, **request_kwargs): + log.debug("Fetching token from %s using client %s", url, self._client.client) + r = self.post(url, **request_kwargs) + + if r.status_code >= 400: + error = "Token request failed with code %s, response was '%s'." + raise TokenRequestDenied(error % (r.status_code, r.text), r) + + log.debug('Decoding token from response "%s"', r.text) + try: + token = dict(urldecode(r.text.strip())) + except ValueError as e: + error = ( + "Unable to decode token from token response. " + "This is commonly caused by an unsuccessful request where" + " a non urlencoded error message is returned. " + "The decoding error was %s" + "" % e + ) + raise ValueError(error) + + log.debug("Obtained token %s", token) + log.debug("Updating internal client attributes from token data.") + self._populate_attributes(token) + self.token = token + return token + + def rebuild_auth(self, prepared_request, response): + """ + When being redirected we should always strip Authorization + header, since nonce may not be reused as per OAuth spec. + """ + if "Authorization" in prepared_request.headers: + # If we get redirected to a new host, we should strip out + # any authentication headers. + prepared_request.headers.pop("Authorization", True) + prepared_request.prepare_auth(self.auth) + return diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_auth.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_auth.py new file mode 100644 index 0000000000000000000000000000000000000000..b880f72f5851dea48c36824267675674a954f843 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_auth.py @@ -0,0 +1,37 @@ +from __future__ import unicode_literals +from oauthlib.oauth2 import WebApplicationClient, InsecureTransportError +from oauthlib.oauth2 import is_secure_transport +from requests.auth import AuthBase + + +class OAuth2(AuthBase): + """Adds proof of authorization (OAuth2 token) to the request.""" + + def __init__(self, client_id=None, client=None, token=None): + """Construct a new OAuth 2 authorization object. + + :param client_id: Client id obtained during registration + :param client: :class:`oauthlib.oauth2.Client` to be used. Default is + WebApplicationClient which is useful for any + hosted application but not mobile or desktop. + :param token: Token dictionary, must include access_token + and token_type. + """ + self._client = client or WebApplicationClient(client_id, token=token) + if token: + for k, v in token.items(): + setattr(self._client, k, v) + + def __call__(self, r): + """Append an OAuth 2 token to the request. + + Note that currently HTTPS is required for all requests. There may be + a token type that allows for plain HTTP in the future and then this + should be updated to allow plain HTTP on a white list basis. + """ + if not is_secure_transport(r.url): + raise InsecureTransportError() + r.url, r.headers, r.body = self._client.add_token( + r.url, http_method=r.method, body=r.body, headers=r.headers + ) + return r diff --git a/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_session.py b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_session.py new file mode 100644 index 0000000000000000000000000000000000000000..db4468089bdf8cdede79d3e8a771c053049c3484 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/requests_oauthlib/oauth2_session.py @@ -0,0 +1,540 @@ +from __future__ import unicode_literals + +import logging + +from oauthlib.common import generate_token, urldecode +from oauthlib.oauth2 import WebApplicationClient, InsecureTransportError +from oauthlib.oauth2 import LegacyApplicationClient +from oauthlib.oauth2 import TokenExpiredError, is_secure_transport +import requests + +log = logging.getLogger(__name__) + + +class TokenUpdated(Warning): + def __init__(self, token): + super(TokenUpdated, self).__init__() + self.token = token + + +class OAuth2Session(requests.Session): + """Versatile OAuth 2 extension to :class:`requests.Session`. + + Supports any grant type adhering to :class:`oauthlib.oauth2.Client` spec + including the four core OAuth 2 grants. + + Can be used to create authorization urls, fetch tokens and access protected + resources using the :class:`requests.Session` interface you are used to. + + - :class:`oauthlib.oauth2.WebApplicationClient` (default): Authorization Code Grant + - :class:`oauthlib.oauth2.MobileApplicationClient`: Implicit Grant + - :class:`oauthlib.oauth2.LegacyApplicationClient`: Password Credentials Grant + - :class:`oauthlib.oauth2.BackendApplicationClient`: Client Credentials Grant + + Note that the only time you will be using Implicit Grant from python is if + you are driving a user agent able to obtain URL fragments. + """ + + def __init__( + self, + client_id=None, + client=None, + auto_refresh_url=None, + auto_refresh_kwargs=None, + scope=None, + redirect_uri=None, + token=None, + state=None, + token_updater=None, + **kwargs + ): + """Construct a new OAuth 2 client session. + + :param client_id: Client id obtained during registration + :param client: :class:`oauthlib.oauth2.Client` to be used. Default is + WebApplicationClient which is useful for any + hosted application but not mobile or desktop. + :param scope: List of scopes you wish to request access to + :param redirect_uri: Redirect URI you registered as callback + :param token: Token dictionary, must include access_token + and token_type. + :param state: State string used to prevent CSRF. This will be given + when creating the authorization url and must be supplied + when parsing the authorization response. + Can be either a string or a no argument callable. + :auto_refresh_url: Refresh token endpoint URL, must be HTTPS. Supply + this if you wish the client to automatically refresh + your access tokens. + :auto_refresh_kwargs: Extra arguments to pass to the refresh token + endpoint. + :token_updater: Method with one argument, token, to be used to update + your token database on automatic token refresh. If not + set a TokenUpdated warning will be raised when a token + has been refreshed. This warning will carry the token + in its token argument. + :param kwargs: Arguments to pass to the Session constructor. + """ + super(OAuth2Session, self).__init__(**kwargs) + self._client = client or WebApplicationClient(client_id, token=token) + self.token = token or {} + self.scope = scope + self.redirect_uri = redirect_uri + self.state = state or generate_token + self._state = state + self.auto_refresh_url = auto_refresh_url + self.auto_refresh_kwargs = auto_refresh_kwargs or {} + self.token_updater = token_updater + + # Ensure that requests doesn't do any automatic auth. See #278. + # The default behavior can be re-enabled by setting auth to None. + self.auth = lambda r: r + + # Allow customizations for non compliant providers through various + # hooks to adjust requests and responses. + self.compliance_hook = { + "access_token_response": set(), + "refresh_token_response": set(), + "protected_request": set(), + } + + def new_state(self): + """Generates a state string to be used in authorizations.""" + try: + self._state = self.state() + log.debug("Generated new state %s.", self._state) + except TypeError: + self._state = self.state + log.debug("Re-using previously supplied state %s.", self._state) + return self._state + + @property + def client_id(self): + return getattr(self._client, "client_id", None) + + @client_id.setter + def client_id(self, value): + self._client.client_id = value + + @client_id.deleter + def client_id(self): + del self._client.client_id + + @property + def token(self): + return getattr(self._client, "token", None) + + @token.setter + def token(self, value): + self._client.token = value + self._client.populate_token_attributes(value) + + @property + def access_token(self): + return getattr(self._client, "access_token", None) + + @access_token.setter + def access_token(self, value): + self._client.access_token = value + + @access_token.deleter + def access_token(self): + del self._client.access_token + + @property + def authorized(self): + """Boolean that indicates whether this session has an OAuth token + or not. If `self.authorized` is True, you can reasonably expect + OAuth-protected requests to the resource to succeed. If + `self.authorized` is False, you need the user to go through the OAuth + authentication dance before OAuth-protected requests to the resource + will succeed. + """ + return bool(self.access_token) + + def authorization_url(self, url, state=None, **kwargs): + """Form an authorization URL. + + :param url: Authorization endpoint url, must be HTTPS. + :param state: An optional state string for CSRF protection. If not + given it will be generated for you. + :param kwargs: Extra parameters to include. + :return: authorization_url, state + """ + state = state or self.new_state() + return ( + self._client.prepare_request_uri( + url, + redirect_uri=self.redirect_uri, + scope=self.scope, + state=state, + **kwargs + ), + state, + ) + + def fetch_token( + self, + token_url, + code=None, + authorization_response=None, + body="", + auth=None, + username=None, + password=None, + method="POST", + force_querystring=False, + timeout=None, + headers=None, + verify=True, + proxies=None, + include_client_id=None, + client_secret=None, + cert=None, + **kwargs + ): + """Generic method for fetching an access token from the token endpoint. + + If you are using the MobileApplicationClient you will want to use + `token_from_fragment` instead of `fetch_token`. + + The current implementation enforces the RFC guidelines. + + :param token_url: Token endpoint URL, must use HTTPS. + :param code: Authorization code (used by WebApplicationClients). + :param authorization_response: Authorization response URL, the callback + URL of the request back to you. Used by + WebApplicationClients instead of code. + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param auth: An auth tuple or method as accepted by `requests`. + :param username: Username required by LegacyApplicationClients to appear + in the request body. + :param password: Password required by LegacyApplicationClients to appear + in the request body. + :param method: The HTTP method used to make the request. Defaults + to POST, but may also be GET. Other methods should + be added as needed. + :param force_querystring: If True, force the request body to be sent + in the querystring instead. + :param timeout: Timeout of the request in seconds. + :param headers: Dict to default request headers with. + :param verify: Verify SSL certificate. + :param proxies: The `proxies` argument is passed onto `requests`. + :param include_client_id: Should the request body include the + `client_id` parameter. Default is `None`, + which will attempt to autodetect. This can be + forced to always include (True) or never + include (False). + :param client_secret: The `client_secret` paired to the `client_id`. + This is generally required unless provided in the + `auth` tuple. If the value is `None`, it will be + omitted from the request, however if the value is + an empty string, an empty string will be sent. + :param cert: Client certificate to send for OAuth 2.0 Mutual-TLS Client + Authentication (draft-ietf-oauth-mtls). Can either be the + path of a file containing the private key and certificate or + a tuple of two filenames for certificate and key. + :param kwargs: Extra parameters to include in the token request. + :return: A token dict + """ + if not is_secure_transport(token_url): + raise InsecureTransportError() + + if not code and authorization_response: + self._client.parse_request_uri_response( + authorization_response, state=self._state + ) + code = self._client.code + elif not code and isinstance(self._client, WebApplicationClient): + code = self._client.code + if not code: + raise ValueError( + "Please supply either code or " "authorization_response parameters." + ) + + # Earlier versions of this library build an HTTPBasicAuth header out of + # `username` and `password`. The RFC states, however these attributes + # must be in the request body and not the header. + # If an upstream server is not spec compliant and requires them to + # appear as an Authorization header, supply an explicit `auth` header + # to this function. + # This check will allow for empty strings, but not `None`. + # + # References + # 4.3.2 - Resource Owner Password Credentials Grant + # https://tools.ietf.org/html/rfc6749#section-4.3.2 + + if isinstance(self._client, LegacyApplicationClient): + if username is None: + raise ValueError( + "`LegacyApplicationClient` requires both the " + "`username` and `password` parameters." + ) + if password is None: + raise ValueError( + "The required parameter `username` was supplied, " + "but `password` was not." + ) + + # merge username and password into kwargs for `prepare_request_body` + if username is not None: + kwargs["username"] = username + if password is not None: + kwargs["password"] = password + + # is an auth explicitly supplied? + if auth is not None: + # if we're dealing with the default of `include_client_id` (None): + # we will assume the `auth` argument is for an RFC compliant server + # and we should not send the `client_id` in the body. + # This approach allows us to still force the client_id by submitting + # `include_client_id=True` along with an `auth` object. + if include_client_id is None: + include_client_id = False + + # otherwise we may need to create an auth header + else: + # since we don't have an auth header, we MAY need to create one + # it is possible that we want to send the `client_id` in the body + # if so, `include_client_id` should be set to True + # otherwise, we will generate an auth header + if include_client_id is not True: + client_id = self.client_id + if client_id: + log.debug( + 'Encoding `client_id` "%s" with `client_secret` ' + "as Basic auth credentials.", + client_id, + ) + client_secret = client_secret if client_secret is not None else "" + auth = requests.auth.HTTPBasicAuth(client_id, client_secret) + + if include_client_id: + # this was pulled out of the params + # it needs to be passed into prepare_request_body + if client_secret is not None: + kwargs["client_secret"] = client_secret + + body = self._client.prepare_request_body( + code=code, + body=body, + redirect_uri=self.redirect_uri, + include_client_id=include_client_id, + **kwargs + ) + + headers = headers or { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", + } + self.token = {} + request_kwargs = {} + if method.upper() == "POST": + request_kwargs["params" if force_querystring else "data"] = dict( + urldecode(body) + ) + elif method.upper() == "GET": + request_kwargs["params"] = dict(urldecode(body)) + else: + raise ValueError("The method kwarg must be POST or GET.") + + r = self.request( + method=method, + url=token_url, + timeout=timeout, + headers=headers, + auth=auth, + verify=verify, + proxies=proxies, + cert=cert, + **request_kwargs + ) + + log.debug("Request to fetch token completed with status %s.", r.status_code) + log.debug("Request url was %s", r.request.url) + log.debug("Request headers were %s", r.request.headers) + log.debug("Request body was %s", r.request.body) + log.debug("Response headers were %s and content %s.", r.headers, r.text) + log.debug( + "Invoking %d token response hooks.", + len(self.compliance_hook["access_token_response"]), + ) + for hook in self.compliance_hook["access_token_response"]: + log.debug("Invoking hook %s.", hook) + r = hook(r) + + self._client.parse_request_body_response(r.text, scope=self.scope) + self.token = self._client.token + log.debug("Obtained token %s.", self.token) + return self.token + + def token_from_fragment(self, authorization_response): + """Parse token from the URI fragment, used by MobileApplicationClients. + + :param authorization_response: The full URL of the redirect back to you + :return: A token dict + """ + self._client.parse_request_uri_response( + authorization_response, state=self._state + ) + self.token = self._client.token + return self.token + + def refresh_token( + self, + token_url, + refresh_token=None, + body="", + auth=None, + timeout=None, + headers=None, + verify=True, + proxies=None, + **kwargs + ): + """Fetch a new access token using a refresh token. + + :param token_url: The token endpoint, must be HTTPS. + :param refresh_token: The refresh_token to use. + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param auth: An auth tuple or method as accepted by `requests`. + :param timeout: Timeout of the request in seconds. + :param headers: A dict of headers to be used by `requests`. + :param verify: Verify SSL certificate. + :param proxies: The `proxies` argument will be passed to `requests`. + :param kwargs: Extra parameters to include in the token request. + :return: A token dict + """ + if not token_url: + raise ValueError("No token endpoint set for auto_refresh.") + + if not is_secure_transport(token_url): + raise InsecureTransportError() + + refresh_token = refresh_token or self.token.get("refresh_token") + + log.debug( + "Adding auto refresh key word arguments %s.", self.auto_refresh_kwargs + ) + kwargs.update(self.auto_refresh_kwargs) + body = self._client.prepare_refresh_body( + body=body, refresh_token=refresh_token, scope=self.scope, **kwargs + ) + log.debug("Prepared refresh token request body %s", body) + + if headers is None: + headers = { + "Accept": "application/json", + "Content-Type": ("application/x-www-form-urlencoded;charset=UTF-8"), + } + + r = self.post( + token_url, + data=dict(urldecode(body)), + auth=auth, + timeout=timeout, + headers=headers, + verify=verify, + withhold_token=True, + proxies=proxies, + ) + log.debug("Request to refresh token completed with status %s.", r.status_code) + log.debug("Response headers were %s and content %s.", r.headers, r.text) + log.debug( + "Invoking %d token response hooks.", + len(self.compliance_hook["refresh_token_response"]), + ) + for hook in self.compliance_hook["refresh_token_response"]: + log.debug("Invoking hook %s.", hook) + r = hook(r) + + self.token = self._client.parse_request_body_response(r.text, scope=self.scope) + if not "refresh_token" in self.token: + log.debug("No new refresh token given. Re-using old.") + self.token["refresh_token"] = refresh_token + return self.token + + def request( + self, + method, + url, + data=None, + headers=None, + withhold_token=False, + client_id=None, + client_secret=None, + **kwargs + ): + """Intercept all requests and add the OAuth 2 token if present.""" + if not is_secure_transport(url): + raise InsecureTransportError() + if self.token and not withhold_token: + log.debug( + "Invoking %d protected resource request hooks.", + len(self.compliance_hook["protected_request"]), + ) + for hook in self.compliance_hook["protected_request"]: + log.debug("Invoking hook %s.", hook) + url, headers, data = hook(url, headers, data) + + log.debug("Adding token %s to request.", self.token) + try: + url, headers, data = self._client.add_token( + url, http_method=method, body=data, headers=headers + ) + # Attempt to retrieve and save new access token if expired + except TokenExpiredError: + if self.auto_refresh_url: + log.debug( + "Auto refresh is set, attempting to refresh at %s.", + self.auto_refresh_url, + ) + + # We mustn't pass auth twice. + auth = kwargs.pop("auth", None) + if client_id and client_secret and (auth is None): + log.debug( + 'Encoding client_id "%s" with client_secret as Basic auth credentials.', + client_id, + ) + auth = requests.auth.HTTPBasicAuth(client_id, client_secret) + token = self.refresh_token( + self.auto_refresh_url, auth=auth, **kwargs + ) + if self.token_updater: + log.debug( + "Updating token to %s using %s.", token, self.token_updater + ) + self.token_updater(token) + url, headers, data = self._client.add_token( + url, http_method=method, body=data, headers=headers + ) + else: + raise TokenUpdated(token) + else: + raise + + log.debug("Requesting url %s using method %s.", url, method) + log.debug("Supplying headers %s and data %s", headers, data) + log.debug("Passing through key word arguments %s.", kwargs) + return super(OAuth2Session, self).request( + method, url, headers=headers, data=data, **kwargs + ) + + def register_compliance_hook(self, hook_type, hook): + """Register a hook for request/response tweaking. + + Available hooks are: + access_token_response invoked before token parsing. + refresh_token_response invoked before refresh token parsing. + protected_request invoked before making a request. + + If you find a new hook is needed please send a GitHub PR request + or open an issue. + """ + if hook_type not in self.compliance_hook: + raise ValueError( + "Hook type %s is not in %s.", hook_type, self.compliance_hook + ) + self.compliance_hook[hook_type].add(hook) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d53b2cb4de9a09b5ee0325ac0e74a586b93433d2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__init__.py @@ -0,0 +1,33 @@ +r""" +______ _____ _____ _____ __ +| ___ \ ___/ ___|_ _| / _| | | +| |_/ / |__ \ `--. | | | |_ _ __ __ _ _ __ ___ _____ _____ _ __| |__ +| /| __| `--. \ | | | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / +| |\ \| |___/\__/ / | | | | | | | (_| | | | | | | __/\ V V / (_) | | | < +\_| \_\____/\____/ \_/ |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_| +""" + +import django + +__title__ = 'Django REST framework' +__version__ = '3.14.0' +__author__ = 'Tom Christie' +__license__ = 'BSD 3-Clause' +__copyright__ = 'Copyright 2011-2019 Encode OSS Ltd' + +# Version synonym +VERSION = __version__ + +# Header encoding (see RFC5987) +HTTP_HEADER_ENCODING = 'iso-8859-1' + +# Default datetime input and output formats +ISO_8601 = 'iso-8601' + + +if django.VERSION < (3, 2): + default_app_config = 'rest_framework.apps.RestFrameworkConfig' + + +class RemovedInDRF315Warning(PendingDeprecationWarning): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebc0f5b2af473e582bbf298982743805544b74ad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/apps.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b07c38518c703f3ffb3b43c283516b417d7647f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/apps.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/authentication.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/authentication.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25fa8291a628e184d50429118b518aa533ec4a51 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/authentication.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/checks.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/checks.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63c9dbc0fdd0ff22a2dfef0ebc0aed2715451834 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/checks.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a031c04199b183a35c3075e8e1d500eb5bff2782 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/decorators.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/decorators.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a4f8956d40fd51086f57b4fa6aad1a2f5b8db15 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/decorators.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/documentation.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/documentation.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bb8a49404c9df3c590e1685191a3e09a1c9e7d7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/documentation.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61c287d339c5fe426c0919bfba9cb689b54f43e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/fields.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/fields.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f7328ffe6fb7f22f71d19c0f826a78d26d68aef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/fields.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/filters.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/filters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8e5156a6e7dcdc3e788ece8434c2adc22a28e15 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/filters.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/generics.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/generics.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc79f96e2babe18488d64c8784330eeab50bafa7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/generics.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/metadata.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/metadata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3194085d1f9eb6e3a7538d197808ab86da6d9fbe Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/metadata.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/mixins.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/mixins.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d67d698a054da59be254ba9c005c9665bac221a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/mixins.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/negotiation.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/negotiation.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aed6351306c47b376b237a258795334562a3d9c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/negotiation.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/pagination.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/pagination.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8a7ffa5bdd54455ef88a2967c8f1a7aab62c65c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/pagination.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/parsers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/parsers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4a4a54a96301f80fe16c13f67011e8a4b2b27e6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/parsers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/permissions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/permissions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74c6a3f7b98203e4faeff20ee417861acafbc2f2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/permissions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/relations.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/relations.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f94d4391e246d50c801fb9c767265e4574963ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/relations.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/renderers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/renderers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0917258ae55467d20e0c06a0e813b911b2b36c5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/renderers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/request.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/request.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83a8af2d4735ef9ec40b85314e003fe4a703d5ba Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/request.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/response.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/response.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0b9a53e1b1fc60228370111953a6714182b8e85 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/response.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/reverse.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/reverse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a9e74fa82e24ce4ffdc1425694f9760369995c7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/reverse.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/routers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/routers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64efef4860771faeeb69fb4a7e406a6684b4fd31 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/routers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/serializers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2fdec719d3695c50073b920734079a197930311 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/serializers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/settings.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ede9f3b8cdb69eebad98a818f5a1d7036bd7540 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/settings.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/status.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/status.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6854dfe13af6aea1d5f14cb397d474dafaff096c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/status.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/test.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/test.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6dba7992ee567c0e6872c712b0c0a4411b4f084 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/test.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/throttling.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/throttling.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..349551dd6c84f2d962289fb294ff2d76c1e612f7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/throttling.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urlpatterns.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urlpatterns.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b3bc09f70b8eba8ba628c0428dfb191e16c45e3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urlpatterns.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urls.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d98f46b1b194f8a706a9367328e2754f91a3847 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/urls.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/validators.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/validators.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16c8116ed2a51367b3121031efc66c627adeb93a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/validators.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/versioning.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/versioning.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..01777be112bc1e5fff558a6c59c39ce07634d057 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/versioning.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cd735a9eedf42b2229fd248a487f9ed6048be78 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/viewsets.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/viewsets.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3254cd025e9fd6d5ac88f3cb1b4e468301369d19 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/__pycache__/viewsets.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/apps.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..f6013eb7e09e3e18e5560af12dd62b2f67bbe2a4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig + + +class RestFrameworkConfig(AppConfig): + name = 'rest_framework' + verbose_name = "Django REST framework" + + def ready(self): + # Add System checks + from .checks import pagination_system_check # NOQA diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authentication.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authentication.py new file mode 100644 index 0000000000000000000000000000000000000000..382abf15807e9d045eab13d63ce0f6e01985c7f7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authentication.py @@ -0,0 +1,232 @@ +""" +Provides various authentication policies. +""" +import base64 +import binascii + +from django.contrib.auth import authenticate, get_user_model +from django.middleware.csrf import CsrfViewMiddleware +from django.utils.translation import gettext_lazy as _ + +from rest_framework import HTTP_HEADER_ENCODING, exceptions + + +def get_authorization_header(request): + """ + Return request's 'Authorization:' header, as a bytestring. + + Hide some test client ickyness where the header can be unicode. + """ + auth = request.META.get('HTTP_AUTHORIZATION', b'') + if isinstance(auth, str): + # Work around django test client oddness + auth = auth.encode(HTTP_HEADER_ENCODING) + return auth + + +class CSRFCheck(CsrfViewMiddleware): + def _reject(self, request, reason): + # Return the failure reason instead of an HttpResponse + return reason + + +class BaseAuthentication: + """ + All authentication classes should extend BaseAuthentication. + """ + + def authenticate(self, request): + """ + Authenticate the request and return a two-tuple of (user, token). + """ + raise NotImplementedError(".authenticate() must be overridden.") + + def authenticate_header(self, request): + """ + Return a string to be used as the value of the `WWW-Authenticate` + header in a `401 Unauthenticated` response, or `None` if the + authentication scheme should return `403 Permission Denied` responses. + """ + pass + + +class BasicAuthentication(BaseAuthentication): + """ + HTTP Basic authentication against username/password. + """ + www_authenticate_realm = 'api' + + def authenticate(self, request): + """ + Returns a `User` if a correct username and password have been supplied + using HTTP Basic authentication. Otherwise returns `None`. + """ + auth = get_authorization_header(request).split() + + if not auth or auth[0].lower() != b'basic': + return None + + if len(auth) == 1: + msg = _('Invalid basic header. No credentials provided.') + raise exceptions.AuthenticationFailed(msg) + elif len(auth) > 2: + msg = _('Invalid basic header. Credentials string should not contain spaces.') + raise exceptions.AuthenticationFailed(msg) + + try: + try: + auth_decoded = base64.b64decode(auth[1]).decode('utf-8') + except UnicodeDecodeError: + auth_decoded = base64.b64decode(auth[1]).decode('latin-1') + auth_parts = auth_decoded.partition(':') + except (TypeError, UnicodeDecodeError, binascii.Error): + msg = _('Invalid basic header. Credentials not correctly base64 encoded.') + raise exceptions.AuthenticationFailed(msg) + + userid, password = auth_parts[0], auth_parts[2] + return self.authenticate_credentials(userid, password, request) + + def authenticate_credentials(self, userid, password, request=None): + """ + Authenticate the userid and password against username and password + with optional request for context. + """ + credentials = { + get_user_model().USERNAME_FIELD: userid, + 'password': password + } + user = authenticate(request=request, **credentials) + + if user is None: + raise exceptions.AuthenticationFailed(_('Invalid username/password.')) + + if not user.is_active: + raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) + + return (user, None) + + def authenticate_header(self, request): + return 'Basic realm="%s"' % self.www_authenticate_realm + + +class SessionAuthentication(BaseAuthentication): + """ + Use Django's session framework for authentication. + """ + + def authenticate(self, request): + """ + Returns a `User` if the request session currently has a logged in user. + Otherwise returns `None`. + """ + + # Get the session-based user from the underlying HttpRequest object + user = getattr(request._request, 'user', None) + + # Unauthenticated, CSRF validation not required + if not user or not user.is_active: + return None + + self.enforce_csrf(request) + + # CSRF passed with authenticated user + return (user, None) + + def enforce_csrf(self, request): + """ + Enforce CSRF validation for session based authentication. + """ + def dummy_get_response(request): # pragma: no cover + return None + + check = CSRFCheck(dummy_get_response) + # populates request.META['CSRF_COOKIE'], which is used in process_view() + check.process_request(request) + reason = check.process_view(request, None, (), {}) + if reason: + # CSRF failed, bail with explicit error message + raise exceptions.PermissionDenied('CSRF Failed: %s' % reason) + + +class TokenAuthentication(BaseAuthentication): + """ + Simple token based authentication. + + Clients should authenticate by passing the token key in the "Authorization" + HTTP header, prepended with the string "Token ". For example: + + Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a + """ + + keyword = 'Token' + model = None + + def get_model(self): + if self.model is not None: + return self.model + from rest_framework.authtoken.models import Token + return Token + + """ + A custom token model may be used, but must have the following properties. + + * key -- The string identifying the token + * user -- The user to which the token belongs + """ + + def authenticate(self, request): + auth = get_authorization_header(request).split() + + if not auth or auth[0].lower() != self.keyword.lower().encode(): + return None + + if len(auth) == 1: + msg = _('Invalid token header. No credentials provided.') + raise exceptions.AuthenticationFailed(msg) + elif len(auth) > 2: + msg = _('Invalid token header. Token string should not contain spaces.') + raise exceptions.AuthenticationFailed(msg) + + try: + token = auth[1].decode() + except UnicodeError: + msg = _('Invalid token header. Token string should not contain invalid characters.') + raise exceptions.AuthenticationFailed(msg) + + return self.authenticate_credentials(token) + + def authenticate_credentials(self, key): + model = self.get_model() + try: + token = model.objects.select_related('user').get(key=key) + except model.DoesNotExist: + raise exceptions.AuthenticationFailed(_('Invalid token.')) + + if not token.user.is_active: + raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) + + return (token.user, token) + + def authenticate_header(self, request): + return self.keyword + + +class RemoteUserAuthentication(BaseAuthentication): + """ + REMOTE_USER authentication. + + To use this, set up your web server to perform authentication, which will + set the REMOTE_USER environment variable. You will need to have + 'django.contrib.auth.backends.RemoteUserBackend in your + AUTHENTICATION_BACKENDS setting + """ + + # Name of request header to grab username from. This will be the key as + # used in the request.META dictionary, i.e. the normalization of headers to + # all uppercase and the addition of "HTTP_" prefix apply. + header = "REMOTE_USER" + + def authenticate(self, request): + user = authenticate(request=request, remote_user=request.META.get(self.header)) + if user and user.is_active: + return (user, None) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..285fe15c6bf1480598771107df94e4c472dad7aa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__init__.py @@ -0,0 +1,4 @@ +import django + +if django.VERSION < (3, 2): + default_app_config = 'rest_framework.authtoken.apps.AuthTokenConfig' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f6da79138dd1b08c122166eff140590f4d8d622 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/admin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d91c45cc54f0226e69f3dabc2271e4e1983d846 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/admin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/apps.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f111dfca7acee69b7fd7bd60f179ab4106afd987 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/apps.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c7f6c0dbeca5609e7e5804b3bf4023054ca2455 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/serializers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ef243e922d8fc2aea2eaf10f316a67f2098a7bb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/serializers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a45b0568e85b9176e9b8b4d8ed14c3edf6dc9465 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/admin.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..b359e4cfe8f422bce93350c018238a8fc695c498 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/admin.py @@ -0,0 +1,51 @@ +from django.contrib import admin +from django.contrib.admin.utils import quote +from django.contrib.admin.views.main import ChangeList +from django.contrib.auth import get_user_model +from django.core.exceptions import ValidationError +from django.urls import reverse + +from rest_framework.authtoken.models import Token, TokenProxy + +User = get_user_model() + + +class TokenChangeList(ChangeList): + """Map to matching User id""" + def url_for_result(self, result): + pk = result.user.pk + return reverse('admin:%s_%s_change' % (self.opts.app_label, + self.opts.model_name), + args=(quote(pk),), + current_app=self.model_admin.admin_site.name) + + +class TokenAdmin(admin.ModelAdmin): + list_display = ('key', 'user', 'created') + fields = ('user',) + ordering = ('-created',) + actions = None # Actions not compatible with mapped IDs. + + def get_changelist(self, request, **kwargs): + return TokenChangeList + + def get_object(self, request, object_id, from_field=None): + """ + Map from User ID to matching Token. + """ + queryset = self.get_queryset(request) + field = User._meta.pk + try: + object_id = field.to_python(object_id) + user = User.objects.get(**{field.name: object_id}) + return queryset.get(user=user) + except (queryset.model.DoesNotExist, User.DoesNotExist, ValidationError, ValueError): + return None + + def delete_model(self, request, obj): + # Map back to actual Token, since delete() uses pk. + token = Token.objects.get(key=obj.key) + return super().delete_model(request, token) + + +admin.site.register(TokenProxy, TokenAdmin) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/apps.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..f90fe961efb594218cd2bb99962f54df8a997922 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class AuthTokenConfig(AppConfig): + name = 'rest_framework.authtoken' + verbose_name = _("Auth Token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f05fed9f19478d3771e8221e2ec290d08d33bf82 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..319cb7ab5caf289a016ee1f24008149bf89a3c00 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/drf_create_token.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/drf_create_token.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08fba3f7cf0e54b4c2393ba56c92ce9cee418514 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/__pycache__/drf_create_token.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/drf_create_token.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/drf_create_token.py new file mode 100644 index 0000000000000000000000000000000000000000..3d65392442e3ae191711a4f042e988555aecb9ca --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/management/commands/drf_create_token.py @@ -0,0 +1,45 @@ +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand, CommandError + +from rest_framework.authtoken.models import Token + +UserModel = get_user_model() + + +class Command(BaseCommand): + help = 'Create DRF Token for a given user' + + def create_user_token(self, username, reset_token): + user = UserModel._default_manager.get_by_natural_key(username) + + if reset_token: + Token.objects.filter(user=user).delete() + + token = Token.objects.get_or_create(user=user) + return token[0] + + def add_arguments(self, parser): + parser.add_argument('username', type=str) + + parser.add_argument( + '-r', + '--reset', + action='store_true', + dest='reset_token', + default=False, + help='Reset existing User token and create a new one', + ) + + def handle(self, *args, **options): + username = options['username'] + reset_token = options['reset_token'] + + try: + token = self.create_user_token(username, reset_token) + except UserModel.DoesNotExist: + raise CommandError( + 'Cannot create the Token: user {} does not exist'.format( + username) + ) + self.stdout.write( + 'Generated token {} for user {}'.format(token.key, username)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0001_initial.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..6a46ccfffe866e5ef1e0e8745fd02efc4f1758b7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0001_initial.py @@ -0,0 +1,23 @@ +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Token', + fields=[ + ('key', models.CharField(primary_key=True, serialize=False, max_length=40)), + ('created', models.DateTimeField(auto_now_add=True)), + ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token', on_delete=models.CASCADE)), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py new file mode 100644 index 0000000000000000000000000000000000000000..43119099a36b14dfa0d1be81a45eac0b213be748 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py @@ -0,0 +1,31 @@ +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authtoken', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='token', + options={'verbose_name_plural': 'Tokens', 'verbose_name': 'Token'}, + ), + migrations.AlterField( + model_name='token', + name='created', + field=models.DateTimeField(verbose_name='Created', auto_now_add=True), + ), + migrations.AlterField( + model_name='token', + name='key', + field=models.CharField(verbose_name='Key', max_length=40, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='token', + name='user', + field=models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name='User', related_name='auth_token', on_delete=models.CASCADE), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0003_tokenproxy.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0003_tokenproxy.py new file mode 100644 index 0000000000000000000000000000000000000000..79405a7c0f95b1d632c407fa0cb26435255eaed2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/0003_tokenproxy.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2020-09-28 09:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authtoken', '0002_auto_20160226_1747'), + ] + + operations = [ + migrations.CreateModel( + name='TokenProxy', + fields=[ + ], + options={ + 'verbose_name': 'token', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('authtoken.token',), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0001_initial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dfb4cfeed33b7b50176d1a002d2ed0037f8e64c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0002_auto_20160226_1747.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0002_auto_20160226_1747.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..579141b036c481000201311da44504445594bf65 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0002_auto_20160226_1747.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0003_tokenproxy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0003_tokenproxy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32195f1ca99a1291559681d46b030fa30cd28a9b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/0003_tokenproxy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b51934488f62ee7b1e9fe29502c2ffaa816a0b6a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/models.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/models.py new file mode 100644 index 0000000000000000000000000000000000000000..5a143d936ca2fdd6dc59a187fdcb26bb7203bd20 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/models.py @@ -0,0 +1,54 @@ +import binascii +import os + +from django.conf import settings +from django.db import models +from django.utils.translation import gettext_lazy as _ + + +class Token(models.Model): + """ + The default authorization token model. + """ + key = models.CharField(_("Key"), max_length=40, primary_key=True) + user = models.OneToOneField( + settings.AUTH_USER_MODEL, related_name='auth_token', + on_delete=models.CASCADE, verbose_name=_("User") + ) + created = models.DateTimeField(_("Created"), auto_now_add=True) + + class Meta: + # Work around for a bug in Django: + # https://code.djangoproject.com/ticket/19422 + # + # Also see corresponding ticket: + # https://github.com/encode/django-rest-framework/issues/705 + abstract = 'rest_framework.authtoken' not in settings.INSTALLED_APPS + verbose_name = _("Token") + verbose_name_plural = _("Tokens") + + def save(self, *args, **kwargs): + if not self.key: + self.key = self.generate_key() + return super().save(*args, **kwargs) + + @classmethod + def generate_key(cls): + return binascii.hexlify(os.urandom(20)).decode() + + def __str__(self): + return self.key + + +class TokenProxy(Token): + """ + Proxy mapping pk to user pk for use in admin. + """ + @property + def pk(self): + return self.user_id + + class Meta: + proxy = 'rest_framework.authtoken' in settings.INSTALLED_APPS + abstract = 'rest_framework.authtoken' not in settings.INSTALLED_APPS + verbose_name = "token" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/serializers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..63e64d66837c9be31efc93e2d05305311349e4eb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/serializers.py @@ -0,0 +1,42 @@ +from django.contrib.auth import authenticate +from django.utils.translation import gettext_lazy as _ + +from rest_framework import serializers + + +class AuthTokenSerializer(serializers.Serializer): + username = serializers.CharField( + label=_("Username"), + write_only=True + ) + password = serializers.CharField( + label=_("Password"), + style={'input_type': 'password'}, + trim_whitespace=False, + write_only=True + ) + token = serializers.CharField( + label=_("Token"), + read_only=True + ) + + def validate(self, attrs): + username = attrs.get('username') + password = attrs.get('password') + + if username and password: + user = authenticate(request=self.context.get('request'), + username=username, password=password) + + # The authenticate call simply returns None for is_active=False + # users. (Assuming the default ModelBackend authentication + # backend.) + if not user: + msg = _('Unable to log in with provided credentials.') + raise serializers.ValidationError(msg, code='authorization') + else: + msg = _('Must include "username" and "password".') + raise serializers.ValidationError(msg, code='authorization') + + attrs['user'] = user + return attrs diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/views.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/views.py new file mode 100644 index 0000000000000000000000000000000000000000..50f9acbd90e1ba83681f0227da957f074a700952 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/authtoken/views.py @@ -0,0 +1,62 @@ +from rest_framework import parsers, renderers +from rest_framework.authtoken.models import Token +from rest_framework.authtoken.serializers import AuthTokenSerializer +from rest_framework.compat import coreapi, coreschema +from rest_framework.response import Response +from rest_framework.schemas import ManualSchema +from rest_framework.schemas import coreapi as coreapi_schema +from rest_framework.views import APIView + + +class ObtainAuthToken(APIView): + throttle_classes = () + permission_classes = () + parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) + renderer_classes = (renderers.JSONRenderer,) + serializer_class = AuthTokenSerializer + + if coreapi_schema.is_enabled(): + schema = ManualSchema( + fields=[ + coreapi.Field( + name="username", + required=True, + location='form', + schema=coreschema.String( + title="Username", + description="Valid username for authentication", + ), + ), + coreapi.Field( + name="password", + required=True, + location='form', + schema=coreschema.String( + title="Password", + description="Valid password for authentication", + ), + ), + ], + encoding="application/json", + ) + + def get_serializer_context(self): + return { + 'request': self.request, + 'format': self.format_kwarg, + 'view': self + } + + def get_serializer(self, *args, **kwargs): + kwargs['context'] = self.get_serializer_context() + return self.serializer_class(*args, **kwargs) + + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = serializer.validated_data['user'] + token, created = Token.objects.get_or_create(user=user) + return Response({'token': token.key}) + + +obtain_auth_token = ObtainAuthToken.as_view() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/checks.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/checks.py new file mode 100644 index 0000000000000000000000000000000000000000..d5d77bc59b4d162551a4ac5c807d8f1f96b5cb2b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/checks.py @@ -0,0 +1,21 @@ +from django.core.checks import Tags, Warning, register + + +@register(Tags.compatibility) +def pagination_system_check(app_configs, **kwargs): + errors = [] + # Use of default page size setting requires a default Paginator class + from rest_framework.settings import api_settings + if api_settings.PAGE_SIZE and not api_settings.DEFAULT_PAGINATION_CLASS: + errors.append( + Warning( + "You have specified a default PAGE_SIZE pagination rest_framework setting, " + "without specifying also a DEFAULT_PAGINATION_CLASS.", + hint="The default for DEFAULT_PAGINATION_CLASS is None. " + "In previous versions this was PageNumberPagination. " + "If you wish to define PAGE_SIZE globally whilst defining " + "pagination_class on a per-view basis you may silence this check.", + id="rest_framework.W001" + ) + ) + return errors diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..ac5cbc572a8ff339e6fffd4e2b94a62c816a0d19 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/compat.py @@ -0,0 +1,184 @@ +""" +The `compat` module provides support for backwards compatibility with older +versions of Django/Python, and compatibility wrappers around optional packages. +""" +import django +from django.conf import settings +from django.views.generic import View + + +def unicode_http_header(value): + # Coerce HTTP header value to unicode. + if isinstance(value, bytes): + return value.decode('iso-8859-1') + return value + + +def distinct(queryset, base): + if settings.DATABASES[queryset.db]["ENGINE"] == "django.db.backends.oracle": + # distinct analogue for Oracle users + return base.filter(pk__in=set(queryset.values_list('pk', flat=True))) + return queryset.distinct() + + +# django.contrib.postgres requires psycopg2 +try: + from django.contrib.postgres import fields as postgres_fields +except ImportError: + postgres_fields = None + + +# coreapi is required for CoreAPI schema generation +try: + import coreapi +except ImportError: + coreapi = None + +# uritemplate is required for OpenAPI and CoreAPI schema generation +try: + import uritemplate +except ImportError: + uritemplate = None + + +# coreschema is optional +try: + import coreschema +except ImportError: + coreschema = None + + +# pyyaml is optional +try: + import yaml +except ImportError: + yaml = None + + +# requests is optional +try: + import requests +except ImportError: + requests = None + + +# PATCH method is not implemented by Django +if 'patch' not in View.http_method_names: + View.http_method_names = View.http_method_names + ['patch'] + + +# Markdown is optional (version 3.0+ required) +try: + import markdown + + HEADERID_EXT_PATH = 'markdown.extensions.toc' + LEVEL_PARAM = 'baselevel' + + def apply_markdown(text): + """ + Simple wrapper around :func:`markdown.markdown` to set the base level + of '#' style headers to <h2>. + """ + extensions = [HEADERID_EXT_PATH] + extension_configs = { + HEADERID_EXT_PATH: { + LEVEL_PARAM: '2' + } + } + md = markdown.Markdown( + extensions=extensions, extension_configs=extension_configs + ) + md_filter_add_syntax_highlight(md) + return md.convert(text) +except ImportError: + apply_markdown = None + markdown = None + + +try: + import pygments + from pygments.formatters import HtmlFormatter + from pygments.lexers import TextLexer, get_lexer_by_name + + def pygments_highlight(text, lang, style): + lexer = get_lexer_by_name(lang, stripall=False) + formatter = HtmlFormatter(nowrap=True, style=style) + return pygments.highlight(text, lexer, formatter) + + def pygments_css(style): + formatter = HtmlFormatter(style=style) + return formatter.get_style_defs('.highlight') + +except ImportError: + pygments = None + + def pygments_highlight(text, lang, style): + return text + + def pygments_css(style): + return None + +if markdown is not None and pygments is not None: + # starting from this blogpost and modified to support current markdown extensions API + # https://zerokspot.com/weblog/2008/06/18/syntax-highlighting-in-markdown-with-pygments/ + + import re + + from markdown.preprocessors import Preprocessor + + class CodeBlockPreprocessor(Preprocessor): + pattern = re.compile( + r'^\s*``` *([^\n]+)\n(.+?)^\s*```', re.M | re.S) + + formatter = HtmlFormatter() + + def run(self, lines): + def repl(m): + try: + lexer = get_lexer_by_name(m.group(1)) + except (ValueError, NameError): + lexer = TextLexer() + code = m.group(2).replace('\t', ' ') + code = pygments.highlight(code, lexer, self.formatter) + code = code.replace('\n\n', '\n \n').replace('\n', '<br />').replace('\\@', '@') + return '\n\n%s\n\n' % code + ret = self.pattern.sub(repl, "\n".join(lines)) + return ret.split("\n") + + def md_filter_add_syntax_highlight(md): + md.preprocessors.register(CodeBlockPreprocessor(), 'highlight', 40) + return True +else: + def md_filter_add_syntax_highlight(md): + return False + + +if django.VERSION >= (4, 2): + # Django 4.2+: use the stock parse_header_parameters function + # Note: Django 4.1 also has an implementation of parse_header_parameters + # which is slightly different from the one in 4.2, it needs + # the compatibility shim as well. + from django.utils.http import parse_header_parameters +else: + # Django <= 4.1: create a compatibility shim for parse_header_parameters + from django.http.multipartparser import parse_header + + def parse_header_parameters(line): + # parse_header works with bytes, but parse_header_parameters + # works with strings. Call encode to convert the line to bytes. + main_value_pair, params = parse_header(line.encode()) + return main_value_pair, { + # parse_header will convert *some* values to string. + # parse_header_parameters converts *all* values to string. + # Make sure all values are converted by calling decode on + # any remaining non-string values. + k: v if isinstance(v, str) else v.decode() + for k, v in params.items() + } + + +# `separators` argument to `json.dumps()` differs between 2.x and 3.x +# See: https://bugs.python.org/issue22767 +SHORT_SEPARATORS = (',', ':') +LONG_SEPARATORS = (', ', ': ') +INDENT_SEPARATORS = (',', ': ') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/decorators.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..3b572c09ef8756cc03a2e6c793f5dc2440b811bf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/decorators.py @@ -0,0 +1,233 @@ +""" +The most important decorator in this module is `@api_view`, which is used +for writing function-based views with REST framework. + +There are also various decorators for setting the API policies on function +based views, as well as the `@action` decorator, which is used to annotate +methods on viewsets that should be included by routers. +""" +import types + +from django.forms.utils import pretty_name + +from rest_framework.views import APIView + + +def api_view(http_method_names=None): + """ + Decorator that converts a function-based view into an APIView subclass. + Takes a list of allowed methods for the view as an argument. + """ + http_method_names = ['GET'] if (http_method_names is None) else http_method_names + + def decorator(func): + + WrappedAPIView = type( + 'WrappedAPIView', + (APIView,), + {'__doc__': func.__doc__} + ) + + # Note, the above allows us to set the docstring. + # It is the equivalent of: + # + # class WrappedAPIView(APIView): + # pass + # WrappedAPIView.__doc__ = func.doc <--- Not possible to do this + + # api_view applied without (method_names) + assert not(isinstance(http_method_names, types.FunctionType)), \ + '@api_view missing list of allowed HTTP methods' + + # api_view applied with eg. string instead of list of strings + assert isinstance(http_method_names, (list, tuple)), \ + '@api_view expected a list of strings, received %s' % type(http_method_names).__name__ + + allowed_methods = set(http_method_names) | {'options'} + WrappedAPIView.http_method_names = [method.lower() for method in allowed_methods] + + def handler(self, *args, **kwargs): + return func(*args, **kwargs) + + for method in http_method_names: + setattr(WrappedAPIView, method.lower(), handler) + + WrappedAPIView.__name__ = func.__name__ + WrappedAPIView.__module__ = func.__module__ + + WrappedAPIView.renderer_classes = getattr(func, 'renderer_classes', + APIView.renderer_classes) + + WrappedAPIView.parser_classes = getattr(func, 'parser_classes', + APIView.parser_classes) + + WrappedAPIView.authentication_classes = getattr(func, 'authentication_classes', + APIView.authentication_classes) + + WrappedAPIView.throttle_classes = getattr(func, 'throttle_classes', + APIView.throttle_classes) + + WrappedAPIView.permission_classes = getattr(func, 'permission_classes', + APIView.permission_classes) + + WrappedAPIView.schema = getattr(func, 'schema', + APIView.schema) + + return WrappedAPIView.as_view() + + return decorator + + +def renderer_classes(renderer_classes): + def decorator(func): + func.renderer_classes = renderer_classes + return func + return decorator + + +def parser_classes(parser_classes): + def decorator(func): + func.parser_classes = parser_classes + return func + return decorator + + +def authentication_classes(authentication_classes): + def decorator(func): + func.authentication_classes = authentication_classes + return func + return decorator + + +def throttle_classes(throttle_classes): + def decorator(func): + func.throttle_classes = throttle_classes + return func + return decorator + + +def permission_classes(permission_classes): + def decorator(func): + func.permission_classes = permission_classes + return func + return decorator + + +def schema(view_inspector): + def decorator(func): + func.schema = view_inspector + return func + return decorator + + +def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs): + """ + Mark a ViewSet method as a routable action. + + `@action`-decorated functions will be endowed with a `mapping` property, + a `MethodMapper` that can be used to add additional method-based behaviors + on the routed action. + + :param methods: A list of HTTP method names this action responds to. + Defaults to GET only. + :param detail: Required. Determines whether this action applies to + instance/detail requests or collection/list requests. + :param url_path: Define the URL segment for this action. Defaults to the + name of the method decorated. + :param url_name: Define the internal (`reverse`) URL name for this action. + Defaults to the name of the method decorated with underscores + replaced with dashes. + :param kwargs: Additional properties to set on the view. This can be used + to override viewset-level *_classes settings, equivalent to + how the `@renderer_classes` etc. decorators work for function- + based API views. + """ + methods = ['get'] if methods is None else methods + methods = [method.lower() for method in methods] + + assert detail is not None, ( + "@action() missing required argument: 'detail'" + ) + + # name and suffix are mutually exclusive + if 'name' in kwargs and 'suffix' in kwargs: + raise TypeError("`name` and `suffix` are mutually exclusive arguments.") + + def decorator(func): + func.mapping = MethodMapper(func, methods) + + func.detail = detail + func.url_path = url_path if url_path else func.__name__ + func.url_name = url_name if url_name else func.__name__.replace('_', '-') + + # These kwargs will end up being passed to `ViewSet.as_view()` within + # the router, which eventually delegates to Django's CBV `View`, + # which assigns them as instance attributes for each request. + func.kwargs = kwargs + + # Set descriptive arguments for viewsets + if 'name' not in kwargs and 'suffix' not in kwargs: + func.kwargs['name'] = pretty_name(func.__name__) + func.kwargs['description'] = func.__doc__ or None + + return func + return decorator + + +class MethodMapper(dict): + """ + Enables mapping HTTP methods to different ViewSet methods for a single, + logical action. + + Example usage: + + class MyViewSet(ViewSet): + + @action(detail=False) + def example(self, request, **kwargs): + ... + + @example.mapping.post + def create_example(self, request, **kwargs): + ... + """ + + def __init__(self, action, methods): + self.action = action + for method in methods: + self[method] = self.action.__name__ + + def _map(self, method, func): + assert method not in self, ( + "Method '%s' has already been mapped to '.%s'." % (method, self[method])) + assert func.__name__ != self.action.__name__, ( + "Method mapping does not behave like the property decorator. You " + "cannot use the same method name for each mapping declaration.") + + self[method] = func.__name__ + + return func + + def get(self, func): + return self._map('get', func) + + def post(self, func): + return self._map('post', func) + + def put(self, func): + return self._map('put', func) + + def patch(self, func): + return self._map('patch', func) + + def delete(self, func): + return self._map('delete', func) + + def head(self, func): + return self._map('head', func) + + def options(self, func): + return self._map('options', func) + + def trace(self, func): + return self._map('trace', func) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/documentation.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/documentation.py new file mode 100644 index 0000000000000000000000000000000000000000..53e5ab551a22a3c241e87d30a3c9af4f5f3caa9f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/documentation.py @@ -0,0 +1,88 @@ +from django.urls import include, path + +from rest_framework.renderers import ( + CoreJSONRenderer, DocumentationRenderer, SchemaJSRenderer +) +from rest_framework.schemas import SchemaGenerator, get_schema_view +from rest_framework.settings import api_settings + + +def get_docs_view( + title=None, description=None, schema_url=None, urlconf=None, + public=True, patterns=None, generator_class=SchemaGenerator, + authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES, + permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES, + renderer_classes=None): + + if renderer_classes is None: + renderer_classes = [DocumentationRenderer, CoreJSONRenderer] + + return get_schema_view( + title=title, + url=schema_url, + urlconf=urlconf, + description=description, + renderer_classes=renderer_classes, + public=public, + patterns=patterns, + generator_class=generator_class, + authentication_classes=authentication_classes, + permission_classes=permission_classes, + ) + + +def get_schemajs_view( + title=None, description=None, schema_url=None, urlconf=None, + public=True, patterns=None, generator_class=SchemaGenerator, + authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES, + permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES): + renderer_classes = [SchemaJSRenderer] + + return get_schema_view( + title=title, + url=schema_url, + urlconf=urlconf, + description=description, + renderer_classes=renderer_classes, + public=public, + patterns=patterns, + generator_class=generator_class, + authentication_classes=authentication_classes, + permission_classes=permission_classes, + ) + + +def include_docs_urls( + title=None, description=None, schema_url=None, urlconf=None, + public=True, patterns=None, generator_class=SchemaGenerator, + authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES, + permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES, + renderer_classes=None): + docs_view = get_docs_view( + title=title, + description=description, + schema_url=schema_url, + urlconf=urlconf, + public=public, + patterns=patterns, + generator_class=generator_class, + authentication_classes=authentication_classes, + renderer_classes=renderer_classes, + permission_classes=permission_classes, + ) + schema_js_view = get_schemajs_view( + title=title, + description=description, + schema_url=schema_url, + urlconf=urlconf, + public=public, + patterns=patterns, + generator_class=generator_class, + authentication_classes=authentication_classes, + permission_classes=permission_classes, + ) + urls = [ + path('', docs_view, name='docs-index'), + path('schema.js', schema_js_view, name='schema-js') + ] + return include((urls, 'api-docs'), namespace='api-docs') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..09f111102ef4dc38f244cbcdd6da1143d7d31bc1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/exceptions.py @@ -0,0 +1,264 @@ +""" +Handled exceptions raised by REST framework. + +In addition, Django's built in 403 and 404 exceptions are handled. +(`django.http.Http404` and `django.core.exceptions.PermissionDenied`) +""" +import math + +from django.http import JsonResponse +from django.utils.encoding import force_str +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext + +from rest_framework import status +from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList + + +def _get_error_details(data, default_code=None): + """ + Descend into a nested data structure, forcing any + lazy translation strings or strings into `ErrorDetail`. + """ + if isinstance(data, (list, tuple)): + ret = [ + _get_error_details(item, default_code) for item in data + ] + if isinstance(data, ReturnList): + return ReturnList(ret, serializer=data.serializer) + return ret + elif isinstance(data, dict): + ret = { + key: _get_error_details(value, default_code) + for key, value in data.items() + } + if isinstance(data, ReturnDict): + return ReturnDict(ret, serializer=data.serializer) + return ret + + text = force_str(data) + code = getattr(data, 'code', default_code) + return ErrorDetail(text, code) + + +def _get_codes(detail): + if isinstance(detail, list): + return [_get_codes(item) for item in detail] + elif isinstance(detail, dict): + return {key: _get_codes(value) for key, value in detail.items()} + return detail.code + + +def _get_full_details(detail): + if isinstance(detail, list): + return [_get_full_details(item) for item in detail] + elif isinstance(detail, dict): + return {key: _get_full_details(value) for key, value in detail.items()} + return { + 'message': detail, + 'code': detail.code + } + + +class ErrorDetail(str): + """ + A string-like object that can additionally have a code. + """ + code = None + + def __new__(cls, string, code=None): + self = super().__new__(cls, string) + self.code = code + return self + + def __eq__(self, other): + result = super().__eq__(other) + if result is NotImplemented: + return NotImplemented + try: + return result and self.code == other.code + except AttributeError: + return result + + def __ne__(self, other): + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + return not result + + def __repr__(self): + return 'ErrorDetail(string=%r, code=%r)' % ( + str(self), + self.code, + ) + + def __hash__(self): + return hash(str(self)) + + +class APIException(Exception): + """ + Base class for REST framework exceptions. + Subclasses should provide `.status_code` and `.default_detail` properties. + """ + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + default_detail = _('A server error occurred.') + default_code = 'error' + + def __init__(self, detail=None, code=None): + if detail is None: + detail = self.default_detail + if code is None: + code = self.default_code + + self.detail = _get_error_details(detail, code) + + def __str__(self): + return str(self.detail) + + def get_codes(self): + """ + Return only the code part of the error details. + + Eg. {"name": ["required"]} + """ + return _get_codes(self.detail) + + def get_full_details(self): + """ + Return both the message & code parts of the error details. + + Eg. {"name": [{"message": "This field is required.", "code": "required"}]} + """ + return _get_full_details(self.detail) + + +# The recommended style for using `ValidationError` is to keep it namespaced +# under `serializers`, in order to minimize potential confusion with Django's +# built in `ValidationError`. For example: +# +# from rest_framework import serializers +# raise serializers.ValidationError('Value was invalid') + +class ValidationError(APIException): + status_code = status.HTTP_400_BAD_REQUEST + default_detail = _('Invalid input.') + default_code = 'invalid' + + def __init__(self, detail=None, code=None): + if detail is None: + detail = self.default_detail + if code is None: + code = self.default_code + + # For validation failures, we may collect many errors together, + # so the details should always be coerced to a list if not already. + if isinstance(detail, tuple): + detail = list(detail) + elif not isinstance(detail, dict) and not isinstance(detail, list): + detail = [detail] + + self.detail = _get_error_details(detail, code) + + +class ParseError(APIException): + status_code = status.HTTP_400_BAD_REQUEST + default_detail = _('Malformed request.') + default_code = 'parse_error' + + +class AuthenticationFailed(APIException): + status_code = status.HTTP_401_UNAUTHORIZED + default_detail = _('Incorrect authentication credentials.') + default_code = 'authentication_failed' + + +class NotAuthenticated(APIException): + status_code = status.HTTP_401_UNAUTHORIZED + default_detail = _('Authentication credentials were not provided.') + default_code = 'not_authenticated' + + +class PermissionDenied(APIException): + status_code = status.HTTP_403_FORBIDDEN + default_detail = _('You do not have permission to perform this action.') + default_code = 'permission_denied' + + +class NotFound(APIException): + status_code = status.HTTP_404_NOT_FOUND + default_detail = _('Not found.') + default_code = 'not_found' + + +class MethodNotAllowed(APIException): + status_code = status.HTTP_405_METHOD_NOT_ALLOWED + default_detail = _('Method "{method}" not allowed.') + default_code = 'method_not_allowed' + + def __init__(self, method, detail=None, code=None): + if detail is None: + detail = force_str(self.default_detail).format(method=method) + super().__init__(detail, code) + + +class NotAcceptable(APIException): + status_code = status.HTTP_406_NOT_ACCEPTABLE + default_detail = _('Could not satisfy the request Accept header.') + default_code = 'not_acceptable' + + def __init__(self, detail=None, code=None, available_renderers=None): + self.available_renderers = available_renderers + super().__init__(detail, code) + + +class UnsupportedMediaType(APIException): + status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE + default_detail = _('Unsupported media type "{media_type}" in request.') + default_code = 'unsupported_media_type' + + def __init__(self, media_type, detail=None, code=None): + if detail is None: + detail = force_str(self.default_detail).format(media_type=media_type) + super().__init__(detail, code) + + +class Throttled(APIException): + status_code = status.HTTP_429_TOO_MANY_REQUESTS + default_detail = _('Request was throttled.') + extra_detail_singular = _('Expected available in {wait} second.') + extra_detail_plural = _('Expected available in {wait} seconds.') + default_code = 'throttled' + + def __init__(self, wait=None, detail=None, code=None): + if detail is None: + detail = force_str(self.default_detail) + if wait is not None: + wait = math.ceil(wait) + detail = ' '.join(( + detail, + force_str(ngettext(self.extra_detail_singular.format(wait=wait), + self.extra_detail_plural.format(wait=wait), + wait)))) + self.wait = wait + super().__init__(detail, code) + + +def server_error(request, *args, **kwargs): + """ + Generic 500 error handler. + """ + data = { + 'error': 'Server Error (500)' + } + return JsonResponse(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + +def bad_request(request, exception, *args, **kwargs): + """ + Generic 400 error handler. + """ + data = { + 'error': 'Bad Request (400)' + } + return JsonResponse(data, status=status.HTTP_400_BAD_REQUEST) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/fields.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/fields.py new file mode 100644 index 0000000000000000000000000000000000000000..6374c1ea987f46fb70f9fc496d66ba70149bbc45 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/fields.py @@ -0,0 +1,1878 @@ +import copy +import datetime +import decimal +import functools +import inspect +import re +import uuid +from collections import OrderedDict +from collections.abc import Mapping + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ValidationError as DjangoValidationError +from django.core.validators import ( + EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, + MinValueValidator, ProhibitNullCharactersValidator, RegexValidator, + URLValidator, ip_address_validators +) +from django.forms import FilePathField as DjangoFilePathField +from django.forms import ImageField as DjangoImageField +from django.utils import timezone +from django.utils.dateparse import ( + parse_date, parse_datetime, parse_duration, parse_time +) +from django.utils.duration import duration_string +from django.utils.encoding import is_protected_type, smart_str +from django.utils.formats import localize_input, sanitize_separators +from django.utils.ipv6 import clean_ipv6_address +from django.utils.translation import gettext_lazy as _ +from pytz.exceptions import InvalidTimeError + +from rest_framework import ISO_8601 +from rest_framework.exceptions import ErrorDetail, ValidationError +from rest_framework.settings import api_settings +from rest_framework.utils import html, humanize_datetime, json, representation +from rest_framework.utils.formatting import lazy_format +from rest_framework.validators import ProhibitSurrogateCharactersValidator + + +class empty: + """ + This class is used to represent no data being provided for a given input + or output value. + + It is required because `None` may be a valid input or output value. + """ + pass + + +class BuiltinSignatureError(Exception): + """ + Built-in function signatures are not inspectable. This exception is raised + so the serializer can raise a helpful error message. + """ + pass + + +def is_simple_callable(obj): + """ + True if the object is a callable that takes no arguments. + """ + if not callable(obj): + return False + + # Bail early since we cannot inspect built-in function signatures. + if inspect.isbuiltin(obj): + raise BuiltinSignatureError( + 'Built-in function signatures are not inspectable. ' + 'Wrap the function call in a simple, pure Python function.') + + if not (inspect.isfunction(obj) or inspect.ismethod(obj) or isinstance(obj, functools.partial)): + return False + + sig = inspect.signature(obj) + params = sig.parameters.values() + return all( + param.kind == param.VAR_POSITIONAL or + param.kind == param.VAR_KEYWORD or + param.default != param.empty + for param in params + ) + + +def get_attribute(instance, attrs): + """ + Similar to Python's built in `getattr(instance, attr)`, + but takes a list of nested attributes, instead of a single attribute. + + Also accepts either attribute lookup on objects or dictionary lookups. + """ + for attr in attrs: + try: + if isinstance(instance, Mapping): + instance = instance[attr] + else: + instance = getattr(instance, attr) + except ObjectDoesNotExist: + return None + if is_simple_callable(instance): + try: + instance = instance() + except (AttributeError, KeyError) as exc: + # If we raised an Attribute or KeyError here it'd get treated + # as an omitted field in `Field.get_attribute()`. Instead we + # raise a ValueError to ensure the exception is not masked. + raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc)) + + return instance + + +def set_value(dictionary, keys, value): + """ + Similar to Python's built in `dictionary[key] = value`, + but takes a list of nested keys instead of a single key. + + set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2} + set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2} + set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}} + """ + if not keys: + dictionary.update(value) + return + + for key in keys[:-1]: + if key not in dictionary: + dictionary[key] = {} + dictionary = dictionary[key] + + dictionary[keys[-1]] = value + + +def to_choices_dict(choices): + """ + Convert choices into key/value dicts. + + to_choices_dict([1]) -> {1: 1} + to_choices_dict([(1, '1st'), (2, '2nd')]) -> {1: '1st', 2: '2nd'} + to_choices_dict([('Group', ((1, '1st'), 2))]) -> {'Group': {1: '1st', 2: '2'}} + """ + # Allow single, paired or grouped choices style: + # choices = [1, 2, 3] + # choices = [(1, 'First'), (2, 'Second'), (3, 'Third')] + # choices = [('Category', ((1, 'First'), (2, 'Second'))), (3, 'Third')] + ret = OrderedDict() + for choice in choices: + if not isinstance(choice, (list, tuple)): + # single choice + ret[choice] = choice + else: + key, value = choice + if isinstance(value, (list, tuple)): + # grouped choices (category, sub choices) + ret[key] = to_choices_dict(value) + else: + # paired choice (key, display value) + ret[key] = value + return ret + + +def flatten_choices_dict(choices): + """ + Convert a group choices dict into a flat dict of choices. + + flatten_choices_dict({1: '1st', 2: '2nd'}) -> {1: '1st', 2: '2nd'} + flatten_choices_dict({'Group': {1: '1st', 2: '2nd'}}) -> {1: '1st', 2: '2nd'} + """ + ret = OrderedDict() + for key, value in choices.items(): + if isinstance(value, dict): + # grouped choices (category, sub choices) + for sub_key, sub_value in value.items(): + ret[sub_key] = sub_value + else: + # choice (key, display value) + ret[key] = value + return ret + + +def iter_options(grouped_choices, cutoff=None, cutoff_text=None): + """ + Helper function for options and option groups in templates. + """ + class StartOptionGroup: + start_option_group = True + end_option_group = False + + def __init__(self, label): + self.label = label + + class EndOptionGroup: + start_option_group = False + end_option_group = True + + class Option: + start_option_group = False + end_option_group = False + + def __init__(self, value, display_text, disabled=False): + self.value = value + self.display_text = display_text + self.disabled = disabled + + count = 0 + + for key, value in grouped_choices.items(): + if cutoff and count >= cutoff: + break + + if isinstance(value, dict): + yield StartOptionGroup(label=key) + for sub_key, sub_value in value.items(): + if cutoff and count >= cutoff: + break + yield Option(value=sub_key, display_text=sub_value) + count += 1 + yield EndOptionGroup() + else: + yield Option(value=key, display_text=value) + count += 1 + + if cutoff and count >= cutoff and cutoff_text: + cutoff_text = cutoff_text.format(count=cutoff) + yield Option(value='n/a', display_text=cutoff_text, disabled=True) + + +def get_error_detail(exc_info): + """ + Given a Django ValidationError, return a list of ErrorDetail, + with the `code` populated. + """ + code = getattr(exc_info, 'code', None) or 'invalid' + + try: + error_dict = exc_info.error_dict + except AttributeError: + return [ + ErrorDetail((error.message % error.params) if error.params else error.message, + code=error.code if error.code else code) + for error in exc_info.error_list] + return { + k: [ + ErrorDetail((error.message % error.params) if error.params else error.message, + code=error.code if error.code else code) + for error in errors + ] for k, errors in error_dict.items() + } + + +class CreateOnlyDefault: + """ + This class may be used to provide default values that are only used + for create operations, but that do not return any value for update + operations. + """ + requires_context = True + + def __init__(self, default): + self.default = default + + def __call__(self, serializer_field): + is_update = serializer_field.parent.instance is not None + if is_update: + raise SkipField() + if callable(self.default): + if getattr(self.default, 'requires_context', False): + return self.default(serializer_field) + else: + return self.default() + return self.default + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, repr(self.default)) + + +class CurrentUserDefault: + requires_context = True + + def __call__(self, serializer_field): + return serializer_field.context['request'].user + + def __repr__(self): + return '%s()' % self.__class__.__name__ + + +class SkipField(Exception): + pass + + +REGEX_TYPE = type(re.compile('')) + +NOT_READ_ONLY_WRITE_ONLY = 'May not set both `read_only` and `write_only`' +NOT_READ_ONLY_REQUIRED = 'May not set both `read_only` and `required`' +NOT_REQUIRED_DEFAULT = 'May not set both `required` and `default`' +USE_READONLYFIELD = 'Field(read_only=True) should be ReadOnlyField' +MISSING_ERROR_MESSAGE = ( + 'ValidationError raised by `{class_name}`, but error key `{key}` does ' + 'not exist in the `error_messages` dictionary.' +) + + +class Field: + _creation_counter = 0 + + default_error_messages = { + 'required': _('This field is required.'), + 'null': _('This field may not be null.') + } + default_validators = [] + default_empty_html = empty + initial = None + + def __init__(self, *, read_only=False, write_only=False, + required=None, default=empty, initial=empty, source=None, + label=None, help_text=None, style=None, + error_messages=None, validators=None, allow_null=False): + self._creation_counter = Field._creation_counter + Field._creation_counter += 1 + + # If `required` is unset, then use `True` unless a default is provided. + if required is None: + required = default is empty and not read_only + + # Some combinations of keyword arguments do not make sense. + assert not (read_only and write_only), NOT_READ_ONLY_WRITE_ONLY + assert not (read_only and required), NOT_READ_ONLY_REQUIRED + assert not (required and default is not empty), NOT_REQUIRED_DEFAULT + assert not (read_only and self.__class__ == Field), USE_READONLYFIELD + + self.read_only = read_only + self.write_only = write_only + self.required = required + self.default = default + self.source = source + self.initial = self.initial if (initial is empty) else initial + self.label = label + self.help_text = help_text + self.style = {} if style is None else style + self.allow_null = allow_null + + if self.default_empty_html is not empty: + if default is not empty: + self.default_empty_html = default + + if validators is not None: + self.validators = list(validators) + + # These are set up by `.bind()` when the field is added to a serializer. + self.field_name = None + self.parent = None + + # Collect default error message from self and parent classes + messages = {} + for cls in reversed(self.__class__.__mro__): + messages.update(getattr(cls, 'default_error_messages', {})) + messages.update(error_messages or {}) + self.error_messages = messages + + def bind(self, field_name, parent): + """ + Initializes the field name and parent for the field instance. + Called when a field is added to the parent serializer instance. + """ + + # In order to enforce a consistent style, we error if a redundant + # 'source' argument has been used. For example: + # my_field = serializer.CharField(source='my_field') + assert self.source != field_name, ( + "It is redundant to specify `source='%s'` on field '%s' in " + "serializer '%s', because it is the same as the field name. " + "Remove the `source` keyword argument." % + (field_name, self.__class__.__name__, parent.__class__.__name__) + ) + + self.field_name = field_name + self.parent = parent + + # `self.label` should default to being based on the field name. + if self.label is None: + self.label = field_name.replace('_', ' ').capitalize() + + # self.source should default to being the same as the field name. + if self.source is None: + self.source = field_name + + # self.source_attrs is a list of attributes that need to be looked up + # when serializing the instance, or populating the validated data. + if self.source == '*': + self.source_attrs = [] + else: + self.source_attrs = self.source.split('.') + + # .validators is a lazily loaded property, that gets its default + # value from `get_validators`. + @property + def validators(self): + if not hasattr(self, '_validators'): + self._validators = self.get_validators() + return self._validators + + @validators.setter + def validators(self, validators): + self._validators = validators + + def get_validators(self): + return list(self.default_validators) + + def get_initial(self): + """ + Return a value to use when the field is being returned as a primitive + value, without any object instance. + """ + if callable(self.initial): + return self.initial() + return self.initial + + def get_value(self, dictionary): + """ + Given the *incoming* primitive data, return the value for this field + that should be validated and transformed to a native value. + """ + if html.is_html_input(dictionary): + # HTML forms will represent empty fields as '', and cannot + # represent None or False values directly. + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty + return self.default_empty_html + ret = dictionary[self.field_name] + if ret == '' and self.allow_null: + # If the field is blank, and null is a valid value then + # determine if we should use null instead. + return '' if getattr(self, 'allow_blank', False) else None + elif ret == '' and not self.required: + # If the field is blank, and emptiness is valid then + # determine if we should use emptiness instead. + return '' if getattr(self, 'allow_blank', False) else empty + return ret + return dictionary.get(self.field_name, empty) + + def get_attribute(self, instance): + """ + Given the *outgoing* object instance, return the primitive value + that should be used for this field. + """ + try: + return get_attribute(instance, self.source_attrs) + except BuiltinSignatureError as exc: + msg = ( + 'Field source for `{serializer}.{field}` maps to a built-in ' + 'function type and is invalid. Define a property or method on ' + 'the `{instance}` instance that wraps the call to the built-in ' + 'function.'.format( + serializer=self.parent.__class__.__name__, + field=self.field_name, + instance=instance.__class__.__name__, + ) + ) + raise type(exc)(msg) + except (KeyError, AttributeError) as exc: + if self.default is not empty: + return self.get_default() + if self.allow_null: + return None + if not self.required: + raise SkipField() + msg = ( + 'Got {exc_type} when attempting to get a value for field ' + '`{field}` on serializer `{serializer}`.\nThe serializer ' + 'field might be named incorrectly and not match ' + 'any attribute or key on the `{instance}` instance.\n' + 'Original exception text was: {exc}.'.format( + exc_type=type(exc).__name__, + field=self.field_name, + serializer=self.parent.__class__.__name__, + instance=instance.__class__.__name__, + exc=exc + ) + ) + raise type(exc)(msg) + + def get_default(self): + """ + Return the default value to use when validating data if no input + is provided for this field. + + If a default has not been set for this field then this will simply + raise `SkipField`, indicating that no value should be set in the + validated data for this field. + """ + if self.default is empty or getattr(self.root, 'partial', False): + # No default, or this is a partial update. + raise SkipField() + if callable(self.default): + if getattr(self.default, 'requires_context', False): + return self.default(self) + else: + return self.default() + + return self.default + + def validate_empty_values(self, data): + """ + Validate empty values, and either: + + * Raise `ValidationError`, indicating invalid data. + * Raise `SkipField`, indicating that the field should be ignored. + * Return (True, data), indicating an empty value that should be + returned without any further validation being applied. + * Return (False, data), indicating a non-empty value, that should + have validation applied as normal. + """ + if self.read_only: + return (True, self.get_default()) + + if data is empty: + if getattr(self.root, 'partial', False): + raise SkipField() + if self.required: + self.fail('required') + return (True, self.get_default()) + + if data is None: + if not self.allow_null: + self.fail('null') + # Nullable `source='*'` fields should not be skipped when its named + # field is given a null value. This is because `source='*'` means + # the field is passed the entire object, which is not null. + elif self.source == '*': + return (False, None) + return (True, None) + + return (False, data) + + def run_validation(self, data=empty): + """ + Validate a simple representation and return the internal value. + + The provided data may be `empty` if no representation was included + in the input. + + May raise `SkipField` if the field should not be included in the + validated data. + """ + (is_empty_value, data) = self.validate_empty_values(data) + if is_empty_value: + return data + value = self.to_internal_value(data) + self.run_validators(value) + return value + + def run_validators(self, value): + """ + Test the given value against all the validators on the field, + and either raise a `ValidationError` or simply return. + """ + errors = [] + for validator in self.validators: + try: + if getattr(validator, 'requires_context', False): + validator(value, self) + else: + validator(value) + except ValidationError as exc: + # If the validation error contains a mapping of fields to + # errors then simply raise it immediately rather than + # attempting to accumulate a list of errors. + if isinstance(exc.detail, dict): + raise + errors.extend(exc.detail) + except DjangoValidationError as exc: + errors.extend(get_error_detail(exc)) + if errors: + raise ValidationError(errors) + + def to_internal_value(self, data): + """ + Transform the *incoming* primitive data into a native value. + """ + raise NotImplementedError( + '{cls}.to_internal_value() must be implemented for field ' + '{field_name}. If you do not need to support write operations ' + 'you probably want to subclass `ReadOnlyField` instead.'.format( + cls=self.__class__.__name__, + field_name=self.field_name, + ) + ) + + def to_representation(self, value): + """ + Transform the *outgoing* native value into primitive data. + """ + raise NotImplementedError( + '{cls}.to_representation() must be implemented for field {field_name}.'.format( + cls=self.__class__.__name__, + field_name=self.field_name, + ) + ) + + def fail(self, key, **kwargs): + """ + A helper method that simply raises a validation error. + """ + try: + msg = self.error_messages[key] + except KeyError: + class_name = self.__class__.__name__ + msg = MISSING_ERROR_MESSAGE.format(class_name=class_name, key=key) + raise AssertionError(msg) + message_string = msg.format(**kwargs) + raise ValidationError(message_string, code=key) + + @property + def root(self): + """ + Returns the top-level serializer for this field. + """ + root = self + while root.parent is not None: + root = root.parent + return root + + @property + def context(self): + """ + Returns the context as passed to the root serializer on initialization. + """ + return getattr(self.root, '_context', {}) + + def __new__(cls, *args, **kwargs): + """ + When a field is instantiated, we store the arguments that were used, + so that we can present a helpful representation of the object. + """ + instance = super().__new__(cls) + instance._args = args + instance._kwargs = kwargs + return instance + + def __deepcopy__(self, memo): + """ + When cloning fields we instantiate using the arguments it was + originally created with, rather than copying the complete state. + """ + # Treat regexes and validators as immutable. + # See https://github.com/encode/django-rest-framework/issues/1954 + # and https://github.com/encode/django-rest-framework/pull/4489 + args = [ + copy.deepcopy(item) if not isinstance(item, REGEX_TYPE) else item + for item in self._args + ] + kwargs = { + key: (copy.deepcopy(value, memo) if (key not in ('validators', 'regex')) else value) + for key, value in self._kwargs.items() + } + return self.__class__(*args, **kwargs) + + def __repr__(self): + """ + Fields are represented using their initial calling arguments. + This allows us to create descriptive representations for serializer + instances that show all the declared fields on the serializer. + """ + return representation.field_repr(self) + + +# Boolean types... + +class BooleanField(Field): + default_error_messages = { + 'invalid': _('Must be a valid boolean.') + } + default_empty_html = False + initial = False + TRUE_VALUES = { + 't', 'T', + 'y', 'Y', 'yes', 'Yes', 'YES', + 'true', 'True', 'TRUE', + 'on', 'On', 'ON', + '1', 1, + True + } + FALSE_VALUES = { + 'f', 'F', + 'n', 'N', 'no', 'No', 'NO', + 'false', 'False', 'FALSE', + 'off', 'Off', 'OFF', + '0', 0, 0.0, + False + } + NULL_VALUES = {'null', 'Null', 'NULL', '', None} + + def to_internal_value(self, data): + try: + if data in self.TRUE_VALUES: + return True + elif data in self.FALSE_VALUES: + return False + elif data in self.NULL_VALUES and self.allow_null: + return None + except TypeError: # Input is an unhashable type + pass + self.fail('invalid', input=data) + + def to_representation(self, value): + if value in self.TRUE_VALUES: + return True + elif value in self.FALSE_VALUES: + return False + if value in self.NULL_VALUES and self.allow_null: + return None + return bool(value) + + +# String types... + +class CharField(Field): + default_error_messages = { + 'invalid': _('Not a valid string.'), + 'blank': _('This field may not be blank.'), + 'max_length': _('Ensure this field has no more than {max_length} characters.'), + 'min_length': _('Ensure this field has at least {min_length} characters.'), + } + initial = '' + + def __init__(self, **kwargs): + self.allow_blank = kwargs.pop('allow_blank', False) + self.trim_whitespace = kwargs.pop('trim_whitespace', True) + self.max_length = kwargs.pop('max_length', None) + self.min_length = kwargs.pop('min_length', None) + super().__init__(**kwargs) + if self.max_length is not None: + message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) + self.validators.append( + MaxLengthValidator(self.max_length, message=message)) + if self.min_length is not None: + message = lazy_format(self.error_messages['min_length'], min_length=self.min_length) + self.validators.append( + MinLengthValidator(self.min_length, message=message)) + + self.validators.append(ProhibitNullCharactersValidator()) + self.validators.append(ProhibitSurrogateCharactersValidator()) + + def run_validation(self, data=empty): + # Test for the empty string here so that it does not get validated, + # and so that subclasses do not need to handle it explicitly + # inside the `to_internal_value()` method. + if data == '' or (self.trim_whitespace and str(data).strip() == ''): + if not self.allow_blank: + self.fail('blank') + return '' + return super().run_validation(data) + + def to_internal_value(self, data): + # We're lenient with allowing basic numerics to be coerced into strings, + # but other types should fail. Eg. unclear if booleans should represent as `true` or `True`, + # and composites such as lists are likely user error. + if isinstance(data, bool) or not isinstance(data, (str, int, float,)): + self.fail('invalid') + value = str(data) + return value.strip() if self.trim_whitespace else value + + def to_representation(self, value): + return str(value) + + +class EmailField(CharField): + default_error_messages = { + 'invalid': _('Enter a valid email address.') + } + + def __init__(self, **kwargs): + super().__init__(**kwargs) + validator = EmailValidator(message=self.error_messages['invalid']) + self.validators.append(validator) + + +class RegexField(CharField): + default_error_messages = { + 'invalid': _('This value does not match the required pattern.') + } + + def __init__(self, regex, **kwargs): + super().__init__(**kwargs) + validator = RegexValidator(regex, message=self.error_messages['invalid']) + self.validators.append(validator) + + +class SlugField(CharField): + default_error_messages = { + 'invalid': _('Enter a valid "slug" consisting of letters, numbers, underscores or hyphens.'), + 'invalid_unicode': _('Enter a valid "slug" consisting of Unicode letters, numbers, underscores, or hyphens.') + } + + def __init__(self, allow_unicode=False, **kwargs): + super().__init__(**kwargs) + self.allow_unicode = allow_unicode + if self.allow_unicode: + validator = RegexValidator(re.compile(r'^[-\w]+\Z', re.UNICODE), message=self.error_messages['invalid_unicode']) + else: + validator = RegexValidator(re.compile(r'^[-a-zA-Z0-9_]+$'), message=self.error_messages['invalid']) + self.validators.append(validator) + + +class URLField(CharField): + default_error_messages = { + 'invalid': _('Enter a valid URL.') + } + + def __init__(self, **kwargs): + super().__init__(**kwargs) + validator = URLValidator(message=self.error_messages['invalid']) + self.validators.append(validator) + + +class UUIDField(Field): + valid_formats = ('hex_verbose', 'hex', 'int', 'urn') + + default_error_messages = { + 'invalid': _('Must be a valid UUID.'), + } + + def __init__(self, **kwargs): + self.uuid_format = kwargs.pop('format', 'hex_verbose') + if self.uuid_format not in self.valid_formats: + raise ValueError( + 'Invalid format for uuid representation. ' + 'Must be one of "{}"'.format('", "'.join(self.valid_formats)) + ) + super().__init__(**kwargs) + + def to_internal_value(self, data): + if not isinstance(data, uuid.UUID): + try: + if isinstance(data, int): + return uuid.UUID(int=data) + elif isinstance(data, str): + return uuid.UUID(hex=data) + else: + self.fail('invalid', value=data) + except (ValueError): + self.fail('invalid', value=data) + return data + + def to_representation(self, value): + if self.uuid_format == 'hex_verbose': + return str(value) + else: + return getattr(value, self.uuid_format) + + +class IPAddressField(CharField): + """Support both IPAddressField and GenericIPAddressField""" + + default_error_messages = { + 'invalid': _('Enter a valid IPv4 or IPv6 address.'), + } + + def __init__(self, protocol='both', **kwargs): + self.protocol = protocol.lower() + self.unpack_ipv4 = (self.protocol == 'both') + super().__init__(**kwargs) + validators, error_message = ip_address_validators(protocol, self.unpack_ipv4) + self.validators.extend(validators) + + def to_internal_value(self, data): + if not isinstance(data, str): + self.fail('invalid', value=data) + + if ':' in data: + try: + if self.protocol in ('both', 'ipv6'): + return clean_ipv6_address(data, self.unpack_ipv4) + except DjangoValidationError: + self.fail('invalid', value=data) + + return super().to_internal_value(data) + + +# Number types... + +class IntegerField(Field): + default_error_messages = { + 'invalid': _('A valid integer is required.'), + 'max_value': _('Ensure this value is less than or equal to {max_value}.'), + 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), + 'max_string_length': _('String value too large.') + } + MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. + re_decimal = re.compile(r'\.0*\s*$') # allow e.g. '1.0' as an int, but not '1.2' + + def __init__(self, **kwargs): + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) + super().__init__(**kwargs) + if self.max_value is not None: + message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) + self.validators.append( + MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) + self.validators.append( + MinValueValidator(self.min_value, message=message)) + + def to_internal_value(self, data): + if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH: + self.fail('max_string_length') + + try: + data = int(self.re_decimal.sub('', str(data))) + except (ValueError, TypeError): + self.fail('invalid') + return data + + def to_representation(self, value): + return int(value) + + +class FloatField(Field): + default_error_messages = { + 'invalid': _('A valid number is required.'), + 'max_value': _('Ensure this value is less than or equal to {max_value}.'), + 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), + 'max_string_length': _('String value too large.') + } + MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. + + def __init__(self, **kwargs): + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) + super().__init__(**kwargs) + if self.max_value is not None: + message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) + self.validators.append( + MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) + self.validators.append( + MinValueValidator(self.min_value, message=message)) + + def to_internal_value(self, data): + + if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH: + self.fail('max_string_length') + + try: + return float(data) + except (TypeError, ValueError): + self.fail('invalid') + + def to_representation(self, value): + return float(value) + + +class DecimalField(Field): + default_error_messages = { + 'invalid': _('A valid number is required.'), + 'max_value': _('Ensure this value is less than or equal to {max_value}.'), + 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), + 'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'), + 'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'), + 'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), + 'max_string_length': _('String value too large.') + } + MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. + + def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, + localize=False, rounding=None, **kwargs): + self.max_digits = max_digits + self.decimal_places = decimal_places + self.localize = localize + if coerce_to_string is not None: + self.coerce_to_string = coerce_to_string + if self.localize: + self.coerce_to_string = True + + self.max_value = max_value + self.min_value = min_value + + if self.max_digits is not None and self.decimal_places is not None: + self.max_whole_digits = self.max_digits - self.decimal_places + else: + self.max_whole_digits = None + + super().__init__(**kwargs) + + if self.max_value is not None: + message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) + self.validators.append( + MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) + self.validators.append( + MinValueValidator(self.min_value, message=message)) + + if rounding is not None: + valid_roundings = [v for k, v in vars(decimal).items() if k.startswith('ROUND_')] + assert rounding in valid_roundings, ( + 'Invalid rounding option %s. Valid values for rounding are: %s' % (rounding, valid_roundings)) + self.rounding = rounding + + def validate_empty_values(self, data): + if smart_str(data).strip() == '' and self.allow_null: + return (True, None) + return super().validate_empty_values(data) + + def to_internal_value(self, data): + """ + Validate that the input is a decimal number and return a Decimal + instance. + """ + + data = smart_str(data).strip() + + if self.localize: + data = sanitize_separators(data) + + if len(data) > self.MAX_STRING_LENGTH: + self.fail('max_string_length') + + try: + value = decimal.Decimal(data) + except decimal.DecimalException: + self.fail('invalid') + + if value.is_nan(): + self.fail('invalid') + + # Check for infinity and negative infinity. + if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')): + self.fail('invalid') + + return self.quantize(self.validate_precision(value)) + + def validate_precision(self, value): + """ + Ensure that there are no more than max_digits in the number, and no + more than decimal_places digits after the decimal point. + + Override this method to disable the precision validation for input + values or to enhance it in any way you need to. + """ + sign, digittuple, exponent = value.as_tuple() + + if exponent >= 0: + # 1234500.0 + total_digits = len(digittuple) + exponent + whole_digits = total_digits + decimal_places = 0 + elif len(digittuple) > abs(exponent): + # 123.45 + total_digits = len(digittuple) + whole_digits = total_digits - abs(exponent) + decimal_places = abs(exponent) + else: + # 0.001234 + total_digits = abs(exponent) + whole_digits = 0 + decimal_places = total_digits + + if self.max_digits is not None and total_digits > self.max_digits: + self.fail('max_digits', max_digits=self.max_digits) + if self.decimal_places is not None and decimal_places > self.decimal_places: + self.fail('max_decimal_places', max_decimal_places=self.decimal_places) + if self.max_whole_digits is not None and whole_digits > self.max_whole_digits: + self.fail('max_whole_digits', max_whole_digits=self.max_whole_digits) + + return value + + def to_representation(self, value): + coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING) + + if value is None: + if coerce_to_string: + return '' + else: + return None + + if not isinstance(value, decimal.Decimal): + value = decimal.Decimal(str(value).strip()) + + quantized = self.quantize(value) + + if not coerce_to_string: + return quantized + if self.localize: + return localize_input(quantized) + + return '{:f}'.format(quantized) + + def quantize(self, value): + """ + Quantize the decimal value to the configured precision. + """ + if self.decimal_places is None: + return value + + context = decimal.getcontext().copy() + if self.max_digits is not None: + context.prec = self.max_digits + return value.quantize( + decimal.Decimal('.1') ** self.decimal_places, + rounding=self.rounding, + context=context + ) + + +# Date & time fields... + +class DateTimeField(Field): + default_error_messages = { + 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), + 'date': _('Expected a datetime but got a date.'), + 'make_aware': _('Invalid datetime for the timezone "{timezone}".'), + 'overflow': _('Datetime value out of range.') + } + datetime_parser = datetime.datetime.strptime + + def __init__(self, format=empty, input_formats=None, default_timezone=None, **kwargs): + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats + if default_timezone is not None: + self.timezone = default_timezone + super().__init__(**kwargs) + + def enforce_timezone(self, value): + """ + When `self.default_timezone` is `None`, always return naive datetimes. + When `self.default_timezone` is not `None`, always return aware datetimes. + """ + field_timezone = self.timezone if hasattr(self, 'timezone') else self.default_timezone() + + if field_timezone is not None: + if timezone.is_aware(value): + try: + return value.astimezone(field_timezone) + except OverflowError: + self.fail('overflow') + try: + return timezone.make_aware(value, field_timezone) + except InvalidTimeError: + self.fail('make_aware', timezone=field_timezone) + elif (field_timezone is None) and timezone.is_aware(value): + return timezone.make_naive(value, datetime.timezone.utc) + return value + + def default_timezone(self): + return timezone.get_current_timezone() if settings.USE_TZ else None + + def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS) + + if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime): + self.fail('date') + + if isinstance(value, datetime.datetime): + return self.enforce_timezone(value) + + for input_format in input_formats: + if input_format.lower() == ISO_8601: + try: + parsed = parse_datetime(value) + if parsed is not None: + return self.enforce_timezone(parsed) + except (ValueError, TypeError): + pass + else: + try: + parsed = self.datetime_parser(value, input_format) + return self.enforce_timezone(parsed) + except (ValueError, TypeError): + pass + + humanized_format = humanize_datetime.datetime_formats(input_formats) + self.fail('invalid', format=humanized_format) + + def to_representation(self, value): + if not value: + return None + + output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT) + + if output_format is None or isinstance(value, str): + return value + + value = self.enforce_timezone(value) + + if output_format.lower() == ISO_8601: + value = value.isoformat() + if value.endswith('+00:00'): + value = value[:-6] + 'Z' + return value + return value.strftime(output_format) + + +class DateField(Field): + default_error_messages = { + 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), + 'datetime': _('Expected a date but got a datetime.'), + } + datetime_parser = datetime.datetime.strptime + + def __init__(self, format=empty, input_formats=None, **kwargs): + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats + super().__init__(**kwargs) + + def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) + + if isinstance(value, datetime.datetime): + self.fail('datetime') + + if isinstance(value, datetime.date): + return value + + for input_format in input_formats: + if input_format.lower() == ISO_8601: + try: + parsed = parse_date(value) + except (ValueError, TypeError): + pass + else: + if parsed is not None: + return parsed + else: + try: + parsed = self.datetime_parser(value, input_format) + except (ValueError, TypeError): + pass + else: + return parsed.date() + + humanized_format = humanize_datetime.date_formats(input_formats) + self.fail('invalid', format=humanized_format) + + def to_representation(self, value): + if not value: + return None + + output_format = getattr(self, 'format', api_settings.DATE_FORMAT) + + if output_format is None or isinstance(value, str): + return value + + # Applying a `DateField` to a datetime value is almost always + # not a sensible thing to do, as it means naively dropping + # any explicit or implicit timezone info. + assert not isinstance(value, datetime.datetime), ( + 'Expected a `date`, but got a `datetime`. Refusing to coerce, ' + 'as this may mean losing timezone information. Use a custom ' + 'read-only field and deal with timezone issues explicitly.' + ) + + if output_format.lower() == ISO_8601: + return value.isoformat() + + return value.strftime(output_format) + + +class TimeField(Field): + default_error_messages = { + 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), + } + datetime_parser = datetime.datetime.strptime + + def __init__(self, format=empty, input_formats=None, **kwargs): + if format is not empty: + self.format = format + if input_formats is not None: + self.input_formats = input_formats + super().__init__(**kwargs) + + def to_internal_value(self, value): + input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS) + + if isinstance(value, datetime.time): + return value + + for input_format in input_formats: + if input_format.lower() == ISO_8601: + try: + parsed = parse_time(value) + except (ValueError, TypeError): + pass + else: + if parsed is not None: + return parsed + else: + try: + parsed = self.datetime_parser(value, input_format) + except (ValueError, TypeError): + pass + else: + return parsed.time() + + humanized_format = humanize_datetime.time_formats(input_formats) + self.fail('invalid', format=humanized_format) + + def to_representation(self, value): + if value in (None, ''): + return None + + output_format = getattr(self, 'format', api_settings.TIME_FORMAT) + + if output_format is None or isinstance(value, str): + return value + + # Applying a `TimeField` to a datetime value is almost always + # not a sensible thing to do, as it means naively dropping + # any explicit or implicit timezone info. + assert not isinstance(value, datetime.datetime), ( + 'Expected a `time`, but got a `datetime`. Refusing to coerce, ' + 'as this may mean losing timezone information. Use a custom ' + 'read-only field and deal with timezone issues explicitly.' + ) + + if output_format.lower() == ISO_8601: + return value.isoformat() + return value.strftime(output_format) + + +class DurationField(Field): + default_error_messages = { + 'invalid': _('Duration has wrong format. Use one of these formats instead: {format}.'), + 'max_value': _('Ensure this value is less than or equal to {max_value}.'), + 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), + } + + def __init__(self, **kwargs): + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) + super().__init__(**kwargs) + if self.max_value is not None: + message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) + self.validators.append( + MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) + self.validators.append( + MinValueValidator(self.min_value, message=message)) + + def to_internal_value(self, value): + if isinstance(value, datetime.timedelta): + return value + parsed = parse_duration(str(value)) + if parsed is not None: + return parsed + self.fail('invalid', format='[DD] [HH:[MM:]]ss[.uuuuuu]') + + def to_representation(self, value): + return duration_string(value) + + +# Choice types... + +class ChoiceField(Field): + default_error_messages = { + 'invalid_choice': _('"{input}" is not a valid choice.') + } + html_cutoff = None + html_cutoff_text = _('More than {count} items...') + + def __init__(self, choices, **kwargs): + self.choices = choices + self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff) + self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text) + + self.allow_blank = kwargs.pop('allow_blank', False) + + super().__init__(**kwargs) + + def to_internal_value(self, data): + if data == '' and self.allow_blank: + return '' + + try: + return self.choice_strings_to_values[str(data)] + except KeyError: + self.fail('invalid_choice', input=data) + + def to_representation(self, value): + if value in ('', None): + return value + return self.choice_strings_to_values.get(str(value), value) + + def iter_options(self): + """ + Helper method for use with templates rendering select widgets. + """ + return iter_options( + self.grouped_choices, + cutoff=self.html_cutoff, + cutoff_text=self.html_cutoff_text + ) + + def _get_choices(self): + return self._choices + + def _set_choices(self, choices): + self.grouped_choices = to_choices_dict(choices) + self._choices = flatten_choices_dict(self.grouped_choices) + + # Map the string representation of choices to the underlying value. + # Allows us to deal with eg. integer choices while supporting either + # integer or string input, but still get the correct datatype out. + self.choice_strings_to_values = { + str(key): key for key in self.choices + } + + choices = property(_get_choices, _set_choices) + + +class MultipleChoiceField(ChoiceField): + default_error_messages = { + 'invalid_choice': _('"{input}" is not a valid choice.'), + 'not_a_list': _('Expected a list of items but got type "{input_type}".'), + 'empty': _('This selection may not be empty.') + } + default_empty_html = [] + + def __init__(self, **kwargs): + self.allow_empty = kwargs.pop('allow_empty', True) + super().__init__(**kwargs) + + def get_value(self, dictionary): + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty + # We override the default field access in order to support + # lists in HTML forms. + if html.is_html_input(dictionary): + return dictionary.getlist(self.field_name) + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + if isinstance(data, str) or not hasattr(data, '__iter__'): + self.fail('not_a_list', input_type=type(data).__name__) + if not self.allow_empty and len(data) == 0: + self.fail('empty') + + return { + # Arguments for super() are needed because of scoping inside + # comprehensions. + super(MultipleChoiceField, self).to_internal_value(item) + for item in data + } + + def to_representation(self, value): + return { + self.choice_strings_to_values.get(str(item), item) for item in value + } + + +class FilePathField(ChoiceField): + default_error_messages = { + 'invalid_choice': _('"{input}" is not a valid path choice.') + } + + def __init__(self, path, match=None, recursive=False, allow_files=True, + allow_folders=False, required=None, **kwargs): + # Defer to Django's FilePathField implementation to get the + # valid set of choices. + field = DjangoFilePathField( + path, match=match, recursive=recursive, allow_files=allow_files, + allow_folders=allow_folders, required=required + ) + kwargs['choices'] = field.choices + super().__init__(**kwargs) + + +# File types... + +class FileField(Field): + default_error_messages = { + 'required': _('No file was submitted.'), + 'invalid': _('The submitted data was not a file. Check the encoding type on the form.'), + 'no_name': _('No filename could be determined.'), + 'empty': _('The submitted file is empty.'), + 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), + } + + def __init__(self, **kwargs): + self.max_length = kwargs.pop('max_length', None) + self.allow_empty_file = kwargs.pop('allow_empty_file', False) + if 'use_url' in kwargs: + self.use_url = kwargs.pop('use_url') + super().__init__(**kwargs) + + def to_internal_value(self, data): + try: + # `UploadedFile` objects should have name and size attributes. + file_name = data.name + file_size = data.size + except AttributeError: + self.fail('invalid') + + if not file_name: + self.fail('no_name') + if not self.allow_empty_file and not file_size: + self.fail('empty') + if self.max_length and len(file_name) > self.max_length: + self.fail('max_length', max_length=self.max_length, length=len(file_name)) + + return data + + def to_representation(self, value): + if not value: + return None + + use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL) + if use_url: + try: + url = value.url + except AttributeError: + return None + request = self.context.get('request', None) + if request is not None: + return request.build_absolute_uri(url) + return url + + return value.name + + +class ImageField(FileField): + default_error_messages = { + 'invalid_image': _( + 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.' + ), + } + + def __init__(self, **kwargs): + self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField) + super().__init__(**kwargs) + + def to_internal_value(self, data): + # Image validation is a bit grungy, so we'll just outright + # defer to Django's implementation so we don't need to + # consider it, or treat PIL as a test dependency. + file_object = super().to_internal_value(data) + django_field = self._DjangoImageField() + django_field.error_messages = self.error_messages + return django_field.clean(file_object) + + +# Composite field types... + +class _UnvalidatedField(Field): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.allow_blank = True + self.allow_null = True + + def to_internal_value(self, data): + return data + + def to_representation(self, value): + return value + + +class ListField(Field): + child = _UnvalidatedField() + initial = [] + default_error_messages = { + 'not_a_list': _('Expected a list of items but got type "{input_type}".'), + 'empty': _('This list may not be empty.'), + 'min_length': _('Ensure this field has at least {min_length} elements.'), + 'max_length': _('Ensure this field has no more than {max_length} elements.') + } + + def __init__(self, **kwargs): + self.child = kwargs.pop('child', copy.deepcopy(self.child)) + self.allow_empty = kwargs.pop('allow_empty', True) + self.max_length = kwargs.pop('max_length', None) + self.min_length = kwargs.pop('min_length', None) + + assert not inspect.isclass(self.child), '`child` has not been instantiated.' + assert self.child.source is None, ( + "The `source` argument is not meaningful when applied to a `child=` field. " + "Remove `source=` from the field declaration." + ) + + super().__init__(**kwargs) + self.child.bind(field_name='', parent=self) + if self.max_length is not None: + message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) + self.validators.append(MaxLengthValidator(self.max_length, message=message)) + if self.min_length is not None: + message = lazy_format(self.error_messages['min_length'], min_length=self.min_length) + self.validators.append(MinLengthValidator(self.min_length, message=message)) + + def get_value(self, dictionary): + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty + # We override the default field access in order to support + # lists in HTML forms. + if html.is_html_input(dictionary): + val = dictionary.getlist(self.field_name, []) + if len(val) > 0: + # Support QueryDict lists in HTML input. + return val + return html.parse_html_list(dictionary, prefix=self.field_name, default=empty) + + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + """ + List of dicts of native values <- List of dicts of primitive datatypes. + """ + if html.is_html_input(data): + data = html.parse_html_list(data, default=[]) + if isinstance(data, (str, Mapping)) or not hasattr(data, '__iter__'): + self.fail('not_a_list', input_type=type(data).__name__) + if not self.allow_empty and len(data) == 0: + self.fail('empty') + return self.run_child_validation(data) + + def to_representation(self, data): + """ + List of object instances -> List of dicts of primitive datatypes. + """ + return [self.child.to_representation(item) if item is not None else None for item in data] + + def run_child_validation(self, data): + result = [] + errors = OrderedDict() + + for idx, item in enumerate(data): + try: + result.append(self.child.run_validation(item)) + except ValidationError as e: + errors[idx] = e.detail + + if not errors: + return result + raise ValidationError(errors) + + +class DictField(Field): + child = _UnvalidatedField() + initial = {} + default_error_messages = { + 'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".'), + 'empty': _('This dictionary may not be empty.'), + } + + def __init__(self, **kwargs): + self.child = kwargs.pop('child', copy.deepcopy(self.child)) + self.allow_empty = kwargs.pop('allow_empty', True) + + assert not inspect.isclass(self.child), '`child` has not been instantiated.' + assert self.child.source is None, ( + "The `source` argument is not meaningful when applied to a `child=` field. " + "Remove `source=` from the field declaration." + ) + + super().__init__(**kwargs) + self.child.bind(field_name='', parent=self) + + def get_value(self, dictionary): + # We override the default field access in order to support + # dictionaries in HTML forms. + if html.is_html_input(dictionary): + return html.parse_html_dict(dictionary, prefix=self.field_name) + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + """ + Dicts of native values <- Dicts of primitive datatypes. + """ + if html.is_html_input(data): + data = html.parse_html_dict(data) + if not isinstance(data, dict): + self.fail('not_a_dict', input_type=type(data).__name__) + if not self.allow_empty and len(data) == 0: + self.fail('empty') + + return self.run_child_validation(data) + + def to_representation(self, value): + return { + str(key): self.child.to_representation(val) if val is not None else None + for key, val in value.items() + } + + def run_child_validation(self, data): + result = {} + errors = OrderedDict() + + for key, value in data.items(): + key = str(key) + + try: + result[key] = self.child.run_validation(value) + except ValidationError as e: + errors[key] = e.detail + + if not errors: + return result + raise ValidationError(errors) + + +class HStoreField(DictField): + child = CharField(allow_blank=True, allow_null=True) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + assert isinstance(self.child, CharField), ( + "The `child` argument must be an instance of `CharField`, " + "as the hstore extension stores values as strings." + ) + + +class JSONField(Field): + default_error_messages = { + 'invalid': _('Value must be valid JSON.') + } + + # Workaround for isinstance calls when importing the field isn't possible + _is_jsonfield = True + + def __init__(self, **kwargs): + self.binary = kwargs.pop('binary', False) + self.encoder = kwargs.pop('encoder', None) + self.decoder = kwargs.pop('decoder', None) + super().__init__(**kwargs) + + def get_value(self, dictionary): + if html.is_html_input(dictionary) and self.field_name in dictionary: + # When HTML form input is used, mark up the input + # as being a JSON string, rather than a JSON primitive. + class JSONString(str): + def __new__(cls, value): + ret = str.__new__(cls, value) + ret.is_json_string = True + return ret + return JSONString(dictionary[self.field_name]) + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + try: + if self.binary or getattr(data, 'is_json_string', False): + if isinstance(data, bytes): + data = data.decode() + return json.loads(data, cls=self.decoder) + else: + json.dumps(data, cls=self.encoder) + except (TypeError, ValueError): + self.fail('invalid') + return data + + def to_representation(self, value): + if self.binary: + value = json.dumps(value, cls=self.encoder) + value = value.encode() + return value + + +# Miscellaneous field types... + +class ReadOnlyField(Field): + """ + A read-only field that simply returns the field value. + + If the field is a method with no parameters, the method will be called + and its return value used as the representation. + + For example, the following would call `get_expiry_date()` on the object: + + class ExampleSerializer(Serializer): + expiry_date = ReadOnlyField(source='get_expiry_date') + """ + + def __init__(self, **kwargs): + kwargs['read_only'] = True + super().__init__(**kwargs) + + def to_representation(self, value): + return value + + +class HiddenField(Field): + """ + A hidden field does not take input from the user, or present any output, + but it does populate a field in `validated_data`, based on its default + value. This is particularly useful when we have a `unique_for_date` + constraint on a pair of fields, as we need some way to include the date in + the validated data. + """ + def __init__(self, **kwargs): + assert 'default' in kwargs, 'default is a required argument.' + kwargs['write_only'] = True + super().__init__(**kwargs) + + def get_value(self, dictionary): + # We always use the default value for `HiddenField`. + # User input is never provided or accepted. + return empty + + def to_internal_value(self, data): + return data + + +class SerializerMethodField(Field): + """ + A read-only field that get its representation from calling a method on the + parent serializer class. The method called will be of the form + "get_{field_name}", and should take a single argument, which is the + object being serialized. + + For example: + + class ExampleSerializer(self): + extra_info = SerializerMethodField() + + def get_extra_info(self, obj): + return ... # Calculate some data to return. + """ + def __init__(self, method_name=None, **kwargs): + self.method_name = method_name + kwargs['source'] = '*' + kwargs['read_only'] = True + super().__init__(**kwargs) + + def bind(self, field_name, parent): + # The method name defaults to `get_{field_name}`. + if self.method_name is None: + self.method_name = 'get_{field_name}'.format(field_name=field_name) + + super().bind(field_name, parent) + + def to_representation(self, value): + method = getattr(self.parent, self.method_name) + return method(value) + + +class ModelField(Field): + """ + A generic field that can be used against an arbitrary model field. + + This is used by `ModelSerializer` when dealing with custom model fields, + that do not have a serializer field to be mapped to. + """ + default_error_messages = { + 'max_length': _('Ensure this field has no more than {max_length} characters.'), + } + + def __init__(self, model_field, **kwargs): + self.model_field = model_field + # The `max_length` option is supported by Django's base `Field` class, + # so we'd better support it here. + self.max_length = kwargs.pop('max_length', None) + super().__init__(**kwargs) + if self.max_length is not None: + message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) + self.validators.append( + MaxLengthValidator(self.max_length, message=message)) + + def to_internal_value(self, data): + rel = self.model_field.remote_field + if rel is not None: + return rel.model._meta.get_field(rel.field_name).to_python(data) + return self.model_field.to_python(data) + + def get_attribute(self, obj): + # We pass the object instance onto `to_representation`, + # not just the field attribute. + return obj + + def to_representation(self, obj): + value = self.model_field.value_from_object(obj) + if is_protected_type(value): + return value + return self.model_field.value_to_string(obj) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/filters.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/filters.py new file mode 100644 index 0000000000000000000000000000000000000000..1ffd9edc0228eff2855330bde4e14345fedc961f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/filters.py @@ -0,0 +1,333 @@ +""" +Provides generic filtering backends that can be used to filter the results +returned by list views. +""" +import operator +from functools import reduce + +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.db.models.constants import LOOKUP_SEP +from django.template import loader +from django.utils.encoding import force_str +from django.utils.translation import gettext_lazy as _ + +from rest_framework.compat import coreapi, coreschema, distinct +from rest_framework.settings import api_settings + + +class BaseFilterBackend: + """ + A base class from which all filter backend classes should inherit. + """ + + def filter_queryset(self, request, queryset, view): + """ + Return a filtered queryset. + """ + raise NotImplementedError(".filter_queryset() must be overridden.") + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + return [] + + def get_schema_operation_parameters(self, view): + return [] + + +class SearchFilter(BaseFilterBackend): + # The URL query parameter used for the search. + search_param = api_settings.SEARCH_PARAM + template = 'rest_framework/filters/search.html' + lookup_prefixes = { + '^': 'istartswith', + '=': 'iexact', + '@': 'search', + '$': 'iregex', + } + search_title = _('Search') + search_description = _('A search term.') + + def get_search_fields(self, view, request): + """ + Search fields are obtained from the view, but the request is always + passed to this method. Sub-classes can override this method to + dynamically change the search fields based on request content. + """ + return getattr(view, 'search_fields', None) + + def get_search_terms(self, request): + """ + Search terms are set by a ?search=... query parameter, + and may be comma and/or whitespace delimited. + """ + params = request.query_params.get(self.search_param, '') + params = params.replace('\x00', '') # strip null characters + params = params.replace(',', ' ') + return params.split() + + def construct_search(self, field_name): + lookup = self.lookup_prefixes.get(field_name[0]) + if lookup: + field_name = field_name[1:] + else: + lookup = 'icontains' + return LOOKUP_SEP.join([field_name, lookup]) + + def must_call_distinct(self, queryset, search_fields): + """ + Return True if 'distinct()' should be used to query the given lookups. + """ + for search_field in search_fields: + opts = queryset.model._meta + if search_field[0] in self.lookup_prefixes: + search_field = search_field[1:] + # Annotated fields do not need to be distinct + if isinstance(queryset, models.QuerySet) and search_field in queryset.query.annotations: + continue + parts = search_field.split(LOOKUP_SEP) + for part in parts: + field = opts.get_field(part) + if hasattr(field, 'get_path_info'): + # This field is a relation, update opts to follow the relation + path_info = field.get_path_info() + opts = path_info[-1].to_opts + if any(path.m2m for path in path_info): + # This field is a m2m relation so we know we need to call distinct + return True + else: + # This field has a custom __ query transform but is not a relational field. + break + return False + + def filter_queryset(self, request, queryset, view): + search_fields = self.get_search_fields(view, request) + search_terms = self.get_search_terms(request) + + if not search_fields or not search_terms: + return queryset + + orm_lookups = [ + self.construct_search(str(search_field)) + for search_field in search_fields + ] + + base = queryset + conditions = [] + for search_term in search_terms: + queries = [ + models.Q(**{orm_lookup: search_term}) + for orm_lookup in orm_lookups + ] + conditions.append(reduce(operator.or_, queries)) + queryset = queryset.filter(reduce(operator.and_, conditions)) + + if self.must_call_distinct(queryset, search_fields): + # Filtering against a many-to-many field requires us to + # call queryset.distinct() in order to avoid duplicate items + # in the resulting queryset. + # We try to avoid this if possible, for performance reasons. + queryset = distinct(queryset, base) + return queryset + + def to_html(self, request, queryset, view): + if not getattr(view, 'search_fields', None): + return '' + + term = self.get_search_terms(request) + term = term[0] if term else '' + context = { + 'param': self.search_param, + 'term': term + } + template = loader.get_template(self.template) + return template.render(context) + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + return [ + coreapi.Field( + name=self.search_param, + required=False, + location='query', + schema=coreschema.String( + title=force_str(self.search_title), + description=force_str(self.search_description) + ) + ) + ] + + def get_schema_operation_parameters(self, view): + return [ + { + 'name': self.search_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.search_description), + 'schema': { + 'type': 'string', + }, + }, + ] + + +class OrderingFilter(BaseFilterBackend): + # The URL query parameter used for the ordering. + ordering_param = api_settings.ORDERING_PARAM + ordering_fields = None + ordering_title = _('Ordering') + ordering_description = _('Which field to use when ordering the results.') + template = 'rest_framework/filters/ordering.html' + + def get_ordering(self, request, queryset, view): + """ + Ordering is set by a comma delimited ?ordering=... query parameter. + + The `ordering` query parameter can be overridden by setting + the `ordering_param` value on the OrderingFilter or by + specifying an `ORDERING_PARAM` value in the API settings. + """ + params = request.query_params.get(self.ordering_param) + if params: + fields = [param.strip() for param in params.split(',')] + ordering = self.remove_invalid_fields(queryset, fields, view, request) + if ordering: + return ordering + + # No ordering was included, or all the ordering fields were invalid + return self.get_default_ordering(view) + + def get_default_ordering(self, view): + ordering = getattr(view, 'ordering', None) + if isinstance(ordering, str): + return (ordering,) + return ordering + + def get_default_valid_fields(self, queryset, view, context={}): + # If `ordering_fields` is not specified, then we determine a default + # based on the serializer class, if one exists on the view. + if hasattr(view, 'get_serializer_class'): + try: + serializer_class = view.get_serializer_class() + except AssertionError: + # Raised by the default implementation if + # no serializer_class was found + serializer_class = None + else: + serializer_class = getattr(view, 'serializer_class', None) + + if serializer_class is None: + msg = ( + "Cannot use %s on a view which does not have either a " + "'serializer_class', an overriding 'get_serializer_class' " + "or 'ordering_fields' attribute." + ) + raise ImproperlyConfigured(msg % self.__class__.__name__) + + model_class = queryset.model + model_property_names = [ + # 'pk' is a property added in Django's Model class, however it is valid for ordering. + attr for attr in dir(model_class) if isinstance(getattr(model_class, attr), property) and attr != 'pk' + ] + + return [ + (field.source.replace('.', '__') or field_name, field.label) + for field_name, field in serializer_class(context=context).fields.items() + if ( + not getattr(field, 'write_only', False) and + not field.source == '*' and + field.source not in model_property_names + ) + ] + + def get_valid_fields(self, queryset, view, context={}): + valid_fields = getattr(view, 'ordering_fields', self.ordering_fields) + + if valid_fields is None: + # Default to allowing filtering on serializer fields + return self.get_default_valid_fields(queryset, view, context) + + elif valid_fields == '__all__': + # View explicitly allows filtering on any model field + valid_fields = [ + (field.name, field.verbose_name) for field in queryset.model._meta.fields + ] + valid_fields += [ + (key, key.title().split('__')) + for key in queryset.query.annotations + ] + else: + valid_fields = [ + (item, item) if isinstance(item, str) else item + for item in valid_fields + ] + + return valid_fields + + def remove_invalid_fields(self, queryset, fields, view, request): + valid_fields = [item[0] for item in self.get_valid_fields(queryset, view, {'request': request})] + + def term_valid(term): + if term.startswith("-"): + term = term[1:] + return term in valid_fields + + return [term for term in fields if term_valid(term)] + + def filter_queryset(self, request, queryset, view): + ordering = self.get_ordering(request, queryset, view) + + if ordering: + return queryset.order_by(*ordering) + + return queryset + + def get_template_context(self, request, queryset, view): + current = self.get_ordering(request, queryset, view) + current = None if not current else current[0] + options = [] + context = { + 'request': request, + 'current': current, + 'param': self.ordering_param, + } + for key, label in self.get_valid_fields(queryset, view, context): + options.append((key, '%s - %s' % (label, _('ascending')))) + options.append(('-' + key, '%s - %s' % (label, _('descending')))) + context['options'] = options + return context + + def to_html(self, request, queryset, view): + template = loader.get_template(self.template) + context = self.get_template_context(request, queryset, view) + return template.render(context) + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + return [ + coreapi.Field( + name=self.ordering_param, + required=False, + location='query', + schema=coreschema.String( + title=force_str(self.ordering_title), + description=force_str(self.ordering_description) + ) + ) + ] + + def get_schema_operation_parameters(self, view): + return [ + { + 'name': self.ordering_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.ordering_description), + 'schema': { + 'type': 'string', + }, + }, + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/generics.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/generics.py new file mode 100644 index 0000000000000000000000000000000000000000..55cfafda443d2728048823ac9fe5a934e7935010 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/generics.py @@ -0,0 +1,291 @@ +""" +Generic views that provide commonly needed behaviour. +""" +from django.core.exceptions import ValidationError +from django.db.models.query import QuerySet +from django.http import Http404 +from django.shortcuts import get_object_or_404 as _get_object_or_404 + +from rest_framework import mixins, views +from rest_framework.settings import api_settings + + +def get_object_or_404(queryset, *filter_args, **filter_kwargs): + """ + Same as Django's standard shortcut, but make sure to also raise 404 + if the filter_kwargs don't match the required types. + """ + try: + return _get_object_or_404(queryset, *filter_args, **filter_kwargs) + except (TypeError, ValueError, ValidationError): + raise Http404 + + +class GenericAPIView(views.APIView): + """ + Base class for all other generic views. + """ + # You'll need to either set these attributes, + # or override `get_queryset()`/`get_serializer_class()`. + # If you are overriding a view method, it is important that you call + # `get_queryset()` instead of accessing the `queryset` property directly, + # as `queryset` will get evaluated only once, and those results are cached + # for all subsequent requests. + queryset = None + serializer_class = None + + # If you want to use object lookups other than pk, set 'lookup_field'. + # For more complex lookup requirements override `get_object()`. + lookup_field = 'pk' + lookup_url_kwarg = None + + # The filter backend classes to use for queryset filtering + filter_backends = api_settings.DEFAULT_FILTER_BACKENDS + + # The style to use for queryset pagination. + pagination_class = api_settings.DEFAULT_PAGINATION_CLASS + + def get_queryset(self): + """ + Get the list of items for this view. + This must be an iterable, and may be a queryset. + Defaults to using `self.queryset`. + + This method should always be used rather than accessing `self.queryset` + directly, as `self.queryset` gets evaluated only once, and those results + are cached for all subsequent requests. + + You may want to override this if you need to provide different + querysets depending on the incoming request. + + (Eg. return a list of items that is specific to the user) + """ + assert self.queryset is not None, ( + "'%s' should either include a `queryset` attribute, " + "or override the `get_queryset()` method." + % self.__class__.__name__ + ) + + queryset = self.queryset + if isinstance(queryset, QuerySet): + # Ensure queryset is re-evaluated on each request. + queryset = queryset.all() + return queryset + + def get_object(self): + """ + Returns the object the view is displaying. + + You may want to override this if you need to provide non-standard + queryset lookups. Eg if objects are referenced using multiple + keyword arguments in the url conf. + """ + queryset = self.filter_queryset(self.get_queryset()) + + # Perform the lookup filtering. + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + + assert lookup_url_kwarg in self.kwargs, ( + 'Expected view %s to be called with a URL keyword argument ' + 'named "%s". Fix your URL conf, or set the `.lookup_field` ' + 'attribute on the view correctly.' % + (self.__class__.__name__, lookup_url_kwarg) + ) + + filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} + obj = get_object_or_404(queryset, **filter_kwargs) + + # May raise a permission denied + self.check_object_permissions(self.request, obj) + + return obj + + def get_serializer(self, *args, **kwargs): + """ + Return the serializer instance that should be used for validating and + deserializing input, and for serializing output. + """ + serializer_class = self.get_serializer_class() + kwargs.setdefault('context', self.get_serializer_context()) + return serializer_class(*args, **kwargs) + + def get_serializer_class(self): + """ + Return the class to use for the serializer. + Defaults to using `self.serializer_class`. + + You may want to override this if you need to provide different + serializations depending on the incoming request. + + (Eg. admins get full serialization, others get basic serialization) + """ + assert self.serializer_class is not None, ( + "'%s' should either include a `serializer_class` attribute, " + "or override the `get_serializer_class()` method." + % self.__class__.__name__ + ) + + return self.serializer_class + + def get_serializer_context(self): + """ + Extra context provided to the serializer class. + """ + return { + 'request': self.request, + 'format': self.format_kwarg, + 'view': self + } + + def filter_queryset(self, queryset): + """ + Given a queryset, filter it with whichever filter backend is in use. + + You are unlikely to want to override this method, although you may need + to call it either from a list view, or from a custom `get_object` + method if you want to apply the configured filtering backend to the + default queryset. + """ + for backend in list(self.filter_backends): + queryset = backend().filter_queryset(self.request, queryset, self) + return queryset + + @property + def paginator(self): + """ + The paginator instance associated with the view, or `None`. + """ + if not hasattr(self, '_paginator'): + if self.pagination_class is None: + self._paginator = None + else: + self._paginator = self.pagination_class() + return self._paginator + + def paginate_queryset(self, queryset): + """ + Return a single page of results, or `None` if pagination is disabled. + """ + if self.paginator is None: + return None + return self.paginator.paginate_queryset(queryset, self.request, view=self) + + def get_paginated_response(self, data): + """ + Return a paginated style `Response` object for the given output data. + """ + assert self.paginator is not None + return self.paginator.get_paginated_response(data) + + +# Concrete view classes that provide method handlers +# by composing the mixin classes with the base view. + +class CreateAPIView(mixins.CreateModelMixin, + GenericAPIView): + """ + Concrete view for creating a model instance. + """ + def post(self, request, *args, **kwargs): + return self.create(request, *args, **kwargs) + + +class ListAPIView(mixins.ListModelMixin, + GenericAPIView): + """ + Concrete view for listing a queryset. + """ + def get(self, request, *args, **kwargs): + return self.list(request, *args, **kwargs) + + +class RetrieveAPIView(mixins.RetrieveModelMixin, + GenericAPIView): + """ + Concrete view for retrieving a model instance. + """ + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + +class DestroyAPIView(mixins.DestroyModelMixin, + GenericAPIView): + """ + Concrete view for deleting a model instance. + """ + def delete(self, request, *args, **kwargs): + return self.destroy(request, *args, **kwargs) + + +class UpdateAPIView(mixins.UpdateModelMixin, + GenericAPIView): + """ + Concrete view for updating a model instance. + """ + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + def patch(self, request, *args, **kwargs): + return self.partial_update(request, *args, **kwargs) + + +class ListCreateAPIView(mixins.ListModelMixin, + mixins.CreateModelMixin, + GenericAPIView): + """ + Concrete view for listing a queryset or creating a model instance. + """ + def get(self, request, *args, **kwargs): + return self.list(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + return self.create(request, *args, **kwargs) + + +class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + GenericAPIView): + """ + Concrete view for retrieving, updating a model instance. + """ + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + def patch(self, request, *args, **kwargs): + return self.partial_update(request, *args, **kwargs) + + +class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + GenericAPIView): + """ + Concrete view for retrieving or deleting a model instance. + """ + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + return self.destroy(request, *args, **kwargs) + + +class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericAPIView): + """ + Concrete view for retrieving, updating or deleting a model instance. + """ + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + def patch(self, request, *args, **kwargs): + return self.partial_update(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + return self.destroy(request, *args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ach/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ach/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0fe8c3e93a7058da492d7ff8452b42a578db63e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ach/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ar/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ar/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f793d7c73b74b37eee04252018de72e7505a305d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ar/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/az/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/az/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..08648351e8ed72361f7148ed5f2e38e412dea206 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/az/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/be/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/be/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..62321f7a4047ff74e384431a3e49417131b17693 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/be/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/bg/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/bg/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..71a0d8a74863adbce4792dd85f71dd318fa09d8c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/bg/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7da9971a8ec201a5e8907883c09508c10db7c4d9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca_ES/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca_ES/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f46cd7f6de12ec75843a836a5aace6de2619b614 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ca_ES/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/cs/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ebf7db5aa7b4cb3f8bc3c7e406e4246ea92501ce Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/cs/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/da/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d70bc13a51ec471f0bb2093aac13daead653e7e2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/da/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/de/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..98688039789f0300dd6aed554c84050365f9991c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/de/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f434e6fc9067325f42f365893ffa52e35dd577bc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el_GR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el_GR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f23ce5f267bd9cba20cce38ac773030ea9ef256 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/el_GR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0770a9d5e7d6269e71717c100aa98d02275cfa7e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_AU/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_AU/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3a595d935c66c95ffa0ede345d185429fde0fd5b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_AU/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_CA/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_CA/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..930db1b4e55435d30687e4309f37a4ff74dd8320 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_CA/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_US/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_US/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c5906d1cd061dff54de8b533942893de34efc9e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/en_US/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/es/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..16df627fcc901ed5fb7307de1b195c5672dad071 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/es/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/et/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/et/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e14ea9e270d7b06ac9ad497bf06c55378c98c170 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/et/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..099318e69a178c32d30b3ddcefbec1a8579d8d55 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa_IR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa_IR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..52d3f3bf84e43fd3972255b9ae363c56677e4d00 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fa_IR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fi/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fi/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..50a6d0f8a9fb01938b54ccd72ef0d55931faf36a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fi/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a1c0b3c2d4a0e9d28c07dac5652968dee90fcff6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr_CA/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr_CA/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..77bcff117b96241947f9688adf731ba475b95088 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/fr_CA/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..87d65da74aecdad411178afb03fdc78291931a79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl_ES/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl_ES/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a9a0273f192d60396ce41bb11e916f510c201459 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/gl_ES/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/he_IL/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/he_IL/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..acd15d9fd06fd6c231092fa08f99d4cac1c19107 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/he_IL/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hu/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hu/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..61f285299f185130df373672340c8f4146af0556 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hu/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hy/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hy/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c5f3ebcfaa1efa88d9c0bbd02b03d659b1ae662c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/hy/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/id/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/id/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c67e2a1da9e52599dd32d35227af0187b2ec1b12 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/id/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/it/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c84273a9228807bff9e2698eaf72d15892722cc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/it/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ja/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ja/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e949a57f792568f3e4200b448b49a1f59b8b6bab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ja/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c3aeb27a96e5c3b3ef9e61ac79e9ad229463ec7c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lt/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..b43a6a8a4dfe2dd8777393c186c605423e76089c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lt/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lv/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lv/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7ee7172407f2e4b860d57c55ce1d73a04f42f0a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/lv/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/mk/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/mk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4c13e5a3df71ee2357544a6a7386ed8cdce59f37 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/mk/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nb/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nb/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..bd983b292c4cb1c0223b45b9624554ca496ec38d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nb/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ne_NP/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ne_NP/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a9071d09e83417e0d10cf349f5e2f9f8d9f9a2d4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ne_NP/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nl/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4691ca63fffdb0a1e8a48941f95a499d7f227728 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nl/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nn/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nn/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6c28661ea5d57a068c42676d8b44d737456de0c2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/nn/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/no/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/no/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..808e0a2d54b6c204ca54f542a1969cf7638e1a42 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/no/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pl/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f265186aef076fe1a2729562bc13a39773879530 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pl/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..653cce97ebb8df40090f661e659d22b6d322575d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a6e3788e651dfed18d4d5cb4efe1ab658b6ed59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_PT/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_PT/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..67da6164b9275741397768929e7284305f1379c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/pt_PT/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ro/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ro/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0c9fb9c560564aef7eedc70fb9bb634d02ccf74a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ro/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..82688a41205544a65abef56ffcbdd70f883c70f4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru_RU/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru_RU/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d6da8f432d9025af1a83c7c408f46d16e8368f68 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/ru_RU/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sk/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..561c98e98847ec949c767ff3a251f017130b8dc9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sk/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sl/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7ec83f821634b41b2c0a9f5ffef75ec33aedf0d6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sl/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sv/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sv/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..fb1a9f6f9e3f6ec7ddc3294224384284e7f8d122 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/sv/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/th/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/th/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4a2b85a9bb977c0b5c54ea19106fc5b912da14fa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/th/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6386aab5236ae56a95525a2b2c525baa555c3963 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr_TR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr_TR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3751732bed5bf46bde9aeb814b71f2a8e1d419a5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/tr_TR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/uk/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/uk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..18c3242bbed7b0a0ad675349c155e3939d2d3c1d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/uk/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/vi/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/vi/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6809b650c1d85cfa5ec65341ba957cd98eaa09da Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/vi/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3bd1fd3efa65ee170719887e0f0eff038e4accb8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..670228a8346076571906d56e43817d7e8354163c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..26ea0cee93d7fd2fd2dd8695ed3a50c0c1269b10 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_TW/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_TW/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f85c2f82b5b8357a4ccd0ad8893567488e4da39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/locale/zh_TW/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bada7bb3959bf1dcdfcbe04f5aa90ad68a3edde6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecd38ced23b365c4d23ec6514c702d8783d2ff62 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/generateschema.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/generateschema.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b307ee42465f5ddcd5d2e7586b6170d0be48df68 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/__pycache__/generateschema.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/generateschema.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/generateschema.py new file mode 100644 index 0000000000000000000000000000000000000000..8c73e4b9c8e86ab98b04852f73b9357a0e385557 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/management/commands/generateschema.py @@ -0,0 +1,71 @@ +from django.core.management.base import BaseCommand +from django.utils.module_loading import import_string + +from rest_framework import renderers +from rest_framework.schemas import coreapi +from rest_framework.schemas.openapi import SchemaGenerator + +OPENAPI_MODE = 'openapi' +COREAPI_MODE = 'coreapi' + + +class Command(BaseCommand): + help = "Generates configured API schema for project." + + def get_mode(self): + return COREAPI_MODE if coreapi.is_enabled() else OPENAPI_MODE + + def add_arguments(self, parser): + parser.add_argument('--title', dest="title", default='', type=str) + parser.add_argument('--url', dest="url", default=None, type=str) + parser.add_argument('--description', dest="description", default=None, type=str) + if self.get_mode() == COREAPI_MODE: + parser.add_argument('--format', dest="format", choices=['openapi', 'openapi-json', 'corejson'], default='openapi', type=str) + else: + parser.add_argument('--format', dest="format", choices=['openapi', 'openapi-json'], default='openapi', type=str) + parser.add_argument('--urlconf', dest="urlconf", default=None, type=str) + parser.add_argument('--generator_class', dest="generator_class", default=None, type=str) + parser.add_argument('--file', dest="file", default=None, type=str) + parser.add_argument('--api_version', dest="api_version", default='', type=str) + + def handle(self, *args, **options): + if options['generator_class']: + generator_class = import_string(options['generator_class']) + else: + generator_class = self.get_generator_class() + generator = generator_class( + url=options['url'], + title=options['title'], + description=options['description'], + urlconf=options['urlconf'], + version=options['api_version'], + ) + schema = generator.get_schema(request=None, public=True) + renderer = self.get_renderer(options['format']) + output = renderer.render(schema, renderer_context={}) + + if options['file']: + with open(options['file'], 'wb') as f: + f.write(output) + else: + self.stdout.write(output.decode()) + + def get_renderer(self, format): + if self.get_mode() == COREAPI_MODE: + renderer_cls = { + 'corejson': renderers.CoreJSONRenderer, + 'openapi': renderers.CoreAPIOpenAPIRenderer, + 'openapi-json': renderers.CoreAPIJSONOpenAPIRenderer, + }[format] + return renderer_cls() + + renderer_cls = { + 'openapi': renderers.OpenAPIRenderer, + 'openapi-json': renderers.JSONOpenAPIRenderer, + }[format] + return renderer_cls() + + def get_generator_class(self): + if self.get_mode() == COREAPI_MODE: + return coreapi.SchemaGenerator + return SchemaGenerator diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/metadata.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..7708fe0a21c036610a9d4075f266320b88dcffdc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/metadata.py @@ -0,0 +1,150 @@ +""" +The metadata API is used to allow customization of how `OPTIONS` requests +are handled. We currently provide a single default implementation that returns +some fairly ad-hoc information about the view. + +Future implementations might use JSON schema or other definitions in order +to return this information in a more standardized way. +""" +from collections import OrderedDict + +from django.core.exceptions import PermissionDenied +from django.http import Http404 +from django.utils.encoding import force_str + +from rest_framework import exceptions, serializers +from rest_framework.request import clone_request +from rest_framework.utils.field_mapping import ClassLookupDict + + +class BaseMetadata: + def determine_metadata(self, request, view): + """ + Return a dictionary of metadata about the view. + Used to return responses for OPTIONS requests. + """ + raise NotImplementedError(".determine_metadata() must be overridden.") + + +class SimpleMetadata(BaseMetadata): + """ + This is the default metadata implementation. + It returns an ad-hoc set of information about the view. + There are not any formalized standards for `OPTIONS` responses + for us to base this on. + """ + label_lookup = ClassLookupDict({ + serializers.Field: 'field', + serializers.BooleanField: 'boolean', + serializers.CharField: 'string', + serializers.UUIDField: 'string', + serializers.URLField: 'url', + serializers.EmailField: 'email', + serializers.RegexField: 'regex', + serializers.SlugField: 'slug', + serializers.IntegerField: 'integer', + serializers.FloatField: 'float', + serializers.DecimalField: 'decimal', + serializers.DateField: 'date', + serializers.DateTimeField: 'datetime', + serializers.TimeField: 'time', + serializers.ChoiceField: 'choice', + serializers.MultipleChoiceField: 'multiple choice', + serializers.FileField: 'file upload', + serializers.ImageField: 'image upload', + serializers.ListField: 'list', + serializers.DictField: 'nested object', + serializers.Serializer: 'nested object', + }) + + def determine_metadata(self, request, view): + metadata = OrderedDict() + metadata['name'] = view.get_view_name() + metadata['description'] = view.get_view_description() + metadata['renders'] = [renderer.media_type for renderer in view.renderer_classes] + metadata['parses'] = [parser.media_type for parser in view.parser_classes] + if hasattr(view, 'get_serializer'): + actions = self.determine_actions(request, view) + if actions: + metadata['actions'] = actions + return metadata + + def determine_actions(self, request, view): + """ + For generic class based views we return information about + the fields that are accepted for 'PUT' and 'POST' methods. + """ + actions = {} + for method in {'PUT', 'POST'} & set(view.allowed_methods): + view.request = clone_request(request, method) + try: + # Test global permissions + if hasattr(view, 'check_permissions'): + view.check_permissions(view.request) + # Test object permissions + if method == 'PUT' and hasattr(view, 'get_object'): + view.get_object() + except (exceptions.APIException, PermissionDenied, Http404): + pass + else: + # If user has appropriate permissions for the view, include + # appropriate metadata about the fields that should be supplied. + serializer = view.get_serializer() + actions[method] = self.get_serializer_info(serializer) + finally: + view.request = request + + return actions + + def get_serializer_info(self, serializer): + """ + Given an instance of a serializer, return a dictionary of metadata + about its fields. + """ + if hasattr(serializer, 'child'): + # If this is a `ListSerializer` then we want to examine the + # underlying child serializer instance instead. + serializer = serializer.child + return OrderedDict([ + (field_name, self.get_field_info(field)) + for field_name, field in serializer.fields.items() + if not isinstance(field, serializers.HiddenField) + ]) + + def get_field_info(self, field): + """ + Given an instance of a serializer field, return a dictionary + of metadata about it. + """ + field_info = OrderedDict() + field_info['type'] = self.label_lookup[field] + field_info['required'] = getattr(field, 'required', False) + + attrs = [ + 'read_only', 'label', 'help_text', + 'min_length', 'max_length', + 'min_value', 'max_value' + ] + + for attr in attrs: + value = getattr(field, attr, None) + if value is not None and value != '': + field_info[attr] = force_str(value, strings_only=True) + + if getattr(field, 'child', None): + field_info['child'] = self.get_field_info(field.child) + elif getattr(field, 'fields', None): + field_info['children'] = self.get_serializer_info(field) + + if (not field_info.get('read_only') and + not isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField)) and + hasattr(field, 'choices')): + field_info['choices'] = [ + { + 'value': choice_value, + 'display_name': force_str(choice_name, strings_only=True) + } + for choice_value, choice_name in field.choices.items() + ] + + return field_info diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/mixins.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/mixins.py new file mode 100644 index 0000000000000000000000000000000000000000..7fa8947cb9ce1a06630419d7af949125f5e67088 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/mixins.py @@ -0,0 +1,95 @@ +""" +Basic building blocks for generic class based views. + +We don't bind behaviour to http method handlers yet, +which allows mixin classes to be composed in interesting ways. +""" +from rest_framework import status +from rest_framework.response import Response +from rest_framework.settings import api_settings + + +class CreateModelMixin: + """ + Create a model instance. + """ + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + def perform_create(self, serializer): + serializer.save() + + def get_success_headers(self, data): + try: + return {'Location': str(data[api_settings.URL_FIELD_NAME])} + except (TypeError, KeyError): + return {} + + +class ListModelMixin: + """ + List a queryset. + """ + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + + +class RetrieveModelMixin: + """ + Retrieve a model instance. + """ + def retrieve(self, request, *args, **kwargs): + instance = self.get_object() + serializer = self.get_serializer(instance) + return Response(serializer.data) + + +class UpdateModelMixin: + """ + Update a model instance. + """ + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + instance = self.get_object() + serializer = self.get_serializer(instance, data=request.data, partial=partial) + serializer.is_valid(raise_exception=True) + self.perform_update(serializer) + + if getattr(instance, '_prefetched_objects_cache', None): + # If 'prefetch_related' has been applied to a queryset, we need to + # forcibly invalidate the prefetch cache on the instance. + instance._prefetched_objects_cache = {} + + return Response(serializer.data) + + def perform_update(self, serializer): + serializer.save() + + def partial_update(self, request, *args, **kwargs): + kwargs['partial'] = True + return self.update(request, *args, **kwargs) + + +class DestroyModelMixin: + """ + Destroy a model instance. + """ + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + self.perform_destroy(instance) + return Response(status=status.HTTP_204_NO_CONTENT) + + def perform_destroy(self, instance): + instance.delete() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/negotiation.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/negotiation.py new file mode 100644 index 0000000000000000000000000000000000000000..b4bbfa1f546c0ecf18c5e8e84bf37789ad7e4387 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/negotiation.py @@ -0,0 +1,97 @@ +""" +Content negotiation deals with selecting an appropriate renderer given the +incoming request. Typically this will be based on the request's Accept header. +""" +from django.http import Http404 + +from rest_framework import exceptions +from rest_framework.settings import api_settings +from rest_framework.utils.mediatypes import ( + _MediaType, media_type_matches, order_by_precedence +) + + +class BaseContentNegotiation: + def select_parser(self, request, parsers): + raise NotImplementedError('.select_parser() must be implemented') + + def select_renderer(self, request, renderers, format_suffix=None): + raise NotImplementedError('.select_renderer() must be implemented') + + +class DefaultContentNegotiation(BaseContentNegotiation): + settings = api_settings + + def select_parser(self, request, parsers): + """ + Given a list of parsers and a media type, return the appropriate + parser to handle the incoming request. + """ + for parser in parsers: + if media_type_matches(parser.media_type, request.content_type): + return parser + return None + + def select_renderer(self, request, renderers, format_suffix=None): + """ + Given a request and a list of renderers, return a two-tuple of: + (renderer, media type). + """ + # Allow URL style format override. eg. "?format=json + format_query_param = self.settings.URL_FORMAT_OVERRIDE + format = format_suffix or request.query_params.get(format_query_param) + + if format: + renderers = self.filter_renderers(renderers, format) + + accepts = self.get_accept_list(request) + + # Check the acceptable media types against each renderer, + # attempting more specific media types first + # NB. The inner loop here isn't as bad as it first looks :) + # Worst case is we're looping over len(accept_list) * len(self.renderers) + for media_type_set in order_by_precedence(accepts): + for renderer in renderers: + for media_type in media_type_set: + if media_type_matches(renderer.media_type, media_type): + # Return the most specific media type as accepted. + media_type_wrapper = _MediaType(media_type) + if ( + _MediaType(renderer.media_type).precedence > + media_type_wrapper.precedence + ): + # Eg client requests '*/*' + # Accepted media type is 'application/json' + full_media_type = ';'.join( + (renderer.media_type,) + + tuple( + '{}={}'.format(key, value) + for key, value in media_type_wrapper.params.items() + ) + ) + return renderer, full_media_type + else: + # Eg client requests 'application/json; indent=8' + # Accepted media type is 'application/json; indent=8' + return renderer, media_type + + raise exceptions.NotAcceptable(available_renderers=renderers) + + def filter_renderers(self, renderers, format): + """ + If there is a '.json' style format suffix, filter the renderers + so that we only negotiation against those that accept that format. + """ + renderers = [renderer for renderer in renderers + if renderer.format == format] + if not renderers: + raise Http404 + return renderers + + def get_accept_list(self, request): + """ + Given the incoming request, return a tokenized list of media + type strings. + """ + header = request.META.get('HTTP_ACCEPT', '*/*') + return [token.strip() for token in header.split(',')] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/pagination.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/pagination.py new file mode 100644 index 0000000000000000000000000000000000000000..e815d8d5cffc6142f73e80f22d1edb6ed870c047 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/pagination.py @@ -0,0 +1,980 @@ +""" +Pagination serializers determine the structure of the output that should +be used for paginated responses. +""" +from base64 import b64decode, b64encode +from collections import OrderedDict, namedtuple +from urllib import parse + +from django.core.paginator import InvalidPage +from django.core.paginator import Paginator as DjangoPaginator +from django.template import loader +from django.utils.encoding import force_str +from django.utils.translation import gettext_lazy as _ + +from rest_framework.compat import coreapi, coreschema +from rest_framework.exceptions import NotFound +from rest_framework.response import Response +from rest_framework.settings import api_settings +from rest_framework.utils.urls import remove_query_param, replace_query_param + + +def _positive_int(integer_string, strict=False, cutoff=None): + """ + Cast a string to a strictly positive integer. + """ + ret = int(integer_string) + if ret < 0 or (ret == 0 and strict): + raise ValueError() + if cutoff: + return min(ret, cutoff) + return ret + + +def _divide_with_ceil(a, b): + """ + Returns 'a' divided by 'b', with any remainder rounded up. + """ + if a % b: + return (a // b) + 1 + + return a // b + + +def _get_displayed_page_numbers(current, final): + """ + This utility function determines a list of page numbers to display. + This gives us a nice contextually relevant set of page numbers. + + For example: + current=14, final=16 -> [1, None, 13, 14, 15, 16] + + This implementation gives one page to each side of the cursor, + or two pages to the side when the cursor is at the edge, then + ensures that any breaks between non-continuous page numbers never + remove only a single page. + + For an alternative implementation which gives two pages to each side of + the cursor, eg. as in GitHub issue list pagination, see: + + https://gist.github.com/tomchristie/321140cebb1c4a558b15 + """ + assert current >= 1 + assert final >= current + + if final <= 5: + return list(range(1, final + 1)) + + # We always include the first two pages, last two pages, and + # two pages either side of the current page. + included = {1, current - 1, current, current + 1, final} + + # If the break would only exclude a single page number then we + # may as well include the page number instead of the break. + if current <= 4: + included.add(2) + included.add(3) + if current >= final - 3: + included.add(final - 1) + included.add(final - 2) + + # Now sort the page numbers and drop anything outside the limits. + included = [ + idx for idx in sorted(included) + if 0 < idx <= final + ] + + # Finally insert any `...` breaks + if current > 4: + included.insert(1, None) + if current < final - 3: + included.insert(len(included) - 1, None) + return included + + +def _get_page_links(page_numbers, current, url_func): + """ + Given a list of page numbers and `None` page breaks, + return a list of `PageLink` objects. + """ + page_links = [] + for page_number in page_numbers: + if page_number is None: + page_link = PAGE_BREAK + else: + page_link = PageLink( + url=url_func(page_number), + number=page_number, + is_active=(page_number == current), + is_break=False + ) + page_links.append(page_link) + return page_links + + +def _reverse_ordering(ordering_tuple): + """ + Given an order_by tuple such as `('-created', 'uuid')` reverse the + ordering and return a new tuple, eg. `('created', '-uuid')`. + """ + def invert(x): + return x[1:] if x.startswith('-') else '-' + x + + return tuple([invert(item) for item in ordering_tuple]) + + +Cursor = namedtuple('Cursor', ['offset', 'reverse', 'position']) +PageLink = namedtuple('PageLink', ['url', 'number', 'is_active', 'is_break']) + +PAGE_BREAK = PageLink(url=None, number=None, is_active=False, is_break=True) + + +class BasePagination: + display_page_controls = False + + def paginate_queryset(self, queryset, request, view=None): # pragma: no cover + raise NotImplementedError('paginate_queryset() must be implemented.') + + def get_paginated_response(self, data): # pragma: no cover + raise NotImplementedError('get_paginated_response() must be implemented.') + + def get_paginated_response_schema(self, schema): + return schema + + def to_html(self): # pragma: no cover + raise NotImplementedError('to_html() must be implemented to display page controls.') + + def get_results(self, data): + return data['results'] + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + return [] + + def get_schema_operation_parameters(self, view): + return [] + + +class PageNumberPagination(BasePagination): + """ + A simple page number based style that supports page numbers as + query parameters. For example: + + http://api.example.org/accounts/?page=4 + http://api.example.org/accounts/?page=4&page_size=100 + """ + # The default page size. + # Defaults to `None`, meaning pagination is disabled. + page_size = api_settings.PAGE_SIZE + + django_paginator_class = DjangoPaginator + + # Client can control the page using this query parameter. + page_query_param = 'page' + page_query_description = _('A page number within the paginated result set.') + + # Client can control the page size using this query parameter. + # Default is 'None'. Set to eg 'page_size' to enable usage. + page_size_query_param = None + page_size_query_description = _('Number of results to return per page.') + + # Set to an integer to limit the maximum page size the client may request. + # Only relevant if 'page_size_query_param' has also been set. + max_page_size = None + + last_page_strings = ('last',) + + template = 'rest_framework/pagination/numbers.html' + + invalid_page_message = _('Invalid page.') + + def paginate_queryset(self, queryset, request, view=None): + """ + Paginate a queryset if required, either returning a + page object, or `None` if pagination is not configured for this view. + """ + page_size = self.get_page_size(request) + if not page_size: + return None + + paginator = self.django_paginator_class(queryset, page_size) + page_number = self.get_page_number(request, paginator) + + try: + self.page = paginator.page(page_number) + except InvalidPage as exc: + msg = self.invalid_page_message.format( + page_number=page_number, message=str(exc) + ) + raise NotFound(msg) + + if paginator.num_pages > 1 and self.template is not None: + # The browsable API should display pagination controls. + self.display_page_controls = True + + self.request = request + return list(self.page) + + def get_page_number(self, request, paginator): + page_number = request.query_params.get(self.page_query_param, 1) + if page_number in self.last_page_strings: + page_number = paginator.num_pages + return page_number + + def get_paginated_response(self, data): + return Response(OrderedDict([ + ('count', self.page.paginator.count), + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('results', data) + ])) + + def get_paginated_response_schema(self, schema): + return { + 'type': 'object', + 'properties': { + 'count': { + 'type': 'integer', + 'example': 123, + }, + 'next': { + 'type': 'string', + 'nullable': True, + 'format': 'uri', + 'example': 'http://api.example.org/accounts/?{page_query_param}=4'.format( + page_query_param=self.page_query_param) + }, + 'previous': { + 'type': 'string', + 'nullable': True, + 'format': 'uri', + 'example': 'http://api.example.org/accounts/?{page_query_param}=2'.format( + page_query_param=self.page_query_param) + }, + 'results': schema, + }, + } + + def get_page_size(self, request): + if self.page_size_query_param: + try: + return _positive_int( + request.query_params[self.page_size_query_param], + strict=True, + cutoff=self.max_page_size + ) + except (KeyError, ValueError): + pass + + return self.page_size + + def get_next_link(self): + if not self.page.has_next(): + return None + url = self.request.build_absolute_uri() + page_number = self.page.next_page_number() + return replace_query_param(url, self.page_query_param, page_number) + + def get_previous_link(self): + if not self.page.has_previous(): + return None + url = self.request.build_absolute_uri() + page_number = self.page.previous_page_number() + if page_number == 1: + return remove_query_param(url, self.page_query_param) + return replace_query_param(url, self.page_query_param, page_number) + + def get_html_context(self): + base_url = self.request.build_absolute_uri() + + def page_number_to_url(page_number): + if page_number == 1: + return remove_query_param(base_url, self.page_query_param) + else: + return replace_query_param(base_url, self.page_query_param, page_number) + + current = self.page.number + final = self.page.paginator.num_pages + page_numbers = _get_displayed_page_numbers(current, final) + page_links = _get_page_links(page_numbers, current, page_number_to_url) + + return { + 'previous_url': self.get_previous_link(), + 'next_url': self.get_next_link(), + 'page_links': page_links + } + + def to_html(self): + template = loader.get_template(self.template) + context = self.get_html_context() + return template.render(context) + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + fields = [ + coreapi.Field( + name=self.page_query_param, + required=False, + location='query', + schema=coreschema.Integer( + title='Page', + description=force_str(self.page_query_description) + ) + ) + ] + if self.page_size_query_param is not None: + fields.append( + coreapi.Field( + name=self.page_size_query_param, + required=False, + location='query', + schema=coreschema.Integer( + title='Page size', + description=force_str(self.page_size_query_description) + ) + ) + ) + return fields + + def get_schema_operation_parameters(self, view): + parameters = [ + { + 'name': self.page_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.page_query_description), + 'schema': { + 'type': 'integer', + }, + }, + ] + if self.page_size_query_param is not None: + parameters.append( + { + 'name': self.page_size_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.page_size_query_description), + 'schema': { + 'type': 'integer', + }, + }, + ) + return parameters + + +class LimitOffsetPagination(BasePagination): + """ + A limit/offset based style. For example: + + http://api.example.org/accounts/?limit=100 + http://api.example.org/accounts/?offset=400&limit=100 + """ + default_limit = api_settings.PAGE_SIZE + limit_query_param = 'limit' + limit_query_description = _('Number of results to return per page.') + offset_query_param = 'offset' + offset_query_description = _('The initial index from which to return the results.') + max_limit = None + template = 'rest_framework/pagination/numbers.html' + + def paginate_queryset(self, queryset, request, view=None): + self.limit = self.get_limit(request) + if self.limit is None: + return None + + self.count = self.get_count(queryset) + self.offset = self.get_offset(request) + self.request = request + if self.count > self.limit and self.template is not None: + self.display_page_controls = True + + if self.count == 0 or self.offset > self.count: + return [] + return list(queryset[self.offset:self.offset + self.limit]) + + def get_paginated_response(self, data): + return Response(OrderedDict([ + ('count', self.count), + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('results', data) + ])) + + def get_paginated_response_schema(self, schema): + return { + 'type': 'object', + 'properties': { + 'count': { + 'type': 'integer', + 'example': 123, + }, + 'next': { + 'type': 'string', + 'nullable': True, + 'format': 'uri', + 'example': 'http://api.example.org/accounts/?{offset_param}=400&{limit_param}=100'.format( + offset_param=self.offset_query_param, limit_param=self.limit_query_param), + }, + 'previous': { + 'type': 'string', + 'nullable': True, + 'format': 'uri', + 'example': 'http://api.example.org/accounts/?{offset_param}=200&{limit_param}=100'.format( + offset_param=self.offset_query_param, limit_param=self.limit_query_param), + }, + 'results': schema, + }, + } + + def get_limit(self, request): + if self.limit_query_param: + try: + return _positive_int( + request.query_params[self.limit_query_param], + strict=True, + cutoff=self.max_limit + ) + except (KeyError, ValueError): + pass + + return self.default_limit + + def get_offset(self, request): + try: + return _positive_int( + request.query_params[self.offset_query_param], + ) + except (KeyError, ValueError): + return 0 + + def get_next_link(self): + if self.offset + self.limit >= self.count: + return None + + url = self.request.build_absolute_uri() + url = replace_query_param(url, self.limit_query_param, self.limit) + + offset = self.offset + self.limit + return replace_query_param(url, self.offset_query_param, offset) + + def get_previous_link(self): + if self.offset <= 0: + return None + + url = self.request.build_absolute_uri() + url = replace_query_param(url, self.limit_query_param, self.limit) + + if self.offset - self.limit <= 0: + return remove_query_param(url, self.offset_query_param) + + offset = self.offset - self.limit + return replace_query_param(url, self.offset_query_param, offset) + + def get_html_context(self): + base_url = self.request.build_absolute_uri() + + if self.limit: + current = _divide_with_ceil(self.offset, self.limit) + 1 + + # The number of pages is a little bit fiddly. + # We need to sum both the number of pages from current offset to end + # plus the number of pages up to the current offset. + # When offset is not strictly divisible by the limit then we may + # end up introducing an extra page as an artifact. + final = ( + _divide_with_ceil(self.count - self.offset, self.limit) + + _divide_with_ceil(self.offset, self.limit) + ) + + final = max(final, 1) + else: + current = 1 + final = 1 + + if current > final: + current = final + + def page_number_to_url(page_number): + if page_number == 1: + return remove_query_param(base_url, self.offset_query_param) + else: + offset = self.offset + ((page_number - current) * self.limit) + return replace_query_param(base_url, self.offset_query_param, offset) + + page_numbers = _get_displayed_page_numbers(current, final) + page_links = _get_page_links(page_numbers, current, page_number_to_url) + + return { + 'previous_url': self.get_previous_link(), + 'next_url': self.get_next_link(), + 'page_links': page_links + } + + def to_html(self): + template = loader.get_template(self.template) + context = self.get_html_context() + return template.render(context) + + def get_count(self, queryset): + """ + Determine an object count, supporting either querysets or regular lists. + """ + try: + return queryset.count() + except (AttributeError, TypeError): + return len(queryset) + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + return [ + coreapi.Field( + name=self.limit_query_param, + required=False, + location='query', + schema=coreschema.Integer( + title='Limit', + description=force_str(self.limit_query_description) + ) + ), + coreapi.Field( + name=self.offset_query_param, + required=False, + location='query', + schema=coreschema.Integer( + title='Offset', + description=force_str(self.offset_query_description) + ) + ) + ] + + def get_schema_operation_parameters(self, view): + parameters = [ + { + 'name': self.limit_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.limit_query_description), + 'schema': { + 'type': 'integer', + }, + }, + { + 'name': self.offset_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.offset_query_description), + 'schema': { + 'type': 'integer', + }, + }, + ] + return parameters + + +class CursorPagination(BasePagination): + """ + The cursor pagination implementation is necessarily complex. + For an overview of the position/offset style we use, see this post: + https://cra.mr/2011/03/08/building-cursors-for-the-disqus-api + """ + cursor_query_param = 'cursor' + cursor_query_description = _('The pagination cursor value.') + page_size = api_settings.PAGE_SIZE + invalid_cursor_message = _('Invalid cursor') + ordering = '-created' + template = 'rest_framework/pagination/previous_and_next.html' + + # Client can control the page size using this query parameter. + # Default is 'None'. Set to eg 'page_size' to enable usage. + page_size_query_param = None + page_size_query_description = _('Number of results to return per page.') + + # Set to an integer to limit the maximum page size the client may request. + # Only relevant if 'page_size_query_param' has also been set. + max_page_size = None + + # The offset in the cursor is used in situations where we have a + # nearly-unique index. (Eg millisecond precision creation timestamps) + # We guard against malicious users attempting to cause expensive database + # queries, by having a hard cap on the maximum possible size of the offset. + offset_cutoff = 1000 + + def paginate_queryset(self, queryset, request, view=None): + self.page_size = self.get_page_size(request) + if not self.page_size: + return None + + self.base_url = request.build_absolute_uri() + self.ordering = self.get_ordering(request, queryset, view) + + self.cursor = self.decode_cursor(request) + if self.cursor is None: + (offset, reverse, current_position) = (0, False, None) + else: + (offset, reverse, current_position) = self.cursor + + # Cursor pagination always enforces an ordering. + if reverse: + queryset = queryset.order_by(*_reverse_ordering(self.ordering)) + else: + queryset = queryset.order_by(*self.ordering) + + # If we have a cursor with a fixed position then filter by that. + if current_position is not None: + order = self.ordering[0] + is_reversed = order.startswith('-') + order_attr = order.lstrip('-') + + # Test for: (cursor reversed) XOR (queryset reversed) + if self.cursor.reverse != is_reversed: + kwargs = {order_attr + '__lt': current_position} + else: + kwargs = {order_attr + '__gt': current_position} + + queryset = queryset.filter(**kwargs) + + # If we have an offset cursor then offset the entire page by that amount. + # We also always fetch an extra item in order to determine if there is a + # page following on from this one. + results = list(queryset[offset:offset + self.page_size + 1]) + self.page = list(results[:self.page_size]) + + # Determine the position of the final item following the page. + if len(results) > len(self.page): + has_following_position = True + following_position = self._get_position_from_instance(results[-1], self.ordering) + else: + has_following_position = False + following_position = None + + if reverse: + # If we have a reverse queryset, then the query ordering was in reverse + # so we need to reverse the items again before returning them to the user. + self.page = list(reversed(self.page)) + + # Determine next and previous positions for reverse cursors. + self.has_next = (current_position is not None) or (offset > 0) + self.has_previous = has_following_position + if self.has_next: + self.next_position = current_position + if self.has_previous: + self.previous_position = following_position + else: + # Determine next and previous positions for forward cursors. + self.has_next = has_following_position + self.has_previous = (current_position is not None) or (offset > 0) + if self.has_next: + self.next_position = following_position + if self.has_previous: + self.previous_position = current_position + + # Display page controls in the browsable API if there is more + # than one page. + if (self.has_previous or self.has_next) and self.template is not None: + self.display_page_controls = True + + return self.page + + def get_page_size(self, request): + if self.page_size_query_param: + try: + return _positive_int( + request.query_params[self.page_size_query_param], + strict=True, + cutoff=self.max_page_size + ) + except (KeyError, ValueError): + pass + + return self.page_size + + def get_next_link(self): + if not self.has_next: + return None + + if self.page and self.cursor and self.cursor.reverse and self.cursor.offset != 0: + # If we're reversing direction and we have an offset cursor + # then we cannot use the first position we find as a marker. + compare = self._get_position_from_instance(self.page[-1], self.ordering) + else: + compare = self.next_position + offset = 0 + + has_item_with_unique_position = False + for item in reversed(self.page): + position = self._get_position_from_instance(item, self.ordering) + if position != compare: + # The item in this position and the item following it + # have different positions. We can use this position as + # our marker. + has_item_with_unique_position = True + break + + # The item in this position has the same position as the item + # following it, we can't use it as a marker position, so increment + # the offset and keep seeking to the previous item. + compare = position + offset += 1 + + if self.page and not has_item_with_unique_position: + # There were no unique positions in the page. + if not self.has_previous: + # We are on the first page. + # Our cursor will have an offset equal to the page size, + # but no position to filter against yet. + offset = self.page_size + position = None + elif self.cursor.reverse: + # The change in direction will introduce a paging artifact, + # where we end up skipping forward a few extra items. + offset = 0 + position = self.previous_position + else: + # Use the position from the existing cursor and increment + # it's offset by the page size. + offset = self.cursor.offset + self.page_size + position = self.previous_position + + if not self.page: + position = self.next_position + + cursor = Cursor(offset=offset, reverse=False, position=position) + return self.encode_cursor(cursor) + + def get_previous_link(self): + if not self.has_previous: + return None + + if self.page and self.cursor and not self.cursor.reverse and self.cursor.offset != 0: + # If we're reversing direction and we have an offset cursor + # then we cannot use the first position we find as a marker. + compare = self._get_position_from_instance(self.page[0], self.ordering) + else: + compare = self.previous_position + offset = 0 + + has_item_with_unique_position = False + for item in self.page: + position = self._get_position_from_instance(item, self.ordering) + if position != compare: + # The item in this position and the item following it + # have different positions. We can use this position as + # our marker. + has_item_with_unique_position = True + break + + # The item in this position has the same position as the item + # following it, we can't use it as a marker position, so increment + # the offset and keep seeking to the previous item. + compare = position + offset += 1 + + if self.page and not has_item_with_unique_position: + # There were no unique positions in the page. + if not self.has_next: + # We are on the final page. + # Our cursor will have an offset equal to the page size, + # but no position to filter against yet. + offset = self.page_size + position = None + elif self.cursor.reverse: + # Use the position from the existing cursor and increment + # it's offset by the page size. + offset = self.cursor.offset + self.page_size + position = self.next_position + else: + # The change in direction will introduce a paging artifact, + # where we end up skipping back a few extra items. + offset = 0 + position = self.next_position + + if not self.page: + position = self.previous_position + + cursor = Cursor(offset=offset, reverse=True, position=position) + return self.encode_cursor(cursor) + + def get_ordering(self, request, queryset, view): + """ + Return a tuple of strings, that may be used in an `order_by` method. + """ + ordering_filters = [ + filter_cls for filter_cls in getattr(view, 'filter_backends', []) + if hasattr(filter_cls, 'get_ordering') + ] + + if ordering_filters: + # If a filter exists on the view that implements `get_ordering` + # then we defer to that filter to determine the ordering. + filter_cls = ordering_filters[0] + filter_instance = filter_cls() + ordering = filter_instance.get_ordering(request, queryset, view) + assert ordering is not None, ( + 'Using cursor pagination, but filter class {filter_cls} ' + 'returned a `None` ordering.'.format( + filter_cls=filter_cls.__name__ + ) + ) + else: + # The default case is to check for an `ordering` attribute + # on this pagination instance. + ordering = self.ordering + assert ordering is not None, ( + 'Using cursor pagination, but no ordering attribute was declared ' + 'on the pagination class.' + ) + assert '__' not in ordering, ( + 'Cursor pagination does not support double underscore lookups ' + 'for orderings. Orderings should be an unchanging, unique or ' + 'nearly-unique field on the model, such as "-created" or "pk".' + ) + + assert isinstance(ordering, (str, list, tuple)), ( + 'Invalid ordering. Expected string or tuple, but got {type}'.format( + type=type(ordering).__name__ + ) + ) + + if isinstance(ordering, str): + return (ordering,) + return tuple(ordering) + + def decode_cursor(self, request): + """ + Given a request with a cursor, return a `Cursor` instance. + """ + # Determine if we have a cursor, and if so then decode it. + encoded = request.query_params.get(self.cursor_query_param) + if encoded is None: + return None + + try: + querystring = b64decode(encoded.encode('ascii')).decode('ascii') + tokens = parse.parse_qs(querystring, keep_blank_values=True) + + offset = tokens.get('o', ['0'])[0] + offset = _positive_int(offset, cutoff=self.offset_cutoff) + + reverse = tokens.get('r', ['0'])[0] + reverse = bool(int(reverse)) + + position = tokens.get('p', [None])[0] + except (TypeError, ValueError): + raise NotFound(self.invalid_cursor_message) + + return Cursor(offset=offset, reverse=reverse, position=position) + + def encode_cursor(self, cursor): + """ + Given a Cursor instance, return an url with encoded cursor. + """ + tokens = {} + if cursor.offset != 0: + tokens['o'] = str(cursor.offset) + if cursor.reverse: + tokens['r'] = '1' + if cursor.position is not None: + tokens['p'] = cursor.position + + querystring = parse.urlencode(tokens, doseq=True) + encoded = b64encode(querystring.encode('ascii')).decode('ascii') + return replace_query_param(self.base_url, self.cursor_query_param, encoded) + + def _get_position_from_instance(self, instance, ordering): + field_name = ordering[0].lstrip('-') + if isinstance(instance, dict): + attr = instance[field_name] + else: + attr = getattr(instance, field_name) + return str(attr) + + def get_paginated_response(self, data): + return Response(OrderedDict([ + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('results', data) + ])) + + def get_paginated_response_schema(self, schema): + return { + 'type': 'object', + 'properties': { + 'next': { + 'type': 'string', + 'nullable': True, + }, + 'previous': { + 'type': 'string', + 'nullable': True, + }, + 'results': schema, + }, + } + + def get_html_context(self): + return { + 'previous_url': self.get_previous_link(), + 'next_url': self.get_next_link() + } + + def to_html(self): + template = loader.get_template(self.template) + context = self.get_html_context() + return template.render(context) + + def get_schema_fields(self, view): + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`' + fields = [ + coreapi.Field( + name=self.cursor_query_param, + required=False, + location='query', + schema=coreschema.String( + title='Cursor', + description=force_str(self.cursor_query_description) + ) + ) + ] + if self.page_size_query_param is not None: + fields.append( + coreapi.Field( + name=self.page_size_query_param, + required=False, + location='query', + schema=coreschema.Integer( + title='Page size', + description=force_str(self.page_size_query_description) + ) + ) + ) + return fields + + def get_schema_operation_parameters(self, view): + parameters = [ + { + 'name': self.cursor_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.cursor_query_description), + 'schema': { + 'type': 'string', + }, + } + ] + if self.page_size_query_param is not None: + parameters.append( + { + 'name': self.page_size_query_param, + 'required': False, + 'in': 'query', + 'description': force_str(self.page_size_query_description), + 'schema': { + 'type': 'integer', + }, + } + ) + return parameters diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/parsers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/parsers.py new file mode 100644 index 0000000000000000000000000000000000000000..4ee8e578b8827a45a7ebad802bad6fb83394bab1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/parsers.py @@ -0,0 +1,209 @@ +""" +Parsers are used to parse the content of incoming HTTP requests. + +They give us a generic way of being able to handle various media types +on the request, such as form content or json encoded data. +""" +import codecs + +from django.conf import settings +from django.core.files.uploadhandler import StopFutureHandlers +from django.http import QueryDict +from django.http.multipartparser import ChunkIter +from django.http.multipartparser import \ + MultiPartParser as DjangoMultiPartParser +from django.http.multipartparser import MultiPartParserError + +from rest_framework import renderers +from rest_framework.compat import parse_header_parameters +from rest_framework.exceptions import ParseError +from rest_framework.settings import api_settings +from rest_framework.utils import json + + +class DataAndFiles: + def __init__(self, data, files): + self.data = data + self.files = files + + +class BaseParser: + """ + All parsers should extend `BaseParser`, specifying a `media_type` + attribute, and overriding the `.parse()` method. + """ + media_type = None + + def parse(self, stream, media_type=None, parser_context=None): + """ + Given a stream to read from, return the parsed representation. + Should return parsed data, or a `DataAndFiles` object consisting of the + parsed data and files. + """ + raise NotImplementedError(".parse() must be overridden.") + + +class JSONParser(BaseParser): + """ + Parses JSON-serialized data. + """ + media_type = 'application/json' + renderer_class = renderers.JSONRenderer + strict = api_settings.STRICT_JSON + + def parse(self, stream, media_type=None, parser_context=None): + """ + Parses the incoming bytestream as JSON and returns the resulting data. + """ + parser_context = parser_context or {} + encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) + + try: + decoded_stream = codecs.getreader(encoding)(stream) + parse_constant = json.strict_constant if self.strict else None + return json.load(decoded_stream, parse_constant=parse_constant) + except ValueError as exc: + raise ParseError('JSON parse error - %s' % str(exc)) + + +class FormParser(BaseParser): + """ + Parser for form data. + """ + media_type = 'application/x-www-form-urlencoded' + + def parse(self, stream, media_type=None, parser_context=None): + """ + Parses the incoming bytestream as a URL encoded form, + and returns the resulting QueryDict. + """ + parser_context = parser_context or {} + encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) + return QueryDict(stream.read(), encoding=encoding) + + +class MultiPartParser(BaseParser): + """ + Parser for multipart form data, which may include file data. + """ + media_type = 'multipart/form-data' + + def parse(self, stream, media_type=None, parser_context=None): + """ + Parses the incoming bytestream as a multipart encoded form, + and returns a DataAndFiles object. + + `.data` will be a `QueryDict` containing all the form parameters. + `.files` will be a `QueryDict` containing all the form files. + """ + parser_context = parser_context or {} + request = parser_context['request'] + encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) + meta = request.META.copy() + meta['CONTENT_TYPE'] = media_type + upload_handlers = request.upload_handlers + + try: + parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding) + data, files = parser.parse() + return DataAndFiles(data, files) + except MultiPartParserError as exc: + raise ParseError('Multipart form parse error - %s' % str(exc)) + + +class FileUploadParser(BaseParser): + """ + Parser for file upload data. + """ + media_type = '*/*' + errors = { + 'unhandled': 'FileUpload parse error - none of upload handlers can handle the stream', + 'no_filename': 'Missing filename. Request should include a Content-Disposition header with a filename parameter.', + } + + def parse(self, stream, media_type=None, parser_context=None): + """ + Treats the incoming bytestream as a raw file upload and returns + a `DataAndFiles` object. + + `.data` will be None (we expect request body to be a file content). + `.files` will be a `QueryDict` containing one 'file' element. + """ + parser_context = parser_context or {} + request = parser_context['request'] + encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) + meta = request.META + upload_handlers = request.upload_handlers + filename = self.get_filename(stream, media_type, parser_context) + + if not filename: + raise ParseError(self.errors['no_filename']) + + # Note that this code is extracted from Django's handling of + # file uploads in MultiPartParser. + content_type = meta.get('HTTP_CONTENT_TYPE', + meta.get('CONTENT_TYPE', '')) + try: + content_length = int(meta.get('HTTP_CONTENT_LENGTH', + meta.get('CONTENT_LENGTH', 0))) + except (ValueError, TypeError): + content_length = None + + # See if the handler will want to take care of the parsing. + for handler in upload_handlers: + result = handler.handle_raw_input(stream, + meta, + content_length, + None, + encoding) + if result is not None: + return DataAndFiles({}, {'file': result[1]}) + + # This is the standard case. + possible_sizes = [x.chunk_size for x in upload_handlers if x.chunk_size] + chunk_size = min([2 ** 31 - 4] + possible_sizes) + chunks = ChunkIter(stream, chunk_size) + counters = [0] * len(upload_handlers) + + for index, handler in enumerate(upload_handlers): + try: + handler.new_file(None, filename, content_type, + content_length, encoding) + except StopFutureHandlers: + upload_handlers = upload_handlers[:index + 1] + break + + for chunk in chunks: + for index, handler in enumerate(upload_handlers): + chunk_length = len(chunk) + chunk = handler.receive_data_chunk(chunk, counters[index]) + counters[index] += chunk_length + if chunk is None: + break + + for index, handler in enumerate(upload_handlers): + file_obj = handler.file_complete(counters[index]) + if file_obj is not None: + return DataAndFiles({}, {'file': file_obj}) + + raise ParseError(self.errors['unhandled']) + + def get_filename(self, stream, media_type, parser_context): + """ + Detects the uploaded file name. First searches a 'filename' url kwarg. + Then tries to parse Content-Disposition header. + """ + try: + return parser_context['kwargs']['filename'] + except KeyError: + pass + + try: + meta = parser_context['request'].META + disposition, params = parse_header_parameters(meta['HTTP_CONTENT_DISPOSITION']) + if 'filename*' in params: + return params['filename*'] + else: + return params['filename'] + except (AttributeError, KeyError, ValueError): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/permissions.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..16459b251f42f74576bde15706430c78b84450c8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/permissions.py @@ -0,0 +1,303 @@ +""" +Provides a set of pluggable permission policies. +""" +from django.http import Http404 + +from rest_framework import exceptions + +SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS') + + +class OperationHolderMixin: + def __and__(self, other): + return OperandHolder(AND, self, other) + + def __or__(self, other): + return OperandHolder(OR, self, other) + + def __rand__(self, other): + return OperandHolder(AND, other, self) + + def __ror__(self, other): + return OperandHolder(OR, other, self) + + def __invert__(self): + return SingleOperandHolder(NOT, self) + + +class SingleOperandHolder(OperationHolderMixin): + def __init__(self, operator_class, op1_class): + self.operator_class = operator_class + self.op1_class = op1_class + + def __call__(self, *args, **kwargs): + op1 = self.op1_class(*args, **kwargs) + return self.operator_class(op1) + + +class OperandHolder(OperationHolderMixin): + def __init__(self, operator_class, op1_class, op2_class): + self.operator_class = operator_class + self.op1_class = op1_class + self.op2_class = op2_class + + def __call__(self, *args, **kwargs): + op1 = self.op1_class(*args, **kwargs) + op2 = self.op2_class(*args, **kwargs) + return self.operator_class(op1, op2) + + +class AND: + def __init__(self, op1, op2): + self.op1 = op1 + self.op2 = op2 + + def has_permission(self, request, view): + return ( + self.op1.has_permission(request, view) and + self.op2.has_permission(request, view) + ) + + def has_object_permission(self, request, view, obj): + return ( + self.op1.has_object_permission(request, view, obj) and + self.op2.has_object_permission(request, view, obj) + ) + + +class OR: + def __init__(self, op1, op2): + self.op1 = op1 + self.op2 = op2 + + def has_permission(self, request, view): + return ( + self.op1.has_permission(request, view) or + self.op2.has_permission(request, view) + ) + + def has_object_permission(self, request, view, obj): + return ( + self.op1.has_permission(request, view) + and self.op1.has_object_permission(request, view, obj) + ) or ( + self.op2.has_permission(request, view) + and self.op2.has_object_permission(request, view, obj) + ) + + +class NOT: + def __init__(self, op1): + self.op1 = op1 + + def has_permission(self, request, view): + return not self.op1.has_permission(request, view) + + def has_object_permission(self, request, view, obj): + return not self.op1.has_object_permission(request, view, obj) + + +class BasePermissionMetaclass(OperationHolderMixin, type): + pass + + +class BasePermission(metaclass=BasePermissionMetaclass): + """ + A base class from which all permission classes should inherit. + """ + + def has_permission(self, request, view): + """ + Return `True` if permission is granted, `False` otherwise. + """ + return True + + def has_object_permission(self, request, view, obj): + """ + Return `True` if permission is granted, `False` otherwise. + """ + return True + + +class AllowAny(BasePermission): + """ + Allow any access. + This isn't strictly required, since you could use an empty + permission_classes list, but it's useful because it makes the intention + more explicit. + """ + + def has_permission(self, request, view): + return True + + +class IsAuthenticated(BasePermission): + """ + Allows access only to authenticated users. + """ + + def has_permission(self, request, view): + return bool(request.user and request.user.is_authenticated) + + +class IsAdminUser(BasePermission): + """ + Allows access only to admin users. + """ + + def has_permission(self, request, view): + return bool(request.user and request.user.is_staff) + + +class IsAuthenticatedOrReadOnly(BasePermission): + """ + The request is authenticated as a user, or is a read-only request. + """ + + def has_permission(self, request, view): + return bool( + request.method in SAFE_METHODS or + request.user and + request.user.is_authenticated + ) + + +class DjangoModelPermissions(BasePermission): + """ + The request is authenticated using `django.contrib.auth` permissions. + See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions + + It ensures that the user is authenticated, and has the appropriate + `add`/`change`/`delete` permissions on the model. + + This permission can only be applied against view classes that + provide a `.queryset` attribute. + """ + + # Map methods into required permission codes. + # Override this if you need to also provide 'view' permissions, + # or if you want to provide custom permission codes. + perms_map = { + 'GET': [], + 'OPTIONS': [], + 'HEAD': [], + 'POST': ['%(app_label)s.add_%(model_name)s'], + 'PUT': ['%(app_label)s.change_%(model_name)s'], + 'PATCH': ['%(app_label)s.change_%(model_name)s'], + 'DELETE': ['%(app_label)s.delete_%(model_name)s'], + } + + authenticated_users_only = True + + def get_required_permissions(self, method, model_cls): + """ + Given a model and an HTTP method, return the list of permission + codes that the user is required to have. + """ + kwargs = { + 'app_label': model_cls._meta.app_label, + 'model_name': model_cls._meta.model_name + } + + if method not in self.perms_map: + raise exceptions.MethodNotAllowed(method) + + return [perm % kwargs for perm in self.perms_map[method]] + + def _queryset(self, view): + assert hasattr(view, 'get_queryset') \ + or getattr(view, 'queryset', None) is not None, ( + 'Cannot apply {} on a view that does not set ' + '`.queryset` or have a `.get_queryset()` method.' + ).format(self.__class__.__name__) + + if hasattr(view, 'get_queryset'): + queryset = view.get_queryset() + assert queryset is not None, ( + '{}.get_queryset() returned None'.format(view.__class__.__name__) + ) + return queryset + return view.queryset + + def has_permission(self, request, view): + # Workaround to ensure DjangoModelPermissions are not applied + # to the root view when using DefaultRouter. + if getattr(view, '_ignore_model_permissions', False): + return True + + if not request.user or ( + not request.user.is_authenticated and self.authenticated_users_only): + return False + + queryset = self._queryset(view) + perms = self.get_required_permissions(request.method, queryset.model) + + return request.user.has_perms(perms) + + +class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions): + """ + Similar to DjangoModelPermissions, except that anonymous users are + allowed read-only access. + """ + authenticated_users_only = False + + +class DjangoObjectPermissions(DjangoModelPermissions): + """ + The request is authenticated using Django's object-level permissions. + It requires an object-permissions-enabled backend, such as Django Guardian. + + It ensures that the user is authenticated, and has the appropriate + `add`/`change`/`delete` permissions on the object using .has_perms. + + This permission can only be applied against view classes that + provide a `.queryset` attribute. + """ + perms_map = { + 'GET': [], + 'OPTIONS': [], + 'HEAD': [], + 'POST': ['%(app_label)s.add_%(model_name)s'], + 'PUT': ['%(app_label)s.change_%(model_name)s'], + 'PATCH': ['%(app_label)s.change_%(model_name)s'], + 'DELETE': ['%(app_label)s.delete_%(model_name)s'], + } + + def get_required_object_permissions(self, method, model_cls): + kwargs = { + 'app_label': model_cls._meta.app_label, + 'model_name': model_cls._meta.model_name + } + + if method not in self.perms_map: + raise exceptions.MethodNotAllowed(method) + + return [perm % kwargs for perm in self.perms_map[method]] + + def has_object_permission(self, request, view, obj): + # authentication checks have already executed via has_permission + queryset = self._queryset(view) + model_cls = queryset.model + user = request.user + + perms = self.get_required_object_permissions(request.method, model_cls) + + if not user.has_perms(perms, obj): + # If the user does not have permissions we need to determine if + # they have read permissions to see 403, or not, and simply see + # a 404 response. + + if request.method in SAFE_METHODS: + # Read permissions already checked and failed, no need + # to make another lookup. + raise Http404 + + read_perms = self.get_required_object_permissions('GET', model_cls) + if not user.has_perms(read_perms, obj): + raise Http404 + + # Has read permissions. + return False + + return True diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/relations.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/relations.py new file mode 100644 index 0000000000000000000000000000000000000000..bdedd43b86e94f83120446dcb8255f97f665d50d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/relations.py @@ -0,0 +1,586 @@ +import sys +from collections import OrderedDict +from urllib import parse + +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.db.models import Manager +from django.db.models.query import QuerySet +from django.urls import NoReverseMatch, Resolver404, get_script_prefix, resolve +from django.utils.encoding import smart_str, uri_to_iri +from django.utils.translation import gettext_lazy as _ + +from rest_framework.fields import ( + Field, SkipField, empty, get_attribute, is_simple_callable, iter_options +) +from rest_framework.reverse import reverse +from rest_framework.settings import api_settings +from rest_framework.utils import html + + +def method_overridden(method_name, klass, instance): + """ + Determine if a method has been overridden. + """ + method = getattr(klass, method_name) + default_method = getattr(method, '__func__', method) # Python 3 compat + return default_method is not getattr(instance, method_name).__func__ + + +class ObjectValueError(ValueError): + """ + Raised when `queryset.get()` failed due to an underlying `ValueError`. + Wrapping prevents calling code conflating this with unrelated errors. + """ + + +class ObjectTypeError(TypeError): + """ + Raised when `queryset.get()` failed due to an underlying `TypeError`. + Wrapping prevents calling code conflating this with unrelated errors. + """ + + +class Hyperlink(str): + """ + A string like object that additionally has an associated name. + We use this for hyperlinked URLs that may render as a named link + in some contexts, or render as a plain URL in others. + """ + def __new__(cls, url, obj): + ret = super().__new__(cls, url) + ret.obj = obj + return ret + + def __getnewargs__(self): + return (str(self), self.name) + + @property + def name(self): + # This ensures that we only called `__str__` lazily, + # as in some cases calling __str__ on a model instances *might* + # involve a database lookup. + return str(self.obj) + + is_hyperlink = True + + +class PKOnlyObject: + """ + This is a mock object, used for when we only need the pk of the object + instance, but still want to return an object with a .pk attribute, + in order to keep the same interface as a regular model instance. + """ + def __init__(self, pk): + self.pk = pk + + def __str__(self): + return "%s" % self.pk + + +# We assume that 'validators' are intended for the child serializer, +# rather than the parent serializer. +MANY_RELATION_KWARGS = ( + 'read_only', 'write_only', 'required', 'default', 'initial', 'source', + 'label', 'help_text', 'style', 'error_messages', 'allow_empty', + 'html_cutoff', 'html_cutoff_text' +) + + +class RelatedField(Field): + queryset = None + html_cutoff = None + html_cutoff_text = None + + def __init__(self, **kwargs): + self.queryset = kwargs.pop('queryset', self.queryset) + + cutoff_from_settings = api_settings.HTML_SELECT_CUTOFF + if cutoff_from_settings is not None: + cutoff_from_settings = int(cutoff_from_settings) + self.html_cutoff = kwargs.pop('html_cutoff', cutoff_from_settings) + + self.html_cutoff_text = kwargs.pop( + 'html_cutoff_text', + self.html_cutoff_text or _(api_settings.HTML_SELECT_CUTOFF_TEXT) + ) + if not method_overridden('get_queryset', RelatedField, self): + assert self.queryset is not None or kwargs.get('read_only'), ( + 'Relational field must provide a `queryset` argument, ' + 'override `get_queryset`, or set read_only=`True`.' + ) + assert not (self.queryset is not None and kwargs.get('read_only')), ( + 'Relational fields should not provide a `queryset` argument, ' + 'when setting read_only=`True`.' + ) + kwargs.pop('many', None) + kwargs.pop('allow_empty', None) + super().__init__(**kwargs) + + def __new__(cls, *args, **kwargs): + # We override this method in order to automagically create + # `ManyRelatedField` classes instead when `many=True` is set. + if kwargs.pop('many', False): + return cls.many_init(*args, **kwargs) + return super().__new__(cls, *args, **kwargs) + + @classmethod + def many_init(cls, *args, **kwargs): + """ + This method handles creating a parent `ManyRelatedField` instance + when the `many=True` keyword argument is passed. + + Typically you won't need to override this method. + + Note that we're over-cautious in passing most arguments to both parent + and child classes in order to try to cover the general case. If you're + overriding this method you'll probably want something much simpler, eg: + + @classmethod + def many_init(cls, *args, **kwargs): + kwargs['child'] = cls() + return CustomManyRelatedField(*args, **kwargs) + """ + list_kwargs = {'child_relation': cls(*args, **kwargs)} + for key in kwargs: + if key in MANY_RELATION_KWARGS: + list_kwargs[key] = kwargs[key] + return ManyRelatedField(**list_kwargs) + + def run_validation(self, data=empty): + # We force empty strings to None values for relational fields. + if data == '': + data = None + return super().run_validation(data) + + def get_queryset(self): + queryset = self.queryset + if isinstance(queryset, (QuerySet, Manager)): + # Ensure queryset is re-evaluated whenever used. + # Note that actually a `Manager` class may also be used as the + # queryset argument. This occurs on ModelSerializer fields, + # as it allows us to generate a more expressive 'repr' output + # for the field. + # Eg: 'MyRelationship(queryset=ExampleModel.objects.all())' + queryset = queryset.all() + return queryset + + def use_pk_only_optimization(self): + return False + + def get_attribute(self, instance): + if self.use_pk_only_optimization() and self.source_attrs: + # Optimized case, return a mock object only containing the pk attribute. + try: + attribute_instance = get_attribute(instance, self.source_attrs[:-1]) + value = attribute_instance.serializable_value(self.source_attrs[-1]) + if is_simple_callable(value): + # Handle edge case where the relationship `source` argument + # points to a `get_relationship()` method on the model. + value = value() + + # Handle edge case where relationship `source` argument points + # to an instance instead of a pk (e.g., a `@property`). + value = getattr(value, 'pk', value) + + return PKOnlyObject(pk=value) + except AttributeError: + pass + + # Standard case, return the object instance. + return super().get_attribute(instance) + + def get_choices(self, cutoff=None): + queryset = self.get_queryset() + if queryset is None: + # Ensure that field.choices returns something sensible + # even when accessed with a read-only field. + return {} + + if cutoff is not None: + queryset = queryset[:cutoff] + + return OrderedDict([ + ( + self.to_representation(item), + self.display_value(item) + ) + for item in queryset + ]) + + @property + def choices(self): + return self.get_choices() + + @property + def grouped_choices(self): + return self.choices + + def iter_options(self): + return iter_options( + self.get_choices(cutoff=self.html_cutoff), + cutoff=self.html_cutoff, + cutoff_text=self.html_cutoff_text + ) + + def display_value(self, instance): + return str(instance) + + +class StringRelatedField(RelatedField): + """ + A read only field that represents its targets using their + plain string representation. + """ + + def __init__(self, **kwargs): + kwargs['read_only'] = True + super().__init__(**kwargs) + + def to_representation(self, value): + return str(value) + + +class PrimaryKeyRelatedField(RelatedField): + default_error_messages = { + 'required': _('This field is required.'), + 'does_not_exist': _('Invalid pk "{pk_value}" - object does not exist.'), + 'incorrect_type': _('Incorrect type. Expected pk value, received {data_type}.'), + } + + def __init__(self, **kwargs): + self.pk_field = kwargs.pop('pk_field', None) + super().__init__(**kwargs) + + def use_pk_only_optimization(self): + return True + + def to_internal_value(self, data): + if self.pk_field is not None: + data = self.pk_field.to_internal_value(data) + queryset = self.get_queryset() + try: + if isinstance(data, bool): + raise TypeError + return queryset.get(pk=data) + except ObjectDoesNotExist: + self.fail('does_not_exist', pk_value=data) + except (TypeError, ValueError): + self.fail('incorrect_type', data_type=type(data).__name__) + + def to_representation(self, value): + if self.pk_field is not None: + return self.pk_field.to_representation(value.pk) + return value.pk + + +class HyperlinkedRelatedField(RelatedField): + lookup_field = 'pk' + view_name = None + + default_error_messages = { + 'required': _('This field is required.'), + 'no_match': _('Invalid hyperlink - No URL match.'), + 'incorrect_match': _('Invalid hyperlink - Incorrect URL match.'), + 'does_not_exist': _('Invalid hyperlink - Object does not exist.'), + 'incorrect_type': _('Incorrect type. Expected URL string, received {data_type}.'), + } + + def __init__(self, view_name=None, **kwargs): + if view_name is not None: + self.view_name = view_name + assert self.view_name is not None, 'The `view_name` argument is required.' + self.lookup_field = kwargs.pop('lookup_field', self.lookup_field) + self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field) + self.format = kwargs.pop('format', None) + + # We include this simply for dependency injection in tests. + # We can't add it as a class attributes or it would expect an + # implicit `self` argument to be passed. + self.reverse = reverse + + super().__init__(**kwargs) + + def use_pk_only_optimization(self): + return self.lookup_field == 'pk' + + def get_object(self, view_name, view_args, view_kwargs): + """ + Return the object corresponding to a matched URL. + + Takes the matched URL conf arguments, and should return an + object instance, or raise an `ObjectDoesNotExist` exception. + """ + lookup_value = view_kwargs[self.lookup_url_kwarg] + lookup_kwargs = {self.lookup_field: lookup_value} + queryset = self.get_queryset() + + try: + return queryset.get(**lookup_kwargs) + except ValueError: + exc = ObjectValueError(str(sys.exc_info()[1])) + raise exc.with_traceback(sys.exc_info()[2]) + except TypeError: + exc = ObjectTypeError(str(sys.exc_info()[1])) + raise exc.with_traceback(sys.exc_info()[2]) + + def get_url(self, obj, view_name, request, format): + """ + Given an object, return the URL that hyperlinks to the object. + + May raise a `NoReverseMatch` if the `view_name` and `lookup_field` + attributes are not configured to correctly match the URL conf. + """ + # Unsaved objects will not yet have a valid URL. + if hasattr(obj, 'pk') and obj.pk in (None, ''): + return None + + lookup_value = getattr(obj, self.lookup_field) + kwargs = {self.lookup_url_kwarg: lookup_value} + return self.reverse(view_name, kwargs=kwargs, request=request, format=format) + + def to_internal_value(self, data): + request = self.context.get('request') + try: + http_prefix = data.startswith(('http:', 'https:')) + except AttributeError: + self.fail('incorrect_type', data_type=type(data).__name__) + + if http_prefix: + # If needed convert absolute URLs to relative path + data = parse.urlparse(data).path + prefix = get_script_prefix() + if data.startswith(prefix): + data = '/' + data[len(prefix):] + + data = uri_to_iri(parse.unquote(data)) + + try: + match = resolve(data) + except Resolver404: + self.fail('no_match') + + try: + expected_viewname = request.versioning_scheme.get_versioned_viewname( + self.view_name, request + ) + except AttributeError: + expected_viewname = self.view_name + + if match.view_name != expected_viewname: + self.fail('incorrect_match') + + try: + return self.get_object(match.view_name, match.args, match.kwargs) + except (ObjectDoesNotExist, ObjectValueError, ObjectTypeError): + self.fail('does_not_exist') + + def to_representation(self, value): + assert 'request' in self.context, ( + "`%s` requires the request in the serializer" + " context. Add `context={'request': request}` when instantiating " + "the serializer." % self.__class__.__name__ + ) + + request = self.context['request'] + format = self.context.get('format') + + # By default use whatever format is given for the current context + # unless the target is a different type to the source. + # + # Eg. Consider a HyperlinkedIdentityField pointing from a json + # representation to an html property of that representation... + # + # '/snippets/1/' should link to '/snippets/1/highlight/' + # ...but... + # '/snippets/1/.json' should link to '/snippets/1/highlight/.html' + if format and self.format and self.format != format: + format = self.format + + # Return the hyperlink, or error if incorrectly configured. + try: + url = self.get_url(value, self.view_name, request, format) + except NoReverseMatch: + msg = ( + 'Could not resolve URL for hyperlinked relationship using ' + 'view name "%s". You may have failed to include the related ' + 'model in your API, or incorrectly configured the ' + '`lookup_field` attribute on this field.' + ) + if value in ('', None): + value_string = {'': 'the empty string', None: 'None'}[value] + msg += ( + " WARNING: The value of the field on the model instance " + "was %s, which may be why it didn't match any " + "entries in your URL conf." % value_string + ) + raise ImproperlyConfigured(msg % self.view_name) + + if url is None: + return None + + return Hyperlink(url, value) + + +class HyperlinkedIdentityField(HyperlinkedRelatedField): + """ + A read-only field that represents the identity URL for an object, itself. + + This is in contrast to `HyperlinkedRelatedField` which represents the + URL of relationships to other objects. + """ + + def __init__(self, view_name=None, **kwargs): + assert view_name is not None, 'The `view_name` argument is required.' + kwargs['read_only'] = True + kwargs['source'] = '*' + super().__init__(view_name, **kwargs) + + def use_pk_only_optimization(self): + # We have the complete object instance already. We don't need + # to run the 'only get the pk for this relationship' code. + return False + + +class SlugRelatedField(RelatedField): + """ + A read-write field that represents the target of the relationship + by a unique 'slug' attribute. + """ + default_error_messages = { + 'does_not_exist': _('Object with {slug_name}={value} does not exist.'), + 'invalid': _('Invalid value.'), + } + + def __init__(self, slug_field=None, **kwargs): + assert slug_field is not None, 'The `slug_field` argument is required.' + self.slug_field = slug_field + super().__init__(**kwargs) + + def to_internal_value(self, data): + queryset = self.get_queryset() + try: + return queryset.get(**{self.slug_field: data}) + except ObjectDoesNotExist: + self.fail('does_not_exist', slug_name=self.slug_field, value=smart_str(data)) + except (TypeError, ValueError): + self.fail('invalid') + + def to_representation(self, obj): + return getattr(obj, self.slug_field) + + +class ManyRelatedField(Field): + """ + Relationships with `many=True` transparently get coerced into instead being + a ManyRelatedField with a child relationship. + + The `ManyRelatedField` class is responsible for handling iterating through + the values and passing each one to the child relationship. + + This class is treated as private API. + You shouldn't generally need to be using this class directly yourself, + and should instead simply set 'many=True' on the relationship. + """ + initial = [] + default_empty_html = [] + default_error_messages = { + 'not_a_list': _('Expected a list of items but got type "{input_type}".'), + 'empty': _('This list may not be empty.') + } + html_cutoff = None + html_cutoff_text = None + + def __init__(self, child_relation=None, *args, **kwargs): + self.child_relation = child_relation + self.allow_empty = kwargs.pop('allow_empty', True) + + cutoff_from_settings = api_settings.HTML_SELECT_CUTOFF + if cutoff_from_settings is not None: + cutoff_from_settings = int(cutoff_from_settings) + self.html_cutoff = kwargs.pop('html_cutoff', cutoff_from_settings) + + self.html_cutoff_text = kwargs.pop( + 'html_cutoff_text', + self.html_cutoff_text or _(api_settings.HTML_SELECT_CUTOFF_TEXT) + ) + assert child_relation is not None, '`child_relation` is a required argument.' + super().__init__(*args, **kwargs) + self.child_relation.bind(field_name='', parent=self) + + def get_value(self, dictionary): + # We override the default field access in order to support + # lists in HTML forms. + if html.is_html_input(dictionary): + # Don't return [] if the update is partial + if self.field_name not in dictionary: + if getattr(self.root, 'partial', False): + return empty + return dictionary.getlist(self.field_name) + + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + if isinstance(data, str) or not hasattr(data, '__iter__'): + self.fail('not_a_list', input_type=type(data).__name__) + if not self.allow_empty and len(data) == 0: + self.fail('empty') + + return [ + self.child_relation.to_internal_value(item) + for item in data + ] + + def get_attribute(self, instance): + # Can't have any relationships if not created + if hasattr(instance, 'pk') and instance.pk is None: + return [] + + try: + relationship = get_attribute(instance, self.source_attrs) + except (KeyError, AttributeError) as exc: + if self.default is not empty: + return self.get_default() + if self.allow_null: + return None + if not self.required: + raise SkipField() + msg = ( + 'Got {exc_type} when attempting to get a value for field ' + '`{field}` on serializer `{serializer}`.\nThe serializer ' + 'field might be named incorrectly and not match ' + 'any attribute or key on the `{instance}` instance.\n' + 'Original exception text was: {exc}.'.format( + exc_type=type(exc).__name__, + field=self.field_name, + serializer=self.parent.__class__.__name__, + instance=instance.__class__.__name__, + exc=exc + ) + ) + raise type(exc)(msg) + + return relationship.all() if hasattr(relationship, 'all') else relationship + + def to_representation(self, iterable): + return [ + self.child_relation.to_representation(value) + for value in iterable + ] + + def get_choices(self, cutoff=None): + return self.child_relation.get_choices(cutoff) + + @property + def choices(self): + return self.get_choices() + + @property + def grouped_choices(self): + return self.choices + + def iter_options(self): + return iter_options( + self.get_choices(cutoff=self.html_cutoff), + cutoff=self.html_cutoff, + cutoff_text=self.html_cutoff_text + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/renderers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/renderers.py new file mode 100644 index 0000000000000000000000000000000000000000..b74df9a0bb90ec6ef4e89ff33f770f411b89248c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/renderers.py @@ -0,0 +1,1075 @@ +""" +Renderers are used to serialize a response into specific media types. + +They give us a generic way of being able to handle various media types +on the response, such as JSON encoded data or HTML output. + +REST framework also provides an HTML renderer that renders the browsable API. +""" +import base64 +from collections import OrderedDict +from urllib import parse + +from django import forms +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.core.paginator import Page +from django.template import engines, loader +from django.urls import NoReverseMatch +from django.utils.html import mark_safe + +from rest_framework import VERSION, exceptions, serializers, status +from rest_framework.compat import ( + INDENT_SEPARATORS, LONG_SEPARATORS, SHORT_SEPARATORS, coreapi, coreschema, + parse_header_parameters, pygments_css, yaml +) +from rest_framework.exceptions import ParseError +from rest_framework.request import is_form_media_type, override_method +from rest_framework.settings import api_settings +from rest_framework.utils import encoders, json +from rest_framework.utils.breadcrumbs import get_breadcrumbs +from rest_framework.utils.field_mapping import ClassLookupDict + + +def zero_as_none(value): + return None if value == 0 else value + + +class BaseRenderer: + """ + All renderers should extend this class, setting the `media_type` + and `format` attributes, and override the `.render()` method. + """ + media_type = None + format = None + charset = 'utf-8' + render_style = 'text' + + def render(self, data, accepted_media_type=None, renderer_context=None): + raise NotImplementedError('Renderer class requires .render() to be implemented') + + +class JSONRenderer(BaseRenderer): + """ + Renderer which serializes to JSON. + """ + media_type = 'application/json' + format = 'json' + encoder_class = encoders.JSONEncoder + ensure_ascii = not api_settings.UNICODE_JSON + compact = api_settings.COMPACT_JSON + strict = api_settings.STRICT_JSON + + # We don't set a charset because JSON is a binary encoding, + # that can be encoded as utf-8, utf-16 or utf-32. + # See: https://www.ietf.org/rfc/rfc4627.txt + # Also: http://lucumr.pocoo.org/2013/7/19/application-mimetypes-and-encodings/ + charset = None + + def get_indent(self, accepted_media_type, renderer_context): + if accepted_media_type: + # If the media type looks like 'application/json; indent=4', + # then pretty print the result. + # Note that we coerce `indent=0` into `indent=None`. + base_media_type, params = parse_header_parameters(accepted_media_type) + try: + return zero_as_none(max(min(int(params['indent']), 8), 0)) + except (KeyError, ValueError, TypeError): + pass + + # If 'indent' is provided in the context, then pretty print the result. + # E.g. If we're being called by the BrowsableAPIRenderer. + return renderer_context.get('indent', None) + + def render(self, data, accepted_media_type=None, renderer_context=None): + """ + Render `data` into JSON, returning a bytestring. + """ + if data is None: + return b'' + + renderer_context = renderer_context or {} + indent = self.get_indent(accepted_media_type, renderer_context) + + if indent is None: + separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS + else: + separators = INDENT_SEPARATORS + + ret = json.dumps( + data, cls=self.encoder_class, + indent=indent, ensure_ascii=self.ensure_ascii, + allow_nan=not self.strict, separators=separators + ) + + # We always fully escape \u2028 and \u2029 to ensure we output JSON + # that is a strict javascript subset. + # See: https://gist.github.com/damncabbage/623b879af56f850a6ddc + ret = ret.replace('\u2028', '\\u2028').replace('\u2029', '\\u2029') + return ret.encode() + + +class TemplateHTMLRenderer(BaseRenderer): + """ + An HTML renderer for use with templates. + + The data supplied to the Response object should be a dictionary that will + be used as context for the template. + + The template name is determined by (in order of preference): + + 1. An explicit `.template_name` attribute set on the response. + 2. An explicit `.template_name` attribute set on this class. + 3. The return result of calling `view.get_template_names()`. + + For example: + data = {'users': User.objects.all()} + return Response(data, template_name='users.html') + + For pre-rendered HTML, see StaticHTMLRenderer. + """ + media_type = 'text/html' + format = 'html' + template_name = None + exception_template_names = [ + '%(status_code)s.html', + 'api_exception.html' + ] + charset = 'utf-8' + + def render(self, data, accepted_media_type=None, renderer_context=None): + """ + Renders data to HTML, using Django's standard template rendering. + + The template name is determined by (in order of preference): + + 1. An explicit .template_name set on the response. + 2. An explicit .template_name set on this class. + 3. The return result of calling view.get_template_names(). + """ + renderer_context = renderer_context or {} + view = renderer_context['view'] + request = renderer_context['request'] + response = renderer_context['response'] + + if response.exception: + template = self.get_exception_template(response) + else: + template_names = self.get_template_names(response, view) + template = self.resolve_template(template_names) + + if hasattr(self, 'resolve_context'): + # Fallback for older versions. + context = self.resolve_context(data, request, response) + else: + context = self.get_template_context(data, renderer_context) + return template.render(context, request=request) + + def resolve_template(self, template_names): + return loader.select_template(template_names) + + def get_template_context(self, data, renderer_context): + response = renderer_context['response'] + if response.exception: + data['status_code'] = response.status_code + return data + + def get_template_names(self, response, view): + if response.template_name: + return [response.template_name] + elif self.template_name: + return [self.template_name] + elif hasattr(view, 'get_template_names'): + return view.get_template_names() + elif hasattr(view, 'template_name'): + return [view.template_name] + raise ImproperlyConfigured( + 'Returned a template response with no `template_name` attribute set on either the view or response' + ) + + def get_exception_template(self, response): + template_names = [name % {'status_code': response.status_code} + for name in self.exception_template_names] + + try: + # Try to find an appropriate error template + return self.resolve_template(template_names) + except Exception: + # Fall back to using eg '404 Not Found' + body = '%d %s' % (response.status_code, response.status_text.title()) + template = engines['django'].from_string(body) + return template + + +# Note, subclass TemplateHTMLRenderer simply for the exception behavior +class StaticHTMLRenderer(TemplateHTMLRenderer): + """ + An HTML renderer class that simply returns pre-rendered HTML. + + The data supplied to the Response object should be a string representing + the pre-rendered HTML content. + + For example: + data = '<html><body>example</body></html>' + return Response(data) + + For template rendered HTML, see TemplateHTMLRenderer. + """ + media_type = 'text/html' + format = 'html' + charset = 'utf-8' + + def render(self, data, accepted_media_type=None, renderer_context=None): + renderer_context = renderer_context or {} + response = renderer_context.get('response') + + if response and response.exception: + request = renderer_context['request'] + template = self.get_exception_template(response) + if hasattr(self, 'resolve_context'): + context = self.resolve_context(data, request, response) + else: + context = self.get_template_context(data, renderer_context) + return template.render(context, request=request) + + return data + + +class HTMLFormRenderer(BaseRenderer): + """ + Renderers serializer data into an HTML form. + + If the serializer was instantiated without an object then this will + return an HTML form not bound to any object, + otherwise it will return an HTML form with the appropriate initial data + populated from the object. + + Note that rendering of field and form errors is not currently supported. + """ + media_type = 'text/html' + format = 'form' + charset = 'utf-8' + template_pack = 'rest_framework/vertical/' + base_template = 'form.html' + + default_style = ClassLookupDict({ + serializers.Field: { + 'base_template': 'input.html', + 'input_type': 'text' + }, + serializers.EmailField: { + 'base_template': 'input.html', + 'input_type': 'email' + }, + serializers.URLField: { + 'base_template': 'input.html', + 'input_type': 'url' + }, + serializers.IntegerField: { + 'base_template': 'input.html', + 'input_type': 'number' + }, + serializers.FloatField: { + 'base_template': 'input.html', + 'input_type': 'number' + }, + serializers.DateTimeField: { + 'base_template': 'input.html', + 'input_type': 'datetime-local' + }, + serializers.DateField: { + 'base_template': 'input.html', + 'input_type': 'date' + }, + serializers.TimeField: { + 'base_template': 'input.html', + 'input_type': 'time' + }, + serializers.FileField: { + 'base_template': 'input.html', + 'input_type': 'file' + }, + serializers.BooleanField: { + 'base_template': 'checkbox.html' + }, + serializers.ChoiceField: { + 'base_template': 'select.html', # Also valid: 'radio.html' + }, + serializers.MultipleChoiceField: { + 'base_template': 'select_multiple.html', # Also valid: 'checkbox_multiple.html' + }, + serializers.RelatedField: { + 'base_template': 'select.html', # Also valid: 'radio.html' + }, + serializers.ManyRelatedField: { + 'base_template': 'select_multiple.html', # Also valid: 'checkbox_multiple.html' + }, + serializers.Serializer: { + 'base_template': 'fieldset.html' + }, + serializers.ListSerializer: { + 'base_template': 'list_fieldset.html' + }, + serializers.ListField: { + 'base_template': 'list_field.html' + }, + serializers.DictField: { + 'base_template': 'dict_field.html' + }, + serializers.FilePathField: { + 'base_template': 'select.html', + }, + serializers.JSONField: { + 'base_template': 'textarea.html', + }, + }) + + def render_field(self, field, parent_style): + if isinstance(field._field, serializers.HiddenField): + return '' + + style = self.default_style[field].copy() + style.update(field.style) + if 'template_pack' not in style: + style['template_pack'] = parent_style.get('template_pack', self.template_pack) + style['renderer'] = self + + # Get a clone of the field with text-only value representation. + field = field.as_form_field() + + if style.get('input_type') == 'datetime-local' and isinstance(field.value, str): + field.value = field.value.rstrip('Z') + + if 'template' in style: + template_name = style['template'] + else: + template_name = style['template_pack'].strip('/') + '/' + style['base_template'] + + template = loader.get_template(template_name) + context = {'field': field, 'style': style} + return template.render(context) + + def render(self, data, accepted_media_type=None, renderer_context=None): + """ + Render serializer data and return an HTML form, as a string. + """ + renderer_context = renderer_context or {} + form = data.serializer + + style = renderer_context.get('style', {}) + if 'template_pack' not in style: + style['template_pack'] = self.template_pack + style['renderer'] = self + + template_pack = style['template_pack'].strip('/') + template_name = template_pack + '/' + self.base_template + template = loader.get_template(template_name) + context = { + 'form': form, + 'style': style + } + return template.render(context) + + +class BrowsableAPIRenderer(BaseRenderer): + """ + HTML renderer used to self-document the API. + """ + media_type = 'text/html' + format = 'api' + template = 'rest_framework/api.html' + filter_template = 'rest_framework/filters/base.html' + code_style = 'emacs' + charset = 'utf-8' + form_renderer_class = HTMLFormRenderer + + def get_default_renderer(self, view): + """ + Return an instance of the first valid renderer. + (Don't use another documenting renderer.) + """ + renderers = [renderer for renderer in view.renderer_classes + if not issubclass(renderer, BrowsableAPIRenderer)] + non_template_renderers = [renderer for renderer in renderers + if not hasattr(renderer, 'get_template_names')] + + if not renderers: + return None + elif non_template_renderers: + return non_template_renderers[0]() + return renderers[0]() + + def get_content(self, renderer, data, + accepted_media_type, renderer_context): + """ + Get the content as if it had been rendered by the default + non-documenting renderer. + """ + if not renderer: + return '[No renderers were found]' + + renderer_context['indent'] = 4 + content = renderer.render(data, accepted_media_type, renderer_context) + + render_style = getattr(renderer, 'render_style', 'text') + assert render_style in ['text', 'binary'], 'Expected .render_style ' \ + '"text" or "binary", but got "%s"' % render_style + if render_style == 'binary': + return '[%d bytes of binary content]' % len(content) + + return content.decode('utf-8') if isinstance(content, bytes) else content + + def show_form_for_method(self, view, method, request, obj): + """ + Returns True if a form should be shown for this method. + """ + if method not in view.allowed_methods: + return # Not a valid method + + try: + view.check_permissions(request) + if obj is not None: + view.check_object_permissions(request, obj) + except exceptions.APIException: + return False # Doesn't have permissions + return True + + def _get_serializer(self, serializer_class, view_instance, request, *args, **kwargs): + kwargs['context'] = { + 'request': request, + 'format': self.format, + 'view': view_instance + } + return serializer_class(*args, **kwargs) + + def get_rendered_html_form(self, data, view, method, request): + """ + Return a string representing a rendered HTML form, possibly bound to + either the input or output data. + + In the absence of the View having an associated form then return None. + """ + # See issue #2089 for refactoring this. + serializer = getattr(data, 'serializer', None) + if serializer and not getattr(serializer, 'many', False): + instance = getattr(serializer, 'instance', None) + if isinstance(instance, Page): + instance = None + else: + instance = None + + # If this is valid serializer data, and the form is for the same + # HTTP method as was used in the request then use the existing + # serializer instance, rather than dynamically creating a new one. + if request.method == method and serializer is not None: + try: + kwargs = {'data': request.data} + except ParseError: + kwargs = {} + existing_serializer = serializer + else: + kwargs = {} + existing_serializer = None + + with override_method(view, request, method) as request: + if not self.show_form_for_method(view, method, request, instance): + return + + if method in ('DELETE', 'OPTIONS'): + return True # Don't actually need to return a form + + has_serializer = getattr(view, 'get_serializer', None) + has_serializer_class = getattr(view, 'serializer_class', None) + + if ( + (not has_serializer and not has_serializer_class) or + not any(is_form_media_type(parser.media_type) for parser in view.parser_classes) + ): + return + + if existing_serializer is not None: + try: + return self.render_form_for_serializer(existing_serializer) + except TypeError: + pass + + if has_serializer: + if method in ('PUT', 'PATCH'): + serializer = view.get_serializer(instance=instance, **kwargs) + else: + serializer = view.get_serializer(**kwargs) + else: + # at this point we must have a serializer_class + if method in ('PUT', 'PATCH'): + serializer = self._get_serializer(view.serializer_class, view, + request, instance=instance, **kwargs) + else: + serializer = self._get_serializer(view.serializer_class, view, + request, **kwargs) + + return self.render_form_for_serializer(serializer) + + def render_form_for_serializer(self, serializer): + if hasattr(serializer, 'initial_data'): + serializer.is_valid() + + form_renderer = self.form_renderer_class() + return form_renderer.render( + serializer.data, + self.accepted_media_type, + {'style': {'template_pack': 'rest_framework/horizontal'}} + ) + + def get_raw_data_form(self, data, view, method, request): + """ + Returns a form that allows for arbitrary content types to be tunneled + via standard HTML forms. + (Which are typically application/x-www-form-urlencoded) + """ + # See issue #2089 for refactoring this. + serializer = getattr(data, 'serializer', None) + if serializer and not getattr(serializer, 'many', False): + instance = getattr(serializer, 'instance', None) + if isinstance(instance, Page): + instance = None + else: + instance = None + + with override_method(view, request, method) as request: + # Check permissions + if not self.show_form_for_method(view, method, request, instance): + return + + # If possible, serialize the initial content for the generic form + default_parser = view.parser_classes[0] + renderer_class = getattr(default_parser, 'renderer_class', None) + if hasattr(view, 'get_serializer') and renderer_class: + # View has a serializer defined and parser class has a + # corresponding renderer that can be used to render the data. + + if method in ('PUT', 'PATCH'): + serializer = view.get_serializer(instance=instance) + else: + serializer = view.get_serializer() + + # Render the raw data content + renderer = renderer_class() + accepted = self.accepted_media_type + context = self.renderer_context.copy() + context['indent'] = 4 + + # strip HiddenField from output + data = serializer.data.copy() + for name, field in serializer.fields.items(): + if isinstance(field, serializers.HiddenField): + data.pop(name, None) + content = renderer.render(data, accepted, context) + # Renders returns bytes, but CharField expects a str. + content = content.decode() + else: + content = None + + # Generate a generic form that includes a content type field, + # and a content field. + media_types = [parser.media_type for parser in view.parser_classes] + choices = [(media_type, media_type) for media_type in media_types] + initial = media_types[0] + + class GenericContentForm(forms.Form): + _content_type = forms.ChoiceField( + label='Media type', + choices=choices, + initial=initial, + widget=forms.Select(attrs={'data-override': 'content-type'}) + ) + _content = forms.CharField( + label='Content', + widget=forms.Textarea(attrs={'data-override': 'content'}), + initial=content, + required=False + ) + + return GenericContentForm() + + def get_name(self, view): + return view.get_view_name() + + def get_description(self, view, status_code): + if status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN): + return '' + return view.get_view_description(html=True) + + def get_breadcrumbs(self, request): + return get_breadcrumbs(request.path, request) + + def get_extra_actions(self, view, status_code): + if (status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN)): + return None + elif not hasattr(view, 'get_extra_action_url_map'): + return None + + return view.get_extra_action_url_map() + + def get_filter_form(self, data, view, request): + if not hasattr(view, 'get_queryset') or not hasattr(view, 'filter_backends'): + return + + # Infer if this is a list view or not. + paginator = getattr(view, 'paginator', None) + if isinstance(data, list): + pass + elif paginator is not None and data is not None: + try: + paginator.get_results(data) + except (TypeError, KeyError): + return + elif not isinstance(data, list): + return + + queryset = view.get_queryset() + elements = [] + for backend in view.filter_backends: + if hasattr(backend, 'to_html'): + html = backend().to_html(request, queryset, view) + if html: + elements.append(html) + + if not elements: + return + + template = loader.get_template(self.filter_template) + context = {'elements': elements} + return template.render(context) + + def get_context(self, data, accepted_media_type, renderer_context): + """ + Returns the context used to render. + """ + view = renderer_context['view'] + request = renderer_context['request'] + response = renderer_context['response'] + + renderer = self.get_default_renderer(view) + + raw_data_post_form = self.get_raw_data_form(data, view, 'POST', request) + raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request) + raw_data_patch_form = self.get_raw_data_form(data, view, 'PATCH', request) + raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form + + response_headers = OrderedDict(sorted(response.items())) + renderer_content_type = '' + if renderer: + renderer_content_type = '%s' % renderer.media_type + if renderer.charset: + renderer_content_type += ' ;%s' % renderer.charset + response_headers['Content-Type'] = renderer_content_type + + if getattr(view, 'paginator', None) and view.paginator.display_page_controls: + paginator = view.paginator + else: + paginator = None + + csrf_cookie_name = settings.CSRF_COOKIE_NAME + csrf_header_name = settings.CSRF_HEADER_NAME + if csrf_header_name.startswith('HTTP_'): + csrf_header_name = csrf_header_name[5:] + csrf_header_name = csrf_header_name.replace('_', '-') + + return { + 'content': self.get_content(renderer, data, accepted_media_type, renderer_context), + 'code_style': pygments_css(self.code_style), + 'view': view, + 'request': request, + 'response': response, + 'user': request.user, + 'description': self.get_description(view, response.status_code), + 'name': self.get_name(view), + 'version': VERSION, + 'paginator': paginator, + 'breadcrumblist': self.get_breadcrumbs(request), + 'allowed_methods': view.allowed_methods, + 'available_formats': [renderer_cls.format for renderer_cls in view.renderer_classes], + 'response_headers': response_headers, + + 'put_form': self.get_rendered_html_form(data, view, 'PUT', request), + 'post_form': self.get_rendered_html_form(data, view, 'POST', request), + 'delete_form': self.get_rendered_html_form(data, view, 'DELETE', request), + 'options_form': self.get_rendered_html_form(data, view, 'OPTIONS', request), + + 'extra_actions': self.get_extra_actions(view, response.status_code), + + 'filter_form': self.get_filter_form(data, view, request), + + 'raw_data_put_form': raw_data_put_form, + 'raw_data_post_form': raw_data_post_form, + 'raw_data_patch_form': raw_data_patch_form, + 'raw_data_put_or_patch_form': raw_data_put_or_patch_form, + + 'display_edit_forms': bool(response.status_code != 403), + + 'api_settings': api_settings, + 'csrf_cookie_name': csrf_cookie_name, + 'csrf_header_name': csrf_header_name + } + + def render(self, data, accepted_media_type=None, renderer_context=None): + """ + Render the HTML for the browsable API representation. + """ + self.accepted_media_type = accepted_media_type or '' + self.renderer_context = renderer_context or {} + + template = loader.get_template(self.template) + context = self.get_context(data, accepted_media_type, renderer_context) + ret = template.render(context, request=renderer_context['request']) + + # Munge DELETE Response code to allow us to return content + # (Do this *after* we've rendered the template so that we include + # the normal deletion response code in the output) + response = renderer_context['response'] + if response.status_code == status.HTTP_204_NO_CONTENT: + response.status_code = status.HTTP_200_OK + + return ret + + +class AdminRenderer(BrowsableAPIRenderer): + template = 'rest_framework/admin.html' + format = 'admin' + + def render(self, data, accepted_media_type=None, renderer_context=None): + self.accepted_media_type = accepted_media_type or '' + self.renderer_context = renderer_context or {} + + response = renderer_context['response'] + request = renderer_context['request'] + view = self.renderer_context['view'] + + if response.status_code == status.HTTP_400_BAD_REQUEST: + # Errors still need to display the list or detail information. + # The only way we can get at that is to simulate a GET request. + self.error_form = self.get_rendered_html_form(data, view, request.method, request) + self.error_title = {'POST': 'Create', 'PUT': 'Edit'}.get(request.method, 'Errors') + + with override_method(view, request, 'GET') as request: + response = view.get(request, *view.args, **view.kwargs) + data = response.data + + template = loader.get_template(self.template) + context = self.get_context(data, accepted_media_type, renderer_context) + ret = template.render(context, request=renderer_context['request']) + + # Creation and deletion should use redirects in the admin style. + if response.status_code == status.HTTP_201_CREATED and 'Location' in response: + response.status_code = status.HTTP_303_SEE_OTHER + response['Location'] = request.build_absolute_uri() + ret = '' + + if response.status_code == status.HTTP_204_NO_CONTENT: + response.status_code = status.HTTP_303_SEE_OTHER + try: + # Attempt to get the parent breadcrumb URL. + response['Location'] = self.get_breadcrumbs(request)[-2][1] + except KeyError: + # Otherwise reload current URL to get a 'Not Found' page. + response['Location'] = request.full_path + ret = '' + + return ret + + def get_context(self, data, accepted_media_type, renderer_context): + """ + Render the HTML for the browsable API representation. + """ + context = super().get_context( + data, accepted_media_type, renderer_context + ) + + paginator = getattr(context['view'], 'paginator', None) + if paginator is not None and data is not None: + try: + results = paginator.get_results(data) + except (TypeError, KeyError): + results = data + else: + results = data + + if results is None: + header = {} + style = 'detail' + elif isinstance(results, list): + header = results[0] if results else {} + style = 'list' + else: + header = results + style = 'detail' + + columns = [key for key in header if key != 'url'] + details = [key for key in header if key != 'url'] + + if isinstance(results, list) and 'view' in renderer_context: + for result in results: + url = self.get_result_url(result, context['view']) + if url is not None: + result.setdefault('url', url) + + context['style'] = style + context['columns'] = columns + context['details'] = details + context['results'] = results + context['error_form'] = getattr(self, 'error_form', None) + context['error_title'] = getattr(self, 'error_title', None) + return context + + def get_result_url(self, result, view): + """ + Attempt to reverse the result's detail view URL. + + This only works with views that are generic-like (has `.lookup_field`) + and viewset-like (has `.basename` / `.reverse_action()`). + """ + if not hasattr(view, 'reverse_action') or \ + not hasattr(view, 'lookup_field'): + return + + lookup_field = view.lookup_field + lookup_url_kwarg = getattr(view, 'lookup_url_kwarg', None) or lookup_field + + try: + kwargs = {lookup_url_kwarg: result[lookup_field]} + return view.reverse_action('detail', kwargs=kwargs) + except (KeyError, NoReverseMatch): + return + + +class DocumentationRenderer(BaseRenderer): + media_type = 'text/html' + format = 'html' + charset = 'utf-8' + template = 'rest_framework/docs/index.html' + error_template = 'rest_framework/docs/error.html' + code_style = 'emacs' + languages = ['shell', 'javascript', 'python'] + + def get_context(self, data, request): + return { + 'document': data, + 'langs': self.languages, + 'lang_htmls': ["rest_framework/docs/langs/%s.html" % language for language in self.languages], + 'lang_intro_htmls': ["rest_framework/docs/langs/%s-intro.html" % language for language in self.languages], + 'code_style': pygments_css(self.code_style), + 'request': request + } + + def render(self, data, accepted_media_type=None, renderer_context=None): + if isinstance(data, coreapi.Document): + template = loader.get_template(self.template) + context = self.get_context(data, renderer_context['request']) + return template.render(context, request=renderer_context['request']) + else: + template = loader.get_template(self.error_template) + context = { + "data": data, + "request": renderer_context['request'], + "response": renderer_context['response'], + "debug": settings.DEBUG, + } + return template.render(context, request=renderer_context['request']) + + +class SchemaJSRenderer(BaseRenderer): + media_type = 'application/javascript' + format = 'javascript' + charset = 'utf-8' + template = 'rest_framework/schema.js' + + def render(self, data, accepted_media_type=None, renderer_context=None): + codec = coreapi.codecs.CoreJSONCodec() + schema = base64.b64encode(codec.encode(data)).decode('ascii') + + template = loader.get_template(self.template) + context = {'schema': mark_safe(schema)} + request = renderer_context['request'] + return template.render(context, request=request) + + +class MultiPartRenderer(BaseRenderer): + media_type = 'multipart/form-data; boundary=BoUnDaRyStRiNg' + format = 'multipart' + charset = 'utf-8' + BOUNDARY = 'BoUnDaRyStRiNg' + + def render(self, data, accepted_media_type=None, renderer_context=None): + from django.test.client import encode_multipart + + if hasattr(data, 'items'): + for key, value in data.items(): + assert not isinstance(value, dict), ( + "Test data contained a dictionary value for key '%s', " + "but multipart uploads do not support nested data. " + "You may want to consider using format='json' in this " + "test case." % key + ) + return encode_multipart(self.BOUNDARY, data) + + +class CoreJSONRenderer(BaseRenderer): + media_type = 'application/coreapi+json' + charset = None + format = 'corejson' + + def __init__(self): + assert coreapi, 'Using CoreJSONRenderer, but `coreapi` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + indent = bool(renderer_context.get('indent', 0)) + codec = coreapi.codecs.CoreJSONCodec() + return codec.dump(data, indent=indent) + + +class _BaseOpenAPIRenderer: + def get_schema(self, instance): + CLASS_TO_TYPENAME = { + coreschema.Object: 'object', + coreschema.Array: 'array', + coreschema.Number: 'number', + coreschema.Integer: 'integer', + coreschema.String: 'string', + coreschema.Boolean: 'boolean', + } + + schema = {} + if instance.__class__ in CLASS_TO_TYPENAME: + schema['type'] = CLASS_TO_TYPENAME[instance.__class__] + schema['title'] = instance.title + schema['description'] = instance.description + if hasattr(instance, 'enum'): + schema['enum'] = instance.enum + return schema + + def get_parameters(self, link): + parameters = [] + for field in link.fields: + if field.location not in ['path', 'query']: + continue + parameter = { + 'name': field.name, + 'in': field.location, + } + if field.required: + parameter['required'] = True + if field.description: + parameter['description'] = field.description + if field.schema: + parameter['schema'] = self.get_schema(field.schema) + parameters.append(parameter) + return parameters + + def get_operation(self, link, name, tag): + operation_id = "%s_%s" % (tag, name) if tag else name + parameters = self.get_parameters(link) + + operation = { + 'operationId': operation_id, + } + if link.title: + operation['summary'] = link.title + if link.description: + operation['description'] = link.description + if parameters: + operation['parameters'] = parameters + if tag: + operation['tags'] = [tag] + return operation + + def get_paths(self, document): + paths = {} + + tag = None + for name, link in document.links.items(): + path = parse.urlparse(link.url).path + method = link.action.lower() + paths.setdefault(path, {}) + paths[path][method] = self.get_operation(link, name, tag=tag) + + for tag, section in document.data.items(): + for name, link in section.links.items(): + path = parse.urlparse(link.url).path + method = link.action.lower() + paths.setdefault(path, {}) + paths[path][method] = self.get_operation(link, name, tag=tag) + + return paths + + def get_structure(self, data): + return { + 'openapi': '3.0.0', + 'info': { + 'version': '', + 'title': data.title, + 'description': data.description + }, + 'servers': [{ + 'url': data.url + }], + 'paths': self.get_paths(data) + } + + +class CoreAPIOpenAPIRenderer(_BaseOpenAPIRenderer): + media_type = 'application/vnd.oai.openapi' + charset = None + format = 'openapi' + + def __init__(self): + assert coreapi, 'Using CoreAPIOpenAPIRenderer, but `coreapi` is not installed.' + assert yaml, 'Using CoreAPIOpenAPIRenderer, but `pyyaml` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + structure = self.get_structure(data) + return yaml.dump(structure, default_flow_style=False).encode() + + +class CoreAPIJSONOpenAPIRenderer(_BaseOpenAPIRenderer): + media_type = 'application/vnd.oai.openapi+json' + charset = None + format = 'openapi-json' + ensure_ascii = not api_settings.UNICODE_JSON + + def __init__(self): + assert coreapi, 'Using CoreAPIJSONOpenAPIRenderer, but `coreapi` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + structure = self.get_structure(data) + return json.dumps( + structure, indent=4, + ensure_ascii=self.ensure_ascii).encode('utf-8') + + +class OpenAPIRenderer(BaseRenderer): + media_type = 'application/vnd.oai.openapi' + charset = None + format = 'openapi' + + def __init__(self): + assert yaml, 'Using OpenAPIRenderer, but `pyyaml` is not installed.' + + def render(self, data, media_type=None, renderer_context=None): + # disable yaml advanced feature 'alias' for clean, portable, and readable output + class Dumper(yaml.Dumper): + def ignore_aliases(self, data): + return True + return yaml.dump(data, default_flow_style=False, sort_keys=False, Dumper=Dumper).encode('utf-8') + + +class JSONOpenAPIRenderer(BaseRenderer): + media_type = 'application/vnd.oai.openapi+json' + charset = None + encoder_class = encoders.JSONEncoder + format = 'openapi-json' + ensure_ascii = not api_settings.UNICODE_JSON + + def render(self, data, media_type=None, renderer_context=None): + return json.dumps( + data, cls=self.encoder_class, indent=2, + ensure_ascii=self.ensure_ascii).encode('utf-8') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/request.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/request.py new file mode 100644 index 0000000000000000000000000000000000000000..93634e667d498be269b065b3a25ee698d63dac43 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/request.py @@ -0,0 +1,455 @@ +""" +The Request class is used as a wrapper around the standard request object. + +The wrapped request then offers a richer API, in particular : + + - content automatically parsed according to `Content-Type` header, + and available as `request.data` + - full support of PUT method, including support for file uploads + - form overloading of HTTP method, content type and content +""" +import io +import sys +from contextlib import contextmanager + +from django.conf import settings +from django.http import HttpRequest, QueryDict +from django.http.request import RawPostDataException +from django.utils.datastructures import MultiValueDict + +from rest_framework import exceptions +from rest_framework.compat import parse_header_parameters +from rest_framework.settings import api_settings + + +def is_form_media_type(media_type): + """ + Return True if the media type is a valid form media type. + """ + base_media_type, params = parse_header_parameters(media_type) + return (base_media_type == 'application/x-www-form-urlencoded' or + base_media_type == 'multipart/form-data') + + +class override_method: + """ + A context manager that temporarily overrides the method on a request, + additionally setting the `view.request` attribute. + + Usage: + + with override_method(view, request, 'POST') as request: + ... # Do stuff with `view` and `request` + """ + + def __init__(self, view, request, method): + self.view = view + self.request = request + self.method = method + self.action = getattr(view, 'action', None) + + def __enter__(self): + self.view.request = clone_request(self.request, self.method) + # For viewsets we also set the `.action` attribute. + action_map = getattr(self.view, 'action_map', {}) + self.view.action = action_map.get(self.method.lower()) + return self.view.request + + def __exit__(self, *args, **kwarg): + self.view.request = self.request + self.view.action = self.action + + +class WrappedAttributeError(Exception): + pass + + +@contextmanager +def wrap_attributeerrors(): + """ + Used to re-raise AttributeErrors caught during authentication, preventing + these errors from otherwise being handled by the attribute access protocol. + """ + try: + yield + except AttributeError: + info = sys.exc_info() + exc = WrappedAttributeError(str(info[1])) + raise exc.with_traceback(info[2]) + + +class Empty: + """ + Placeholder for unset attributes. + Cannot use `None`, as that may be a valid value. + """ + pass + + +def _hasattr(obj, name): + return not getattr(obj, name) is Empty + + +def clone_request(request, method): + """ + Internal helper method to clone a request, replacing with a different + HTTP method. Used for checking permissions against other methods. + """ + ret = Request(request=request._request, + parsers=request.parsers, + authenticators=request.authenticators, + negotiator=request.negotiator, + parser_context=request.parser_context) + ret._data = request._data + ret._files = request._files + ret._full_data = request._full_data + ret._content_type = request._content_type + ret._stream = request._stream + ret.method = method + if hasattr(request, '_user'): + ret._user = request._user + if hasattr(request, '_auth'): + ret._auth = request._auth + if hasattr(request, '_authenticator'): + ret._authenticator = request._authenticator + if hasattr(request, 'accepted_renderer'): + ret.accepted_renderer = request.accepted_renderer + if hasattr(request, 'accepted_media_type'): + ret.accepted_media_type = request.accepted_media_type + if hasattr(request, 'version'): + ret.version = request.version + if hasattr(request, 'versioning_scheme'): + ret.versioning_scheme = request.versioning_scheme + return ret + + +class ForcedAuthentication: + """ + This authentication class is used if the test client or request factory + forcibly authenticated the request. + """ + + def __init__(self, force_user, force_token): + self.force_user = force_user + self.force_token = force_token + + def authenticate(self, request): + return (self.force_user, self.force_token) + + +class Request: + """ + Wrapper allowing to enhance a standard `HttpRequest` instance. + + Kwargs: + - request(HttpRequest). The original request instance. + - parsers(list/tuple). The parsers to use for parsing the + request content. + - authenticators(list/tuple). The authenticators used to try + authenticating the request's user. + """ + + def __init__(self, request, parsers=None, authenticators=None, + negotiator=None, parser_context=None): + assert isinstance(request, HttpRequest), ( + 'The `request` argument must be an instance of ' + '`django.http.HttpRequest`, not `{}.{}`.' + .format(request.__class__.__module__, request.__class__.__name__) + ) + + self._request = request + self.parsers = parsers or () + self.authenticators = authenticators or () + self.negotiator = negotiator or self._default_negotiator() + self.parser_context = parser_context + self._data = Empty + self._files = Empty + self._full_data = Empty + self._content_type = Empty + self._stream = Empty + + if self.parser_context is None: + self.parser_context = {} + self.parser_context['request'] = self + self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET + + force_user = getattr(request, '_force_auth_user', None) + force_token = getattr(request, '_force_auth_token', None) + if force_user is not None or force_token is not None: + forced_auth = ForcedAuthentication(force_user, force_token) + self.authenticators = (forced_auth,) + + def __repr__(self): + return '<%s.%s: %s %r>' % ( + self.__class__.__module__, + self.__class__.__name__, + self.method, + self.get_full_path()) + + def _default_negotiator(self): + return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS() + + @property + def content_type(self): + meta = self._request.META + return meta.get('CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', '')) + + @property + def stream(self): + """ + Returns an object that may be used to stream the request content. + """ + if not _hasattr(self, '_stream'): + self._load_stream() + return self._stream + + @property + def query_params(self): + """ + More semantically correct name for request.GET. + """ + return self._request.GET + + @property + def data(self): + if not _hasattr(self, '_full_data'): + self._load_data_and_files() + return self._full_data + + @property + def user(self): + """ + Returns the user associated with the current request, as authenticated + by the authentication classes provided to the request. + """ + if not hasattr(self, '_user'): + with wrap_attributeerrors(): + self._authenticate() + return self._user + + @user.setter + def user(self, value): + """ + Sets the user on the current request. This is necessary to maintain + compatibility with django.contrib.auth where the user property is + set in the login and logout functions. + + Note that we also set the user on Django's underlying `HttpRequest` + instance, ensuring that it is available to any middleware in the stack. + """ + self._user = value + self._request.user = value + + @property + def auth(self): + """ + Returns any non-user authentication information associated with the + request, such as an authentication token. + """ + if not hasattr(self, '_auth'): + with wrap_attributeerrors(): + self._authenticate() + return self._auth + + @auth.setter + def auth(self, value): + """ + Sets any non-user authentication information associated with the + request, such as an authentication token. + """ + self._auth = value + self._request.auth = value + + @property + def successful_authenticator(self): + """ + Return the instance of the authentication instance class that was used + to authenticate the request, or `None`. + """ + if not hasattr(self, '_authenticator'): + with wrap_attributeerrors(): + self._authenticate() + return self._authenticator + + def _load_data_and_files(self): + """ + Parses the request content into `self.data`. + """ + if not _hasattr(self, '_data'): + self._data, self._files = self._parse() + if self._files: + self._full_data = self._data.copy() + self._full_data.update(self._files) + else: + self._full_data = self._data + + # if a form media type, copy data & files refs to the underlying + # http request so that closable objects are handled appropriately. + if is_form_media_type(self.content_type): + self._request._post = self.POST + self._request._files = self.FILES + + def _load_stream(self): + """ + Return the content body of the request, as a stream. + """ + meta = self._request.META + try: + content_length = int( + meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0)) + ) + except (ValueError, TypeError): + content_length = 0 + + if content_length == 0: + self._stream = None + elif not self._request._read_started: + self._stream = self._request + else: + self._stream = io.BytesIO(self.body) + + def _supports_form_parsing(self): + """ + Return True if this requests supports parsing form data. + """ + form_media = ( + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ) + return any(parser.media_type in form_media for parser in self.parsers) + + def _parse(self): + """ + Parse the request content, returning a two-tuple of (data, files) + + May raise an `UnsupportedMediaType`, or `ParseError` exception. + """ + media_type = self.content_type + try: + stream = self.stream + except RawPostDataException: + if not hasattr(self._request, '_post'): + raise + # If request.POST has been accessed in middleware, and a method='POST' + # request was made with 'multipart/form-data', then the request stream + # will already have been exhausted. + if self._supports_form_parsing(): + return (self._request.POST, self._request.FILES) + stream = None + + if stream is None or media_type is None: + if media_type and is_form_media_type(media_type): + empty_data = QueryDict('', encoding=self._request._encoding) + else: + empty_data = {} + empty_files = MultiValueDict() + return (empty_data, empty_files) + + parser = self.negotiator.select_parser(self, self.parsers) + + if not parser: + raise exceptions.UnsupportedMediaType(media_type) + + try: + parsed = parser.parse(stream, media_type, self.parser_context) + except Exception: + # If we get an exception during parsing, fill in empty data and + # re-raise. Ensures we don't simply repeat the error when + # attempting to render the browsable renderer response, or when + # logging the request or similar. + self._data = QueryDict('', encoding=self._request._encoding) + self._files = MultiValueDict() + self._full_data = self._data + raise + + # Parser classes may return the raw data, or a + # DataAndFiles object. Unpack the result as required. + try: + return (parsed.data, parsed.files) + except AttributeError: + empty_files = MultiValueDict() + return (parsed, empty_files) + + def _authenticate(self): + """ + Attempt to authenticate the request using each authentication instance + in turn. + """ + for authenticator in self.authenticators: + try: + user_auth_tuple = authenticator.authenticate(self) + except exceptions.APIException: + self._not_authenticated() + raise + + if user_auth_tuple is not None: + self._authenticator = authenticator + self.user, self.auth = user_auth_tuple + return + + self._not_authenticated() + + def _not_authenticated(self): + """ + Set authenticator, user & authtoken representing an unauthenticated request. + + Defaults are None, AnonymousUser & None. + """ + self._authenticator = None + + if api_settings.UNAUTHENTICATED_USER: + self.user = api_settings.UNAUTHENTICATED_USER() + else: + self.user = None + + if api_settings.UNAUTHENTICATED_TOKEN: + self.auth = api_settings.UNAUTHENTICATED_TOKEN() + else: + self.auth = None + + def __getattr__(self, attr): + """ + If an attribute does not exist on this instance, then we also attempt + to proxy it to the underlying HttpRequest object. + """ + try: + return getattr(self._request, attr) + except AttributeError: + return self.__getattribute__(attr) + + @property + def DATA(self): + raise NotImplementedError( + '`request.DATA` has been deprecated in favor of `request.data` ' + 'since version 3.0, and has been fully removed as of version 3.2.' + ) + + @property + def POST(self): + # Ensure that request.POST uses our request parsing. + if not _hasattr(self, '_data'): + self._load_data_and_files() + if is_form_media_type(self.content_type): + return self._data + return QueryDict('', encoding=self._request._encoding) + + @property + def FILES(self): + # Leave this one alone for backwards compat with Django's request.FILES + # Different from the other two cases, which are not valid property + # names on the WSGIRequest class. + if not _hasattr(self, '_files'): + self._load_data_and_files() + return self._files + + @property + def QUERY_PARAMS(self): + raise NotImplementedError( + '`request.QUERY_PARAMS` has been deprecated in favor of `request.query_params` ' + 'since version 3.0, and has been fully removed as of version 3.2.' + ) + + def force_plaintext_errors(self, value): + # Hack to allow our exception handler to force choice of + # plaintext or html error responses. + self._request.is_ajax = lambda: value diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/response.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/response.py new file mode 100644 index 0000000000000000000000000000000000000000..495423734781b4da55367311b8103bf2291d2ba0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/response.py @@ -0,0 +1,103 @@ +""" +The Response class in REST framework is similar to HTTPResponse, except that +it is initialized with unrendered data, instead of a pre-rendered string. + +The appropriate renderer is called during Django's template response rendering. +""" +from http.client import responses + +from django.template.response import SimpleTemplateResponse + +from rest_framework.serializers import Serializer + + +class Response(SimpleTemplateResponse): + """ + An HttpResponse that allows its data to be rendered into + arbitrary media types. + """ + + def __init__(self, data=None, status=None, + template_name=None, headers=None, + exception=False, content_type=None): + """ + Alters the init arguments slightly. + For example, drop 'template_name', and instead use 'data'. + + Setting 'renderer' and 'media_type' will typically be deferred, + For example being set automatically by the `APIView`. + """ + super().__init__(None, status=status) + + if isinstance(data, Serializer): + msg = ( + 'You passed a Serializer instance as data, but ' + 'probably meant to pass serialized `.data` or ' + '`.error`. representation.' + ) + raise AssertionError(msg) + + self.data = data + self.template_name = template_name + self.exception = exception + self.content_type = content_type + + if headers: + for name, value in headers.items(): + self[name] = value + + @property + def rendered_content(self): + renderer = getattr(self, 'accepted_renderer', None) + accepted_media_type = getattr(self, 'accepted_media_type', None) + context = getattr(self, 'renderer_context', None) + + assert renderer, ".accepted_renderer not set on Response" + assert accepted_media_type, ".accepted_media_type not set on Response" + assert context is not None, ".renderer_context not set on Response" + context['response'] = self + + media_type = renderer.media_type + charset = renderer.charset + content_type = self.content_type + + if content_type is None and charset is not None: + content_type = "{}; charset={}".format(media_type, charset) + elif content_type is None: + content_type = media_type + self['Content-Type'] = content_type + + ret = renderer.render(self.data, accepted_media_type, context) + if isinstance(ret, str): + assert charset, ( + 'renderer returned unicode, and did not specify ' + 'a charset value.' + ) + return ret.encode(charset) + + if not ret: + del self['Content-Type'] + + return ret + + @property + def status_text(self): + """ + Returns reason text corresponding to our HTTP response status code. + Provided for convenience. + """ + return responses.get(self.status_code, '') + + def __getstate__(self): + """ + Remove attributes from the response that shouldn't be cached. + """ + state = super().__getstate__() + for key in ( + 'accepted_renderer', 'renderer_context', 'resolver_match', + 'client', 'request', 'json', 'wsgi_request' + ): + if key in state: + del state[key] + state['_closable_objects'] = [] + return state diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/reverse.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/reverse.py new file mode 100644 index 0000000000000000000000000000000000000000..55bf74af182da773c0e3944aefa6bc4d9bf6ace4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/reverse.py @@ -0,0 +1,66 @@ +""" +Provide urlresolver functions that return fully qualified URLs or view names +""" +from django.urls import NoReverseMatch +from django.urls import reverse as django_reverse +from django.utils.functional import lazy + +from rest_framework.settings import api_settings +from rest_framework.utils.urls import replace_query_param + + +def preserve_builtin_query_params(url, request=None): + """ + Given an incoming request, and an outgoing URL representation, + append the value of any built-in query parameters. + """ + if request is None: + return url + + overrides = [ + api_settings.URL_FORMAT_OVERRIDE, + ] + + for param in overrides: + if param and (param in request.GET): + value = request.GET[param] + url = replace_query_param(url, param, value) + + return url + + +def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra): + """ + If versioning is being used then we pass any `reverse` calls through + to the versioning scheme instance, so that the resulting URL + can be modified if needed. + """ + scheme = getattr(request, 'versioning_scheme', None) + if scheme is not None: + try: + url = scheme.reverse(viewname, args, kwargs, request, format, **extra) + except NoReverseMatch: + # In case the versioning scheme reversal fails, fallback to the + # default implementation + url = _reverse(viewname, args, kwargs, request, format, **extra) + else: + url = _reverse(viewname, args, kwargs, request, format, **extra) + + return preserve_builtin_query_params(url, request) + + +def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra): + """ + Same as `django.urls.reverse`, but optionally takes a request + and returns a fully qualified URL, using the request to get the base URL. + """ + if format is not None: + kwargs = kwargs or {} + kwargs['format'] = format + url = django_reverse(viewname, args=args, kwargs=kwargs, **extra) + if request: + return request.build_absolute_uri(url) + return url + + +reverse_lazy = lazy(reverse, str) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/routers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/routers.py new file mode 100644 index 0000000000000000000000000000000000000000..e0ae24b95c93bcfb270f932114930c9072688922 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/routers.py @@ -0,0 +1,348 @@ +""" +Routers provide a convenient and consistent way of automatically +determining the URL conf for your API. + +They are used by simply instantiating a Router class, and then registering +all the required ViewSets with that router. + +For example, you might have a `urls.py` that looks something like this: + + router = routers.DefaultRouter() + router.register('users', UserViewSet, 'user') + router.register('accounts', AccountViewSet, 'account') + + urlpatterns = router.urls +""" +import itertools +from collections import OrderedDict, namedtuple + +from django.core.exceptions import ImproperlyConfigured +from django.urls import NoReverseMatch, re_path + +from rest_framework import views +from rest_framework.response import Response +from rest_framework.reverse import reverse +from rest_framework.schemas import SchemaGenerator +from rest_framework.schemas.views import SchemaView +from rest_framework.settings import api_settings +from rest_framework.urlpatterns import format_suffix_patterns + +Route = namedtuple('Route', ['url', 'mapping', 'name', 'detail', 'initkwargs']) +DynamicRoute = namedtuple('DynamicRoute', ['url', 'name', 'detail', 'initkwargs']) + + +def escape_curly_brackets(url_path): + """ + Double brackets in regex of url_path for escape string formatting + """ + return url_path.replace('{', '{{').replace('}', '}}') + + +def flatten(list_of_lists): + """ + Takes an iterable of iterables, returns a single iterable containing all items + """ + return itertools.chain(*list_of_lists) + + +class BaseRouter: + def __init__(self): + self.registry = [] + + def register(self, prefix, viewset, basename=None): + if basename is None: + basename = self.get_default_basename(viewset) + self.registry.append((prefix, viewset, basename)) + + # invalidate the urls cache + if hasattr(self, '_urls'): + del self._urls + + def get_default_basename(self, viewset): + """ + If `basename` is not specified, attempt to automatically determine + it from the viewset. + """ + raise NotImplementedError('get_default_basename must be overridden') + + def get_urls(self): + """ + Return a list of URL patterns, given the registered viewsets. + """ + raise NotImplementedError('get_urls must be overridden') + + @property + def urls(self): + if not hasattr(self, '_urls'): + self._urls = self.get_urls() + return self._urls + + +class SimpleRouter(BaseRouter): + + routes = [ + # List route. + Route( + url=r'^{prefix}{trailing_slash}$', + mapping={ + 'get': 'list', + 'post': 'create' + }, + name='{basename}-list', + detail=False, + initkwargs={'suffix': 'List'} + ), + # Dynamically generated list routes. Generated using + # @action(detail=False) decorator on methods of the viewset. + DynamicRoute( + url=r'^{prefix}/{url_path}{trailing_slash}$', + name='{basename}-{url_name}', + detail=False, + initkwargs={} + ), + # Detail route. + Route( + url=r'^{prefix}/{lookup}{trailing_slash}$', + mapping={ + 'get': 'retrieve', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy' + }, + name='{basename}-detail', + detail=True, + initkwargs={'suffix': 'Instance'} + ), + # Dynamically generated detail routes. Generated using + # @action(detail=True) decorator on methods of the viewset. + DynamicRoute( + url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', + name='{basename}-{url_name}', + detail=True, + initkwargs={} + ), + ] + + def __init__(self, trailing_slash=True): + self.trailing_slash = '/' if trailing_slash else '' + super().__init__() + + def get_default_basename(self, viewset): + """ + If `basename` is not specified, attempt to automatically determine + it from the viewset. + """ + queryset = getattr(viewset, 'queryset', None) + + assert queryset is not None, '`basename` argument not specified, and could ' \ + 'not automatically determine the name from the viewset, as ' \ + 'it does not have a `.queryset` attribute.' + + return queryset.model._meta.object_name.lower() + + def get_routes(self, viewset): + """ + Augment `self.routes` with any dynamically generated routes. + + Returns a list of the Route namedtuple. + """ + # converting to list as iterables are good for one pass, known host needs to be checked again and again for + # different functions. + known_actions = list(flatten([route.mapping.values() for route in self.routes if isinstance(route, Route)])) + extra_actions = viewset.get_extra_actions() + + # checking action names against the known actions list + not_allowed = [ + action.__name__ for action in extra_actions + if action.__name__ in known_actions + ] + if not_allowed: + msg = ('Cannot use the @action decorator on the following ' + 'methods, as they are existing routes: %s') + raise ImproperlyConfigured(msg % ', '.join(not_allowed)) + + # partition detail and list actions + detail_actions = [action for action in extra_actions if action.detail] + list_actions = [action for action in extra_actions if not action.detail] + + routes = [] + for route in self.routes: + if isinstance(route, DynamicRoute) and route.detail: + routes += [self._get_dynamic_route(route, action) for action in detail_actions] + elif isinstance(route, DynamicRoute) and not route.detail: + routes += [self._get_dynamic_route(route, action) for action in list_actions] + else: + routes.append(route) + + return routes + + def _get_dynamic_route(self, route, action): + initkwargs = route.initkwargs.copy() + initkwargs.update(action.kwargs) + + url_path = escape_curly_brackets(action.url_path) + + return Route( + url=route.url.replace('{url_path}', url_path), + mapping=action.mapping, + name=route.name.replace('{url_name}', action.url_name), + detail=route.detail, + initkwargs=initkwargs, + ) + + def get_method_map(self, viewset, method_map): + """ + Given a viewset, and a mapping of http methods to actions, + return a new mapping which only includes any mappings that + are actually implemented by the viewset. + """ + bound_methods = {} + for method, action in method_map.items(): + if hasattr(viewset, action): + bound_methods[method] = action + return bound_methods + + def get_lookup_regex(self, viewset, lookup_prefix=''): + """ + Given a viewset, return the portion of URL regex that is used + to match against a single instance. + + Note that lookup_prefix is not used directly inside REST rest_framework + itself, but is required in order to nicely support nested router + implementations, such as drf-nested-routers. + + https://github.com/alanjds/drf-nested-routers + """ + base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})' + # Use `pk` as default field, unset set. Default regex should not + # consume `.json` style suffixes and should break at '/' boundaries. + lookup_field = getattr(viewset, 'lookup_field', 'pk') + lookup_url_kwarg = getattr(viewset, 'lookup_url_kwarg', None) or lookup_field + lookup_value = getattr(viewset, 'lookup_value_regex', '[^/.]+') + return base_regex.format( + lookup_prefix=lookup_prefix, + lookup_url_kwarg=lookup_url_kwarg, + lookup_value=lookup_value + ) + + def get_urls(self): + """ + Use the registered viewsets to generate a list of URL patterns. + """ + ret = [] + + for prefix, viewset, basename in self.registry: + lookup = self.get_lookup_regex(viewset) + routes = self.get_routes(viewset) + + for route in routes: + + # Only actions which actually exist on the viewset will be bound + mapping = self.get_method_map(viewset, route.mapping) + if not mapping: + continue + + # Build the url pattern + regex = route.url.format( + prefix=prefix, + lookup=lookup, + trailing_slash=self.trailing_slash + ) + + # If there is no prefix, the first part of the url is probably + # controlled by project's urls.py and the router is in an app, + # so a slash in the beginning will (A) cause Django to give + # warnings and (B) generate URLS that will require using '//'. + if not prefix and regex[:2] == '^/': + regex = '^' + regex[2:] + + initkwargs = route.initkwargs.copy() + initkwargs.update({ + 'basename': basename, + 'detail': route.detail, + }) + + view = viewset.as_view(mapping, **initkwargs) + name = route.name.format(basename=basename) + ret.append(re_path(regex, view, name=name)) + + return ret + + +class APIRootView(views.APIView): + """ + The default basic root view for DefaultRouter + """ + _ignore_model_permissions = True + schema = None # exclude from schema + api_root_dict = None + + def get(self, request, *args, **kwargs): + # Return a plain {"name": "hyperlink"} response. + ret = OrderedDict() + namespace = request.resolver_match.namespace + for key, url_name in self.api_root_dict.items(): + if namespace: + url_name = namespace + ':' + url_name + try: + ret[key] = reverse( + url_name, + args=args, + kwargs=kwargs, + request=request, + format=kwargs.get('format') + ) + except NoReverseMatch: + # Don't bail out if eg. no list routes exist, only detail routes. + continue + + return Response(ret) + + +class DefaultRouter(SimpleRouter): + """ + The default router extends the SimpleRouter, but also adds in a default + API root view, and adds format suffix patterns to the URLs. + """ + include_root_view = True + include_format_suffixes = True + root_view_name = 'api-root' + default_schema_renderers = None + APIRootView = APIRootView + APISchemaView = SchemaView + SchemaGenerator = SchemaGenerator + + def __init__(self, *args, **kwargs): + if 'root_renderers' in kwargs: + self.root_renderers = kwargs.pop('root_renderers') + else: + self.root_renderers = list(api_settings.DEFAULT_RENDERER_CLASSES) + super().__init__(*args, **kwargs) + + def get_api_root_view(self, api_urls=None): + """ + Return a basic root view. + """ + api_root_dict = OrderedDict() + list_name = self.routes[0].name + for prefix, viewset, basename in self.registry: + api_root_dict[prefix] = list_name.format(basename=basename) + + return self.APIRootView.as_view(api_root_dict=api_root_dict) + + def get_urls(self): + """ + Generate the list of URL patterns, including a default root view + for the API, and appending `.json` style format suffixes. + """ + urls = super().get_urls() + + if self.include_root_view: + view = self.get_api_root_view(api_urls=urls) + root_url = re_path(r'^$', view, name=self.root_view_name) + urls.append(root_url) + + if self.include_format_suffixes: + urls = format_suffix_patterns(urls) + + return urls diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b63cb23536057cbac6f60e6a6bebb3d70c6884db --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__init__.py @@ -0,0 +1,58 @@ +""" +rest_framework.schemas + +schemas: + __init__.py + generators.py # Top-down schema generation + inspectors.py # Per-endpoint view introspection + utils.py # Shared helper functions + views.py # Houses `SchemaView`, `APIView` subclass. + +We expose a minimal "public" API directly from `schemas`. This covers the +basic use-cases: + + from rest_framework.schemas import ( + AutoSchema, + ManualSchema, + get_schema_view, + SchemaGenerator, + ) + +Other access should target the submodules directly +""" +from rest_framework.settings import api_settings + +from . import coreapi, openapi +from .coreapi import AutoSchema, ManualSchema, SchemaGenerator # noqa +from .inspectors import DefaultSchema # noqa + + +def get_schema_view( + title=None, url=None, description=None, urlconf=None, renderer_classes=None, + public=False, patterns=None, generator_class=None, + authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES, + permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES, + version=None): + """ + Return a schema view. + """ + if generator_class is None: + if coreapi.is_enabled(): + generator_class = coreapi.SchemaGenerator + else: + generator_class = openapi.SchemaGenerator + + generator = generator_class( + title=title, url=url, description=description, + urlconf=urlconf, patterns=patterns, version=version + ) + + # Avoid import cycle on APIView + from .views import SchemaView + return SchemaView.as_view( + renderer_classes=renderer_classes, + schema_generator=generator, + public=public, + authentication_classes=authentication_classes, + permission_classes=permission_classes, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..892e41db51a095ff1d31c1ce075f7a06232abd39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/coreapi.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/coreapi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ba9498b5852d2f17aecb4cf96d8db197d5f75ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/coreapi.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/generators.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/generators.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cdf83f39df1dc0cb0e1c7762fb49f3b4385feb4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/generators.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/inspectors.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/inspectors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..385a9e62242dea178e153fc0d30375923fe3e030 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/inspectors.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/openapi.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/openapi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d5078ed4ad38638e7d72833269298cbc926a8e2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/openapi.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5fc42a95579c3561c1c04d33d5ab2529e48b1c2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..736f5a70efb62812e7218294143185f4bb64eb22 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/coreapi.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/coreapi.py new file mode 100644 index 0000000000000000000000000000000000000000..908518e9d759b963f591025200d9ec816d2e6008 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/coreapi.py @@ -0,0 +1,616 @@ +import warnings +from collections import Counter, OrderedDict +from urllib import parse + +from django.db import models +from django.utils.encoding import force_str + +from rest_framework import exceptions, serializers +from rest_framework.compat import coreapi, coreschema, uritemplate +from rest_framework.settings import api_settings + +from .generators import BaseSchemaGenerator +from .inspectors import ViewInspector +from .utils import get_pk_description, is_list_view + + +def common_path(paths): + split_paths = [path.strip('/').split('/') for path in paths] + s1 = min(split_paths) + s2 = max(split_paths) + common = s1 + for i, c in enumerate(s1): + if c != s2[i]: + common = s1[:i] + break + return '/' + '/'.join(common) + + +def is_custom_action(action): + return action not in { + 'retrieve', 'list', 'create', 'update', 'partial_update', 'destroy' + } + + +def distribute_links(obj): + for key, value in obj.items(): + distribute_links(value) + + for preferred_key, link in obj.links: + key = obj.get_available_key(preferred_key) + obj[key] = link + + +INSERT_INTO_COLLISION_FMT = """ +Schema Naming Collision. + +coreapi.Link for URL path {value_url} cannot be inserted into schema. +Position conflicts with coreapi.Link for URL path {target_url}. + +Attempted to insert link with keys: {keys}. + +Adjust URLs to avoid naming collision or override `SchemaGenerator.get_keys()` +to customise schema structure. +""" + + +class LinkNode(OrderedDict): + def __init__(self): + self.links = [] + self.methods_counter = Counter() + super().__init__() + + def get_available_key(self, preferred_key): + if preferred_key not in self: + return preferred_key + + while True: + current_val = self.methods_counter[preferred_key] + self.methods_counter[preferred_key] += 1 + + key = '{}_{}'.format(preferred_key, current_val) + if key not in self: + return key + + +def insert_into(target, keys, value): + """ + Nested dictionary insertion. + + >>> example = {} + >>> insert_into(example, ['a', 'b', 'c'], 123) + >>> example + LinkNode({'a': LinkNode({'b': LinkNode({'c': LinkNode(links=[123])}}}))) + """ + for key in keys[:-1]: + if key not in target: + target[key] = LinkNode() + target = target[key] + + try: + target.links.append((keys[-1], value)) + except TypeError: + msg = INSERT_INTO_COLLISION_FMT.format( + value_url=value.url, + target_url=target.url, + keys=keys + ) + raise ValueError(msg) + + +class SchemaGenerator(BaseSchemaGenerator): + """ + Original CoreAPI version. + """ + # Map HTTP methods onto actions. + default_mapping = { + 'get': 'retrieve', + 'post': 'create', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy', + } + + # Map the method names we use for viewset actions onto external schema names. + # These give us names that are more suitable for the external representation. + # Set by 'SCHEMA_COERCE_METHOD_NAMES'. + coerce_method_names = None + + def __init__(self, title=None, url=None, description=None, patterns=None, urlconf=None, version=None): + assert coreapi, '`coreapi` must be installed for schema support.' + assert coreschema, '`coreschema` must be installed for schema support.' + + super().__init__(title, url, description, patterns, urlconf) + self.coerce_method_names = api_settings.SCHEMA_COERCE_METHOD_NAMES + + def get_links(self, request=None): + """ + Return a dictionary containing all the links that should be + included in the API schema. + """ + links = LinkNode() + + paths, view_endpoints = self._get_paths_and_endpoints(request) + + # Only generate the path prefix for paths that will be included + if not paths: + return None + prefix = self.determine_path_prefix(paths) + + for path, method, view in view_endpoints: + if not self.has_view_permissions(path, method, view): + continue + link = view.schema.get_link(path, method, base_url=self.url) + subpath = path[len(prefix):] + keys = self.get_keys(subpath, method, view) + insert_into(links, keys, link) + + return links + + def get_schema(self, request=None, public=False): + """ + Generate a `coreapi.Document` representing the API schema. + """ + self._initialise_endpoints() + + links = self.get_links(None if public else request) + if not links: + return None + + url = self.url + if not url and request is not None: + url = request.build_absolute_uri() + + distribute_links(links) + return coreapi.Document( + title=self.title, description=self.description, + url=url, content=links + ) + + # Method for generating the link layout.... + def get_keys(self, subpath, method, view): + """ + Return a list of keys that should be used to layout a link within + the schema document. + + /users/ ("users", "list"), ("users", "create") + /users/{pk}/ ("users", "read"), ("users", "update"), ("users", "delete") + /users/enabled/ ("users", "enabled") # custom viewset list action + /users/{pk}/star/ ("users", "star") # custom viewset detail action + /users/{pk}/groups/ ("users", "groups", "list"), ("users", "groups", "create") + /users/{pk}/groups/{pk}/ ("users", "groups", "read"), ("users", "groups", "update"), ("users", "groups", "delete") + """ + if hasattr(view, 'action'): + # Viewsets have explicitly named actions. + action = view.action + else: + # Views have no associated action, so we determine one from the method. + if is_list_view(subpath, method, view): + action = 'list' + else: + action = self.default_mapping[method.lower()] + + named_path_components = [ + component for component + in subpath.strip('/').split('/') + if '{' not in component + ] + + if is_custom_action(action): + # Custom action, eg "/users/{pk}/activate/", "/users/active/" + mapped_methods = { + # Don't count head mapping, e.g. not part of the schema + method for method in view.action_map if method != 'head' + } + if len(mapped_methods) > 1: + action = self.default_mapping[method.lower()] + if action in self.coerce_method_names: + action = self.coerce_method_names[action] + return named_path_components + [action] + else: + return named_path_components[:-1] + [action] + + if action in self.coerce_method_names: + action = self.coerce_method_names[action] + + # Default action, eg "/users/", "/users/{pk}/" + return named_path_components + [action] + + def determine_path_prefix(self, paths): + """ + Given a list of all paths, return the common prefix which should be + discounted when generating a schema structure. + + This will be the longest common string that does not include that last + component of the URL, or the last component before a path parameter. + + For example: + + /api/v1/users/ + /api/v1/users/{pk}/ + + The path prefix is '/api/v1' + """ + prefixes = [] + for path in paths: + components = path.strip('/').split('/') + initial_components = [] + for component in components: + if '{' in component: + break + initial_components.append(component) + prefix = '/'.join(initial_components[:-1]) + if not prefix: + # We can just break early in the case that there's at least + # one URL that doesn't have a path prefix. + return '/' + prefixes.append('/' + prefix + '/') + return common_path(prefixes) + +# View Inspectors # + + +def field_to_schema(field): + title = force_str(field.label) if field.label else '' + description = force_str(field.help_text) if field.help_text else '' + + if isinstance(field, (serializers.ListSerializer, serializers.ListField)): + child_schema = field_to_schema(field.child) + return coreschema.Array( + items=child_schema, + title=title, + description=description + ) + elif isinstance(field, serializers.DictField): + return coreschema.Object( + title=title, + description=description + ) + elif isinstance(field, serializers.Serializer): + return coreschema.Object( + properties=OrderedDict([ + (key, field_to_schema(value)) + for key, value + in field.fields.items() + ]), + title=title, + description=description + ) + elif isinstance(field, serializers.ManyRelatedField): + related_field_schema = field_to_schema(field.child_relation) + + return coreschema.Array( + items=related_field_schema, + title=title, + description=description + ) + elif isinstance(field, serializers.PrimaryKeyRelatedField): + schema_cls = coreschema.String + model = getattr(field.queryset, 'model', None) + if model is not None: + model_field = model._meta.pk + if isinstance(model_field, models.AutoField): + schema_cls = coreschema.Integer + return schema_cls(title=title, description=description) + elif isinstance(field, serializers.RelatedField): + return coreschema.String(title=title, description=description) + elif isinstance(field, serializers.MultipleChoiceField): + return coreschema.Array( + items=coreschema.Enum(enum=list(field.choices)), + title=title, + description=description + ) + elif isinstance(field, serializers.ChoiceField): + return coreschema.Enum( + enum=list(field.choices), + title=title, + description=description + ) + elif isinstance(field, serializers.BooleanField): + return coreschema.Boolean(title=title, description=description) + elif isinstance(field, (serializers.DecimalField, serializers.FloatField)): + return coreschema.Number(title=title, description=description) + elif isinstance(field, serializers.IntegerField): + return coreschema.Integer(title=title, description=description) + elif isinstance(field, serializers.DateField): + return coreschema.String( + title=title, + description=description, + format='date' + ) + elif isinstance(field, serializers.DateTimeField): + return coreschema.String( + title=title, + description=description, + format='date-time' + ) + elif isinstance(field, serializers.JSONField): + return coreschema.Object(title=title, description=description) + + if field.style.get('base_template') == 'textarea.html': + return coreschema.String( + title=title, + description=description, + format='textarea' + ) + + return coreschema.String(title=title, description=description) + + +class AutoSchema(ViewInspector): + """ + Default inspector for APIView + + Responsible for per-view introspection and schema generation. + """ + def __init__(self, manual_fields=None): + """ + Parameters: + + * `manual_fields`: list of `coreapi.Field` instances that + will be added to auto-generated fields, overwriting on `Field.name` + """ + super().__init__() + if manual_fields is None: + manual_fields = [] + self._manual_fields = manual_fields + + def get_link(self, path, method, base_url): + """ + Generate `coreapi.Link` for self.view, path and method. + + This is the main _public_ access point. + + Parameters: + + * path: Route path for view from URLConf. + * method: The HTTP request method. + * base_url: The project "mount point" as given to SchemaGenerator + """ + fields = self.get_path_fields(path, method) + fields += self.get_serializer_fields(path, method) + fields += self.get_pagination_fields(path, method) + fields += self.get_filter_fields(path, method) + + manual_fields = self.get_manual_fields(path, method) + fields = self.update_fields(fields, manual_fields) + + if fields and any([field.location in ('form', 'body') for field in fields]): + encoding = self.get_encoding(path, method) + else: + encoding = None + + description = self.get_description(path, method) + + if base_url and path.startswith('/'): + path = path[1:] + + return coreapi.Link( + url=parse.urljoin(base_url, path), + action=method.lower(), + encoding=encoding, + fields=fields, + description=description + ) + + def get_path_fields(self, path, method): + """ + Return a list of `coreapi.Field` instances corresponding to any + templated path variables. + """ + view = self.view + model = getattr(getattr(view, 'queryset', None), 'model', None) + fields = [] + + for variable in uritemplate.variables(path): + title = '' + description = '' + schema_cls = coreschema.String + kwargs = {} + if model is not None: + # Attempt to infer a field description if possible. + try: + model_field = model._meta.get_field(variable) + except Exception: + model_field = None + + if model_field is not None and model_field.verbose_name: + title = force_str(model_field.verbose_name) + + if model_field is not None and model_field.help_text: + description = force_str(model_field.help_text) + elif model_field is not None and model_field.primary_key: + description = get_pk_description(model, model_field) + + if hasattr(view, 'lookup_value_regex') and view.lookup_field == variable: + kwargs['pattern'] = view.lookup_value_regex + elif isinstance(model_field, models.AutoField): + schema_cls = coreschema.Integer + + field = coreapi.Field( + name=variable, + location='path', + required=True, + schema=schema_cls(title=title, description=description, **kwargs) + ) + fields.append(field) + + return fields + + def get_serializer_fields(self, path, method): + """ + Return a list of `coreapi.Field` instances corresponding to any + request body input, as determined by the serializer class. + """ + view = self.view + + if method not in ('PUT', 'PATCH', 'POST'): + return [] + + if not hasattr(view, 'get_serializer'): + return [] + + try: + serializer = view.get_serializer() + except exceptions.APIException: + serializer = None + warnings.warn('{}.get_serializer() raised an exception during ' + 'schema generation. Serializer fields will not be ' + 'generated for {} {}.' + .format(view.__class__.__name__, method, path)) + + if isinstance(serializer, serializers.ListSerializer): + return [ + coreapi.Field( + name='data', + location='body', + required=True, + schema=coreschema.Array() + ) + ] + + if not isinstance(serializer, serializers.Serializer): + return [] + + fields = [] + for field in serializer.fields.values(): + if field.read_only or isinstance(field, serializers.HiddenField): + continue + + required = field.required and method != 'PATCH' + field = coreapi.Field( + name=field.field_name, + location='form', + required=required, + schema=field_to_schema(field) + ) + fields.append(field) + + return fields + + def get_pagination_fields(self, path, method): + view = self.view + + if not is_list_view(path, method, view): + return [] + + pagination = getattr(view, 'pagination_class', None) + if not pagination: + return [] + + paginator = view.pagination_class() + return paginator.get_schema_fields(view) + + def _allows_filters(self, path, method): + """ + Determine whether to include filter Fields in schema. + + Default implementation looks for ModelViewSet or GenericAPIView + actions/methods that cause filtering on the default implementation. + + Override to adjust behaviour for your view. + + Note: Introduced in v3.7: Initially "private" (i.e. with leading underscore) + to allow changes based on user experience. + """ + if getattr(self.view, 'filter_backends', None) is None: + return False + + if hasattr(self.view, 'action'): + return self.view.action in ["list", "retrieve", "update", "partial_update", "destroy"] + + return method.lower() in ["get", "put", "patch", "delete"] + + def get_filter_fields(self, path, method): + if not self._allows_filters(path, method): + return [] + + fields = [] + for filter_backend in self.view.filter_backends: + fields += filter_backend().get_schema_fields(self.view) + return fields + + def get_manual_fields(self, path, method): + return self._manual_fields + + @staticmethod + def update_fields(fields, update_with): + """ + Update list of coreapi.Field instances, overwriting on `Field.name`. + + Utility function to handle replacing coreapi.Field fields + from a list by name. Used to handle `manual_fields`. + + Parameters: + + * `fields`: list of `coreapi.Field` instances to update + * `update_with: list of `coreapi.Field` instances to add or replace. + """ + if not update_with: + return fields + + by_name = OrderedDict((f.name, f) for f in fields) + for f in update_with: + by_name[f.name] = f + fields = list(by_name.values()) + return fields + + def get_encoding(self, path, method): + """ + Return the 'encoding' parameter to use for a given endpoint. + """ + view = self.view + + # Core API supports the following request encodings over HTTP... + supported_media_types = { + 'application/json', + 'application/x-www-form-urlencoded', + 'multipart/form-data', + } + parser_classes = getattr(view, 'parser_classes', []) + for parser_class in parser_classes: + media_type = getattr(parser_class, 'media_type', None) + if media_type in supported_media_types: + return media_type + # Raw binary uploads are supported with "application/octet-stream" + if media_type == '*/*': + return 'application/octet-stream' + + return None + + +class ManualSchema(ViewInspector): + """ + Allows providing a list of coreapi.Fields, + plus an optional description. + """ + def __init__(self, fields, description='', encoding=None): + """ + Parameters: + + * `fields`: list of `coreapi.Field` instances. + * `description`: String description for view. Optional. + """ + super().__init__() + assert all(isinstance(f, coreapi.Field) for f in fields), "`fields` must be a list of coreapi.Field instances" + self._fields = fields + self._description = description + self._encoding = encoding + + def get_link(self, path, method, base_url): + + if base_url and path.startswith('/'): + path = path[1:] + + return coreapi.Link( + url=parse.urljoin(base_url, path), + action=method.lower(), + encoding=self._encoding, + fields=self._fields, + description=self._description + ) + + +def is_enabled(): + """Is CoreAPI Mode enabled?""" + return issubclass(api_settings.DEFAULT_SCHEMA_CLASS, AutoSchema) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/generators.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/generators.py new file mode 100644 index 0000000000000000000000000000000000000000..d3c6446aa414577bb3cb88ab8c96a941dd9d5e34 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/generators.py @@ -0,0 +1,239 @@ +""" +generators.py # Top-down schema generation + +See schemas.__init__.py for package overview. +""" +import re +from importlib import import_module + +from django.conf import settings +from django.contrib.admindocs.views import simplify_regex +from django.core.exceptions import PermissionDenied +from django.http import Http404 +from django.urls import URLPattern, URLResolver + +from rest_framework import exceptions +from rest_framework.request import clone_request +from rest_framework.settings import api_settings +from rest_framework.utils.model_meta import _get_pk + + +def get_pk_name(model): + meta = model._meta.concrete_model._meta + return _get_pk(meta).name + + +def is_api_view(callback): + """ + Return `True` if the given view callback is a REST framework view/viewset. + """ + # Avoid import cycle on APIView + from rest_framework.views import APIView + cls = getattr(callback, 'cls', None) + return (cls is not None) and issubclass(cls, APIView) + + +def endpoint_ordering(endpoint): + path, method, callback = endpoint + method_priority = { + 'GET': 0, + 'POST': 1, + 'PUT': 2, + 'PATCH': 3, + 'DELETE': 4 + }.get(method, 5) + return (method_priority,) + + +_PATH_PARAMETER_COMPONENT_RE = re.compile( + r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>\w+)>' +) + + +class EndpointEnumerator: + """ + A class to determine the available API endpoints that a project exposes. + """ + def __init__(self, patterns=None, urlconf=None): + if patterns is None: + if urlconf is None: + # Use the default Django URL conf + urlconf = settings.ROOT_URLCONF + + # Load the given URLconf module + if isinstance(urlconf, str): + urls = import_module(urlconf) + else: + urls = urlconf + patterns = urls.urlpatterns + + self.patterns = patterns + + def get_api_endpoints(self, patterns=None, prefix=''): + """ + Return a list of all available API endpoints by inspecting the URL conf. + """ + if patterns is None: + patterns = self.patterns + + api_endpoints = [] + + for pattern in patterns: + path_regex = prefix + str(pattern.pattern) + if isinstance(pattern, URLPattern): + path = self.get_path_from_regex(path_regex) + callback = pattern.callback + if self.should_include_endpoint(path, callback): + for method in self.get_allowed_methods(callback): + endpoint = (path, method, callback) + api_endpoints.append(endpoint) + + elif isinstance(pattern, URLResolver): + nested_endpoints = self.get_api_endpoints( + patterns=pattern.url_patterns, + prefix=path_regex + ) + api_endpoints.extend(nested_endpoints) + + return sorted(api_endpoints, key=endpoint_ordering) + + def get_path_from_regex(self, path_regex): + """ + Given a URL conf regex, return a URI template string. + """ + # ???: Would it be feasible to adjust this such that we generate the + # path, plus the kwargs, plus the type from the convertor, such that we + # could feed that straight into the parameter schema object? + + path = simplify_regex(path_regex) + + # Strip Django 2.0 convertors as they are incompatible with uritemplate format + return re.sub(_PATH_PARAMETER_COMPONENT_RE, r'{\g<parameter>}', path) + + def should_include_endpoint(self, path, callback): + """ + Return `True` if the given endpoint should be included. + """ + if not is_api_view(callback): + return False # Ignore anything except REST framework views. + + if callback.cls.schema is None: + return False + + if 'schema' in callback.initkwargs: + if callback.initkwargs['schema'] is None: + return False + + if path.endswith('.{format}') or path.endswith('.{format}/'): + return False # Ignore .json style URLs. + + return True + + def get_allowed_methods(self, callback): + """ + Return a list of the valid HTTP methods for this endpoint. + """ + if hasattr(callback, 'actions'): + actions = set(callback.actions) + http_method_names = set(callback.cls.http_method_names) + methods = [method.upper() for method in actions & http_method_names] + else: + methods = callback.cls().allowed_methods + + return [method for method in methods if method not in ('OPTIONS', 'HEAD')] + + +class BaseSchemaGenerator: + endpoint_inspector_cls = EndpointEnumerator + + # 'pk' isn't great as an externally exposed name for an identifier, + # so by default we prefer to use the actual model field name for schemas. + # Set by 'SCHEMA_COERCE_PATH_PK'. + coerce_path_pk = None + + def __init__(self, title=None, url=None, description=None, patterns=None, urlconf=None, version=None): + if url and not url.endswith('/'): + url += '/' + + self.coerce_path_pk = api_settings.SCHEMA_COERCE_PATH_PK + + self.patterns = patterns + self.urlconf = urlconf + self.title = title + self.description = description + self.version = version + self.url = url + self.endpoints = None + + def _initialise_endpoints(self): + if self.endpoints is None: + inspector = self.endpoint_inspector_cls(self.patterns, self.urlconf) + self.endpoints = inspector.get_api_endpoints() + + def _get_paths_and_endpoints(self, request): + """ + Generate (path, method, view) given (path, method, callback) for paths. + """ + paths = [] + view_endpoints = [] + for path, method, callback in self.endpoints: + view = self.create_view(callback, method, request) + path = self.coerce_path(path, method, view) + paths.append(path) + view_endpoints.append((path, method, view)) + + return paths, view_endpoints + + def create_view(self, callback, method, request=None): + """ + Given a callback, return an actual view instance. + """ + view = callback.cls(**getattr(callback, 'initkwargs', {})) + view.args = () + view.kwargs = {} + view.format_kwarg = None + view.request = None + view.action_map = getattr(callback, 'actions', None) + + actions = getattr(callback, 'actions', None) + if actions is not None: + if method == 'OPTIONS': + view.action = 'metadata' + else: + view.action = actions.get(method.lower()) + + if request is not None: + view.request = clone_request(request, method) + + return view + + def coerce_path(self, path, method, view): + """ + Coerce {pk} path arguments into the name of the model field, + where possible. This is cleaner for an external representation. + (Ie. "this is an identifier", not "this is a database primary key") + """ + if not self.coerce_path_pk or '{pk}' not in path: + return path + model = getattr(getattr(view, 'queryset', None), 'model', None) + if model: + field_name = get_pk_name(model) + else: + field_name = 'id' + return path.replace('{pk}', '{%s}' % field_name) + + def get_schema(self, request=None, public=False): + raise NotImplementedError(".get_schema() must be implemented in subclasses.") + + def has_view_permissions(self, path, method, view): + """ + Return `True` if the incoming request has the correct view permissions. + """ + if view.request is None: + return True + + try: + view.check_permissions(view.request) + except (exceptions.APIException, Http404, PermissionDenied): + return False + return True diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/inspectors.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/inspectors.py new file mode 100644 index 0000000000000000000000000000000000000000..027472db14c35b7627ef64f6cfe566db038e5bdd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/inspectors.py @@ -0,0 +1,125 @@ +""" +inspectors.py # Per-endpoint view introspection + +See schemas.__init__.py for package overview. +""" +import re +from weakref import WeakKeyDictionary + +from django.utils.encoding import smart_str + +from rest_framework.settings import api_settings +from rest_framework.utils import formatting + + +class ViewInspector: + """ + Descriptor class on APIView. + + Provide subclass for per-view schema generation + """ + + # Used in _get_description_section() + header_regex = re.compile('^[a-zA-Z][0-9A-Za-z_]*:') + + def __init__(self): + self.instance_schemas = WeakKeyDictionary() + + def __get__(self, instance, owner): + """ + Enables `ViewInspector` as a Python _Descriptor_. + + This is how `view.schema` knows about `view`. + + `__get__` is called when the descriptor is accessed on the owner. + (That will be when view.schema is called in our case.) + + `owner` is always the owner class. (An APIView, or subclass for us.) + `instance` is the view instance or `None` if accessed from the class, + rather than an instance. + + See: https://docs.python.org/3/howto/descriptor.html for info on + descriptor usage. + """ + if instance in self.instance_schemas: + return self.instance_schemas[instance] + + self.view = instance + return self + + def __set__(self, instance, other): + self.instance_schemas[instance] = other + if other is not None: + other.view = instance + + @property + def view(self): + """View property.""" + assert self._view is not None, ( + "Schema generation REQUIRES a view instance. (Hint: you accessed " + "`schema` from the view class rather than an instance.)" + ) + return self._view + + @view.setter + def view(self, value): + self._view = value + + @view.deleter + def view(self): + self._view = None + + def get_description(self, path, method): + """ + Determine a path description. + + This will be based on the method docstring if one exists, + or else the class docstring. + """ + view = self.view + + method_name = getattr(view, 'action', method.lower()) + method_docstring = getattr(view, method_name, None).__doc__ + if method_docstring: + # An explicit docstring on the method or action. + return self._get_description_section(view, method.lower(), formatting.dedent(smart_str(method_docstring))) + else: + return self._get_description_section(view, getattr(view, 'action', method.lower()), + view.get_view_description()) + + def _get_description_section(self, view, header, description): + lines = [line for line in description.splitlines()] + current_section = '' + sections = {'': ''} + + for line in lines: + if self.header_regex.match(line): + current_section, separator, lead = line.partition(':') + sections[current_section] = lead.strip() + else: + sections[current_section] += '\n' + line + + # TODO: SCHEMA_COERCE_METHOD_NAMES appears here and in `SchemaGenerator.get_keys` + coerce_method_names = api_settings.SCHEMA_COERCE_METHOD_NAMES + if header in sections: + return sections[header].strip() + if header in coerce_method_names: + if coerce_method_names[header] in sections: + return sections[coerce_method_names[header]].strip() + return sections[''].strip() + + +class DefaultSchema(ViewInspector): + """Allows overriding AutoSchema using DEFAULT_SCHEMA_CLASS setting""" + def __get__(self, instance, owner): + result = super().__get__(instance, owner) + if not isinstance(result, DefaultSchema): + return result + + inspector_class = api_settings.DEFAULT_SCHEMA_CLASS + assert issubclass(inspector_class, ViewInspector), ( + "DEFAULT_SCHEMA_CLASS must be set to a ViewInspector (usually an AutoSchema) subclass" + ) + inspector = inspector_class() + inspector.view = instance + return inspector diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/openapi.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/openapi.py new file mode 100644 index 0000000000000000000000000000000000000000..ee614fdf6ead2387a50214066ca0d3160ce06997 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/openapi.py @@ -0,0 +1,722 @@ +import re +import warnings +from collections import OrderedDict +from decimal import Decimal +from operator import attrgetter +from urllib.parse import urljoin + +from django.core.validators import ( + DecimalValidator, EmailValidator, MaxLengthValidator, MaxValueValidator, + MinLengthValidator, MinValueValidator, RegexValidator, URLValidator +) +from django.db import models +from django.utils.encoding import force_str + +from rest_framework import ( + RemovedInDRF315Warning, exceptions, renderers, serializers +) +from rest_framework.compat import uritemplate +from rest_framework.fields import _UnvalidatedField, empty +from rest_framework.settings import api_settings + +from .generators import BaseSchemaGenerator +from .inspectors import ViewInspector +from .utils import get_pk_description, is_list_view + + +class SchemaGenerator(BaseSchemaGenerator): + + def get_info(self): + # Title and version are required by openapi specification 3.x + info = { + 'title': self.title or '', + 'version': self.version or '' + } + + if self.description is not None: + info['description'] = self.description + + return info + + def check_duplicate_operation_id(self, paths): + ids = {} + for route in paths: + for method in paths[route]: + if 'operationId' not in paths[route][method]: + continue + operation_id = paths[route][method]['operationId'] + if operation_id in ids: + warnings.warn( + 'You have a duplicated operationId in your OpenAPI schema: {operation_id}\n' + '\tRoute: {route1}, Method: {method1}\n' + '\tRoute: {route2}, Method: {method2}\n' + '\tAn operationId has to be unique across your schema. Your schema may not work in other tools.' + .format( + route1=ids[operation_id]['route'], + method1=ids[operation_id]['method'], + route2=route, + method2=method, + operation_id=operation_id + ) + ) + ids[operation_id] = { + 'route': route, + 'method': method + } + + def get_schema(self, request=None, public=False): + """ + Generate a OpenAPI schema. + """ + self._initialise_endpoints() + components_schemas = {} + + # Iterate endpoints generating per method path operations. + paths = {} + _, view_endpoints = self._get_paths_and_endpoints(None if public else request) + for path, method, view in view_endpoints: + if not self.has_view_permissions(path, method, view): + continue + + operation = view.schema.get_operation(path, method) + components = view.schema.get_components(path, method) + for k in components.keys(): + if k not in components_schemas: + continue + if components_schemas[k] == components[k]: + continue + warnings.warn('Schema component "{}" has been overriden with a different value.'.format(k)) + + components_schemas.update(components) + + # Normalise path for any provided mount url. + if path.startswith('/'): + path = path[1:] + path = urljoin(self.url or '/', path) + + paths.setdefault(path, {}) + paths[path][method.lower()] = operation + + self.check_duplicate_operation_id(paths) + + # Compile final schema. + schema = { + 'openapi': '3.0.2', + 'info': self.get_info(), + 'paths': paths, + } + + if len(components_schemas) > 0: + schema['components'] = { + 'schemas': components_schemas + } + + return schema + +# View Inspectors + + +class AutoSchema(ViewInspector): + + def __init__(self, tags=None, operation_id_base=None, component_name=None): + """ + :param operation_id_base: user-defined name in operationId. If empty, it will be deducted from the Model/Serializer/View name. + :param component_name: user-defined component's name. If empty, it will be deducted from the Serializer's class name. + """ + if tags and not all(isinstance(tag, str) for tag in tags): + raise ValueError('tags must be a list or tuple of string.') + self._tags = tags + self.operation_id_base = operation_id_base + self.component_name = component_name + super().__init__() + + request_media_types = [] + response_media_types = [] + + method_mapping = { + 'get': 'retrieve', + 'post': 'create', + 'put': 'update', + 'patch': 'partialUpdate', + 'delete': 'destroy', + } + + def get_operation(self, path, method): + operation = {} + + operation['operationId'] = self.get_operation_id(path, method) + operation['description'] = self.get_description(path, method) + + parameters = [] + parameters += self.get_path_parameters(path, method) + parameters += self.get_pagination_parameters(path, method) + parameters += self.get_filter_parameters(path, method) + operation['parameters'] = parameters + + request_body = self.get_request_body(path, method) + if request_body: + operation['requestBody'] = request_body + operation['responses'] = self.get_responses(path, method) + operation['tags'] = self.get_tags(path, method) + + return operation + + def get_component_name(self, serializer): + """ + Compute the component's name from the serializer. + Raise an exception if the serializer's class name is "Serializer" (case-insensitive). + """ + if self.component_name is not None: + return self.component_name + + # use the serializer's class name as the component name. + component_name = serializer.__class__.__name__ + # We remove the "serializer" string from the class name. + pattern = re.compile("serializer", re.IGNORECASE) + component_name = pattern.sub("", component_name) + + if component_name == "": + raise Exception( + '"{}" is an invalid class name for schema generation. ' + 'Serializer\'s class name should be unique and explicit. e.g. "ItemSerializer"' + .format(serializer.__class__.__name__) + ) + + return component_name + + def get_components(self, path, method): + """ + Return components with their properties from the serializer. + """ + + if method.lower() == 'delete': + return {} + + request_serializer = self.get_request_serializer(path, method) + response_serializer = self.get_response_serializer(path, method) + + components = {} + + if isinstance(request_serializer, serializers.Serializer): + component_name = self.get_component_name(request_serializer) + content = self.map_serializer(request_serializer) + components.setdefault(component_name, content) + + if isinstance(response_serializer, serializers.Serializer): + component_name = self.get_component_name(response_serializer) + content = self.map_serializer(response_serializer) + components.setdefault(component_name, content) + + return components + + def _to_camel_case(self, snake_str): + components = snake_str.split('_') + # We capitalize the first letter of each component except the first one + # with the 'title' method and join them together. + return components[0] + ''.join(x.title() for x in components[1:]) + + def get_operation_id_base(self, path, method, action): + """ + Compute the base part for operation ID from the model, serializer or view name. + """ + model = getattr(getattr(self.view, 'queryset', None), 'model', None) + + if self.operation_id_base is not None: + name = self.operation_id_base + + # Try to deduce the ID from the view's model + elif model is not None: + name = model.__name__ + + # Try with the serializer class name + elif self.get_serializer(path, method) is not None: + name = self.get_serializer(path, method).__class__.__name__ + if name.endswith('Serializer'): + name = name[:-10] + + # Fallback to the view name + else: + name = self.view.__class__.__name__ + if name.endswith('APIView'): + name = name[:-7] + elif name.endswith('View'): + name = name[:-4] + + # Due to camel-casing of classes and `action` being lowercase, apply title in order to find if action truly + # comes at the end of the name + if name.endswith(action.title()): # ListView, UpdateAPIView, ThingDelete ... + name = name[:-len(action)] + + if action == 'list' and not name.endswith('s'): # listThings instead of listThing + name += 's' + + return name + + def get_operation_id(self, path, method): + """ + Compute an operation ID from the view type and get_operation_id_base method. + """ + method_name = getattr(self.view, 'action', method.lower()) + if is_list_view(path, method, self.view): + action = 'list' + elif method_name not in self.method_mapping: + action = self._to_camel_case(method_name) + else: + action = self.method_mapping[method.lower()] + + name = self.get_operation_id_base(path, method, action) + + return action + name + + def get_path_parameters(self, path, method): + """ + Return a list of parameters from templated path variables. + """ + assert uritemplate, '`uritemplate` must be installed for OpenAPI schema support.' + + model = getattr(getattr(self.view, 'queryset', None), 'model', None) + parameters = [] + + for variable in uritemplate.variables(path): + description = '' + if model is not None: # TODO: test this. + # Attempt to infer a field description if possible. + try: + model_field = model._meta.get_field(variable) + except Exception: + model_field = None + + if model_field is not None and model_field.help_text: + description = force_str(model_field.help_text) + elif model_field is not None and model_field.primary_key: + description = get_pk_description(model, model_field) + + parameter = { + "name": variable, + "in": "path", + "required": True, + "description": description, + 'schema': { + 'type': 'string', # TODO: integer, pattern, ... + }, + } + parameters.append(parameter) + + return parameters + + def get_filter_parameters(self, path, method): + if not self.allows_filters(path, method): + return [] + parameters = [] + for filter_backend in self.view.filter_backends: + parameters += filter_backend().get_schema_operation_parameters(self.view) + return parameters + + def allows_filters(self, path, method): + """ + Determine whether to include filter Fields in schema. + + Default implementation looks for ModelViewSet or GenericAPIView + actions/methods that cause filtering on the default implementation. + """ + if getattr(self.view, 'filter_backends', None) is None: + return False + if hasattr(self.view, 'action'): + return self.view.action in ["list", "retrieve", "update", "partial_update", "destroy"] + return method.lower() in ["get", "put", "patch", "delete"] + + def get_pagination_parameters(self, path, method): + view = self.view + + if not is_list_view(path, method, view): + return [] + + paginator = self.get_paginator() + if not paginator: + return [] + + return paginator.get_schema_operation_parameters(view) + + def map_choicefield(self, field): + choices = list(OrderedDict.fromkeys(field.choices)) # preserve order and remove duplicates + if all(isinstance(choice, bool) for choice in choices): + type = 'boolean' + elif all(isinstance(choice, int) for choice in choices): + type = 'integer' + elif all(isinstance(choice, (int, float, Decimal)) for choice in choices): # `number` includes `integer` + # Ref: https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.21 + type = 'number' + elif all(isinstance(choice, str) for choice in choices): + type = 'string' + else: + type = None + + mapping = { + # The value of `enum` keyword MUST be an array and SHOULD be unique. + # Ref: https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.20 + 'enum': choices + } + + # If We figured out `type` then and only then we should set it. It must be a string. + # Ref: https://swagger.io/docs/specification/data-models/data-types/#mixed-type + # It is optional but it can not be null. + # Ref: https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.21 + if type: + mapping['type'] = type + return mapping + + def map_field(self, field): + + # Nested Serializers, `many` or not. + if isinstance(field, serializers.ListSerializer): + return { + 'type': 'array', + 'items': self.map_serializer(field.child) + } + if isinstance(field, serializers.Serializer): + data = self.map_serializer(field) + data['type'] = 'object' + return data + + # Related fields. + if isinstance(field, serializers.ManyRelatedField): + return { + 'type': 'array', + 'items': self.map_field(field.child_relation) + } + if isinstance(field, serializers.PrimaryKeyRelatedField): + model = getattr(field.queryset, 'model', None) + if model is not None: + model_field = model._meta.pk + if isinstance(model_field, models.AutoField): + return {'type': 'integer'} + + # ChoiceFields (single and multiple). + # Q: + # - Is 'type' required? + # - can we determine the TYPE of a choicefield? + if isinstance(field, serializers.MultipleChoiceField): + return { + 'type': 'array', + 'items': self.map_choicefield(field) + } + + if isinstance(field, serializers.ChoiceField): + return self.map_choicefield(field) + + # ListField. + if isinstance(field, serializers.ListField): + mapping = { + 'type': 'array', + 'items': {}, + } + if not isinstance(field.child, _UnvalidatedField): + mapping['items'] = self.map_field(field.child) + return mapping + + # DateField and DateTimeField type is string + if isinstance(field, serializers.DateField): + return { + 'type': 'string', + 'format': 'date', + } + + if isinstance(field, serializers.DateTimeField): + return { + 'type': 'string', + 'format': 'date-time', + } + + # "Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification." + # see: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#data-types + # see also: https://swagger.io/docs/specification/data-models/data-types/#string + if isinstance(field, serializers.EmailField): + return { + 'type': 'string', + 'format': 'email' + } + + if isinstance(field, serializers.URLField): + return { + 'type': 'string', + 'format': 'uri' + } + + if isinstance(field, serializers.UUIDField): + return { + 'type': 'string', + 'format': 'uuid' + } + + if isinstance(field, serializers.IPAddressField): + content = { + 'type': 'string', + } + if field.protocol != 'both': + content['format'] = field.protocol + return content + + if isinstance(field, serializers.DecimalField): + if getattr(field, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING): + content = { + 'type': 'string', + 'format': 'decimal', + } + else: + content = { + 'type': 'number' + } + + if field.decimal_places: + content['multipleOf'] = float('.' + (field.decimal_places - 1) * '0' + '1') + if field.max_whole_digits: + content['maximum'] = int(field.max_whole_digits * '9') + 1 + content['minimum'] = -content['maximum'] + self._map_min_max(field, content) + return content + + if isinstance(field, serializers.FloatField): + content = { + 'type': 'number', + } + self._map_min_max(field, content) + return content + + if isinstance(field, serializers.IntegerField): + content = { + 'type': 'integer' + } + self._map_min_max(field, content) + # 2147483647 is max for int32_size, so we use int64 for format + if int(content.get('maximum', 0)) > 2147483647 or int(content.get('minimum', 0)) > 2147483647: + content['format'] = 'int64' + return content + + if isinstance(field, serializers.FileField): + return { + 'type': 'string', + 'format': 'binary' + } + + # Simplest cases, default to 'string' type: + FIELD_CLASS_SCHEMA_TYPE = { + serializers.BooleanField: 'boolean', + serializers.JSONField: 'object', + serializers.DictField: 'object', + serializers.HStoreField: 'object', + } + return {'type': FIELD_CLASS_SCHEMA_TYPE.get(field.__class__, 'string')} + + def _map_min_max(self, field, content): + if field.max_value: + content['maximum'] = field.max_value + if field.min_value: + content['minimum'] = field.min_value + + def map_serializer(self, serializer): + # Assuming we have a valid serializer instance. + required = [] + properties = {} + + for field in serializer.fields.values(): + if isinstance(field, serializers.HiddenField): + continue + + if field.required: + required.append(field.field_name) + + schema = self.map_field(field) + if field.read_only: + schema['readOnly'] = True + if field.write_only: + schema['writeOnly'] = True + if field.allow_null: + schema['nullable'] = True + if field.default is not None and field.default != empty and not callable(field.default): + schema['default'] = field.default + if field.help_text: + schema['description'] = str(field.help_text) + self.map_field_validators(field, schema) + + properties[field.field_name] = schema + + result = { + 'type': 'object', + 'properties': properties + } + if required: + result['required'] = required + + return result + + def map_field_validators(self, field, schema): + """ + map field validators + """ + for v in field.validators: + # "Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification." + # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#data-types + if isinstance(v, EmailValidator): + schema['format'] = 'email' + if isinstance(v, URLValidator): + schema['format'] = 'uri' + if isinstance(v, RegexValidator): + # In Python, the token \Z does what \z does in other engines. + # https://stackoverflow.com/questions/53283160 + schema['pattern'] = v.regex.pattern.replace('\\Z', '\\z') + elif isinstance(v, MaxLengthValidator): + attr_name = 'maxLength' + if isinstance(field, serializers.ListField): + attr_name = 'maxItems' + schema[attr_name] = v.limit_value + elif isinstance(v, MinLengthValidator): + attr_name = 'minLength' + if isinstance(field, serializers.ListField): + attr_name = 'minItems' + schema[attr_name] = v.limit_value + elif isinstance(v, MaxValueValidator): + schema['maximum'] = v.limit_value + elif isinstance(v, MinValueValidator): + schema['minimum'] = v.limit_value + elif isinstance(v, DecimalValidator) and \ + not getattr(field, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING): + if v.decimal_places: + schema['multipleOf'] = float('.' + (v.decimal_places - 1) * '0' + '1') + if v.max_digits: + digits = v.max_digits + if v.decimal_places is not None and v.decimal_places > 0: + digits -= v.decimal_places + schema['maximum'] = int(digits * '9') + 1 + schema['minimum'] = -schema['maximum'] + + def get_paginator(self): + pagination_class = getattr(self.view, 'pagination_class', None) + if pagination_class: + return pagination_class() + return None + + def map_parsers(self, path, method): + return list(map(attrgetter('media_type'), self.view.parser_classes)) + + def map_renderers(self, path, method): + media_types = [] + for renderer in self.view.renderer_classes: + # BrowsableAPIRenderer not relevant to OpenAPI spec + if issubclass(renderer, renderers.BrowsableAPIRenderer): + continue + media_types.append(renderer.media_type) + return media_types + + def get_serializer(self, path, method): + view = self.view + + if not hasattr(view, 'get_serializer'): + return None + + try: + return view.get_serializer() + except exceptions.APIException: + warnings.warn('{}.get_serializer() raised an exception during ' + 'schema generation. Serializer fields will not be ' + 'generated for {} {}.' + .format(view.__class__.__name__, method, path)) + return None + + def get_request_serializer(self, path, method): + """ + Override this method if your view uses a different serializer for + handling request body. + """ + return self.get_serializer(path, method) + + def get_response_serializer(self, path, method): + """ + Override this method if your view uses a different serializer for + populating response data. + """ + return self.get_serializer(path, method) + + def get_reference(self, serializer): + return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))} + + def get_request_body(self, path, method): + if method not in ('PUT', 'PATCH', 'POST'): + return {} + + self.request_media_types = self.map_parsers(path, method) + + serializer = self.get_request_serializer(path, method) + + if not isinstance(serializer, serializers.Serializer): + item_schema = {} + else: + item_schema = self.get_reference(serializer) + + return { + 'content': { + ct: {'schema': item_schema} + for ct in self.request_media_types + } + } + + def get_responses(self, path, method): + if method == 'DELETE': + return { + '204': { + 'description': '' + } + } + + self.response_media_types = self.map_renderers(path, method) + + serializer = self.get_response_serializer(path, method) + + if not isinstance(serializer, serializers.Serializer): + item_schema = {} + else: + item_schema = self.get_reference(serializer) + + if is_list_view(path, method, self.view): + response_schema = { + 'type': 'array', + 'items': item_schema, + } + paginator = self.get_paginator() + if paginator: + response_schema = paginator.get_paginated_response_schema(response_schema) + else: + response_schema = item_schema + status_code = '201' if method == 'POST' else '200' + return { + status_code: { + 'content': { + ct: {'schema': response_schema} + for ct in self.response_media_types + }, + # description is a mandatory property, + # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject + # TODO: put something meaningful into it + 'description': "" + } + } + + def get_tags(self, path, method): + # If user have specified tags, use them. + if self._tags: + return self._tags + + # First element of a specific path could be valid tag. This is a fallback solution. + # PUT, PATCH, GET(Retrieve), DELETE: /user_profile/{id}/ tags = [user-profile] + # POST, GET(List): /user_profile/ tags = [user-profile] + if path.startswith('/'): + path = path[1:] + + return [path.split('/')[0].replace('_', '-')] + + def _get_reference(self, serializer): + warnings.warn( + "Method `_get_reference()` has been renamed to `get_reference()`. " + "The old name will be removed in DRF v3.15.", + RemovedInDRF315Warning, stacklevel=2 + ) + return self.get_reference(serializer) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..60ed6982943967bcad1e19c68d83bfdada34f74f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/utils.py @@ -0,0 +1,41 @@ +""" +utils.py # Shared helper functions + +See schemas.__init__.py for package overview. +""" +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from rest_framework.mixins import RetrieveModelMixin + + +def is_list_view(path, method, view): + """ + Return True if the given path/method appears to represent a list view. + """ + if hasattr(view, 'action'): + # Viewsets have an explicitly defined action, which we can inspect. + return view.action == 'list' + + if method.lower() != 'get': + return False + if isinstance(view, RetrieveModelMixin): + return False + path_components = path.strip('/').split('/') + if path_components and '{' in path_components[-1]: + return False + return True + + +def get_pk_description(model, model_field): + if isinstance(model_field, models.AutoField): + value_type = _('unique integer value') + elif isinstance(model_field, models.UUIDField): + value_type = _('UUID string') + else: + value_type = _('unique value') + + return _('A {value_type} identifying this {name}.').format( + value_type=value_type, + name=model._meta.verbose_name, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/views.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/views.py new file mode 100644 index 0000000000000000000000000000000000000000..527a23236f8e426d860709f36f85dfd13fb5f6c8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/schemas/views.py @@ -0,0 +1,48 @@ +""" +views.py # Houses `SchemaView`, `APIView` subclass. + +See schemas.__init__.py for package overview. +""" +from rest_framework import exceptions, renderers +from rest_framework.response import Response +from rest_framework.schemas import coreapi +from rest_framework.settings import api_settings +from rest_framework.views import APIView + + +class SchemaView(APIView): + _ignore_model_permissions = True + schema = None # exclude from schema + renderer_classes = None + schema_generator = None + public = False + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.renderer_classes is None: + if coreapi.is_enabled(): + self.renderer_classes = [ + renderers.CoreAPIOpenAPIRenderer, + renderers.CoreJSONRenderer + ] + else: + self.renderer_classes = [ + renderers.OpenAPIRenderer, + renderers.JSONOpenAPIRenderer, + ] + if renderers.BrowsableAPIRenderer in api_settings.DEFAULT_RENDERER_CLASSES: + self.renderer_classes += [renderers.BrowsableAPIRenderer] + + def get(self, request, *args, **kwargs): + schema = self.schema_generator.get_schema(request, self.public) + if schema is None: + raise exceptions.PermissionDenied() + return Response(schema) + + def handle_exception(self, exc): + # Schema renderers do not render exceptions, so re-perform content + # negotiation with default renderers. + self.renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + neg = self.perform_content_negotiation(self.request, force=True) + self.request.accepted_renderer, self.request.accepted_media_type = neg + return super().handle_exception(exc) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/serializers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..083910174bd45ef14157df85849401b14a3eca2a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/serializers.py @@ -0,0 +1,1666 @@ +""" +Serializers and ModelSerializers are similar to Forms and ModelForms. +Unlike forms, they are not constrained to dealing with HTML output, and +form encoded input. + +Serialization in REST framework is a two-phase process: + +1. Serializers marshal between complex types like model instances, and +python primitives. +2. The process of marshalling between python primitives and request and +response content is handled by parsers and renderers. +""" +import copy +import inspect +import traceback +from collections import OrderedDict, defaultdict +from collections.abc import Mapping + +from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured +from django.core.exceptions import ValidationError as DjangoValidationError +from django.db import models +from django.db.models.fields import Field as DjangoModelField +from django.utils import timezone +from django.utils.functional import cached_property +from django.utils.translation import gettext_lazy as _ + +from rest_framework.compat import postgres_fields +from rest_framework.exceptions import ErrorDetail, ValidationError +from rest_framework.fields import get_error_detail, set_value +from rest_framework.settings import api_settings +from rest_framework.utils import html, model_meta, representation +from rest_framework.utils.field_mapping import ( + ClassLookupDict, get_field_kwargs, get_nested_relation_kwargs, + get_relation_kwargs, get_url_kwargs +) +from rest_framework.utils.serializer_helpers import ( + BindingDict, BoundField, JSONBoundField, NestedBoundField, ReturnDict, + ReturnList +) +from rest_framework.validators import ( + UniqueForDateValidator, UniqueForMonthValidator, UniqueForYearValidator, + UniqueTogetherValidator +) + +# Note: We do the following so that users of the framework can use this style: +# +# example_field = serializers.CharField(...) +# +# This helps keep the separation between model fields, form fields, and +# serializer fields more explicit. +from rest_framework.fields import ( # NOQA # isort:skip + BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField, + DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField, + HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField, + ListField, ModelField, MultipleChoiceField, ReadOnlyField, + RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField, +) +from rest_framework.relations import ( # NOQA # isort:skip + HyperlinkedIdentityField, HyperlinkedRelatedField, ManyRelatedField, + PrimaryKeyRelatedField, RelatedField, SlugRelatedField, StringRelatedField, +) + +# Non-field imports, but public API +from rest_framework.fields import ( # NOQA # isort:skip + CreateOnlyDefault, CurrentUserDefault, SkipField, empty +) +from rest_framework.relations import Hyperlink, PKOnlyObject # NOQA # isort:skip + +# We assume that 'validators' are intended for the child serializer, +# rather than the parent serializer. +LIST_SERIALIZER_KWARGS = ( + 'read_only', 'write_only', 'required', 'default', 'initial', 'source', + 'label', 'help_text', 'style', 'error_messages', 'allow_empty', + 'instance', 'data', 'partial', 'context', 'allow_null', + 'max_length', 'min_length' +) + +ALL_FIELDS = '__all__' + + +# BaseSerializer +# -------------- + +class BaseSerializer(Field): + """ + The BaseSerializer class provides a minimal class which may be used + for writing custom serializer implementations. + + Note that we strongly restrict the ordering of operations/properties + that may be used on the serializer in order to enforce correct usage. + + In particular, if a `data=` argument is passed then: + + .is_valid() - Available. + .initial_data - Available. + .validated_data - Only available after calling `is_valid()` + .errors - Only available after calling `is_valid()` + .data - Only available after calling `is_valid()` + + If a `data=` argument is not passed then: + + .is_valid() - Not available. + .initial_data - Not available. + .validated_data - Not available. + .errors - Not available. + .data - Available. + """ + + def __init__(self, instance=None, data=empty, **kwargs): + self.instance = instance + if data is not empty: + self.initial_data = data + self.partial = kwargs.pop('partial', False) + self._context = kwargs.pop('context', {}) + kwargs.pop('many', None) + super().__init__(**kwargs) + + def __new__(cls, *args, **kwargs): + # We override this method in order to automatically create + # `ListSerializer` classes instead when `many=True` is set. + if kwargs.pop('many', False): + return cls.many_init(*args, **kwargs) + return super().__new__(cls, *args, **kwargs) + + # Allow type checkers to make serializers generic. + def __class_getitem__(cls, *args, **kwargs): + return cls + + @classmethod + def many_init(cls, *args, **kwargs): + """ + This method implements the creation of a `ListSerializer` parent + class when `many=True` is used. You can customize it if you need to + control which keyword arguments are passed to the parent, and + which are passed to the child. + + Note that we're over-cautious in passing most arguments to both parent + and child classes in order to try to cover the general case. If you're + overriding this method you'll probably want something much simpler, eg: + + @classmethod + def many_init(cls, *args, **kwargs): + kwargs['child'] = cls() + return CustomListSerializer(*args, **kwargs) + """ + allow_empty = kwargs.pop('allow_empty', None) + max_length = kwargs.pop('max_length', None) + min_length = kwargs.pop('min_length', None) + child_serializer = cls(*args, **kwargs) + list_kwargs = { + 'child': child_serializer, + } + if allow_empty is not None: + list_kwargs['allow_empty'] = allow_empty + if max_length is not None: + list_kwargs['max_length'] = max_length + if min_length is not None: + list_kwargs['min_length'] = min_length + list_kwargs.update({ + key: value for key, value in kwargs.items() + if key in LIST_SERIALIZER_KWARGS + }) + meta = getattr(cls, 'Meta', None) + list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) + return list_serializer_class(*args, **list_kwargs) + + def to_internal_value(self, data): + raise NotImplementedError('`to_internal_value()` must be implemented.') + + def to_representation(self, instance): + raise NotImplementedError('`to_representation()` must be implemented.') + + def update(self, instance, validated_data): + raise NotImplementedError('`update()` must be implemented.') + + def create(self, validated_data): + raise NotImplementedError('`create()` must be implemented.') + + def save(self, **kwargs): + assert hasattr(self, '_errors'), ( + 'You must call `.is_valid()` before calling `.save()`.' + ) + + assert not self.errors, ( + 'You cannot call `.save()` on a serializer with invalid data.' + ) + + # Guard against incorrect use of `serializer.save(commit=False)` + assert 'commit' not in kwargs, ( + "'commit' is not a valid keyword argument to the 'save()' method. " + "If you need to access data before committing to the database then " + "inspect 'serializer.validated_data' instead. " + "You can also pass additional keyword arguments to 'save()' if you " + "need to set extra attributes on the saved model instance. " + "For example: 'serializer.save(owner=request.user)'.'" + ) + + assert not hasattr(self, '_data'), ( + "You cannot call `.save()` after accessing `serializer.data`." + "If you need to access data before committing to the database then " + "inspect 'serializer.validated_data' instead. " + ) + + validated_data = {**self.validated_data, **kwargs} + + if self.instance is not None: + self.instance = self.update(self.instance, validated_data) + assert self.instance is not None, ( + '`update()` did not return an object instance.' + ) + else: + self.instance = self.create(validated_data) + assert self.instance is not None, ( + '`create()` did not return an object instance.' + ) + + return self.instance + + def is_valid(self, *, raise_exception=False): + assert hasattr(self, 'initial_data'), ( + 'Cannot call `.is_valid()` as no `data=` keyword argument was ' + 'passed when instantiating the serializer instance.' + ) + + if not hasattr(self, '_validated_data'): + try: + self._validated_data = self.run_validation(self.initial_data) + except ValidationError as exc: + self._validated_data = {} + self._errors = exc.detail + else: + self._errors = {} + + if self._errors and raise_exception: + raise ValidationError(self.errors) + + return not bool(self._errors) + + @property + def data(self): + if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'): + msg = ( + 'When a serializer is passed a `data` keyword argument you ' + 'must call `.is_valid()` before attempting to access the ' + 'serialized `.data` representation.\n' + 'You should either call `.is_valid()` first, ' + 'or access `.initial_data` instead.' + ) + raise AssertionError(msg) + + if not hasattr(self, '_data'): + if self.instance is not None and not getattr(self, '_errors', None): + self._data = self.to_representation(self.instance) + elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None): + self._data = self.to_representation(self.validated_data) + else: + self._data = self.get_initial() + return self._data + + @property + def errors(self): + if not hasattr(self, '_errors'): + msg = 'You must call `.is_valid()` before accessing `.errors`.' + raise AssertionError(msg) + return self._errors + + @property + def validated_data(self): + if not hasattr(self, '_validated_data'): + msg = 'You must call `.is_valid()` before accessing `.validated_data`.' + raise AssertionError(msg) + return self._validated_data + + +# Serializer & ListSerializer classes +# ----------------------------------- + +class SerializerMetaclass(type): + """ + This metaclass sets a dictionary named `_declared_fields` on the class. + + Any instances of `Field` included as attributes on either the class + or on any of its superclasses will be include in the + `_declared_fields` dictionary. + """ + + @classmethod + def _get_declared_fields(cls, bases, attrs): + fields = [(field_name, attrs.pop(field_name)) + for field_name, obj in list(attrs.items()) + if isinstance(obj, Field)] + fields.sort(key=lambda x: x[1]._creation_counter) + + # Ensures a base class field doesn't override cls attrs, and maintains + # field precedence when inheriting multiple parents. e.g. if there is a + # class C(A, B), and A and B both define 'field', use 'field' from A. + known = set(attrs) + + def visit(name): + known.add(name) + return name + + base_fields = [ + (visit(name), f) + for base in bases if hasattr(base, '_declared_fields') + for name, f in base._declared_fields.items() if name not in known + ] + + return OrderedDict(base_fields + fields) + + def __new__(cls, name, bases, attrs): + attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs) + return super().__new__(cls, name, bases, attrs) + + +def as_serializer_error(exc): + assert isinstance(exc, (ValidationError, DjangoValidationError)) + + if isinstance(exc, DjangoValidationError): + detail = get_error_detail(exc) + else: + detail = exc.detail + + if isinstance(detail, Mapping): + # If errors may be a dict we use the standard {key: list of values}. + # Here we ensure that all the values are *lists* of errors. + return { + key: value if isinstance(value, (list, Mapping)) else [value] + for key, value in detail.items() + } + elif isinstance(detail, list): + # Errors raised as a list are non-field errors. + return { + api_settings.NON_FIELD_ERRORS_KEY: detail + } + # Errors raised as a string are non-field errors. + return { + api_settings.NON_FIELD_ERRORS_KEY: [detail] + } + + +class Serializer(BaseSerializer, metaclass=SerializerMetaclass): + default_error_messages = { + 'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.') + } + + @cached_property + def fields(self): + """ + A dictionary of {field_name: field_instance}. + """ + # `fields` is evaluated lazily. We do this to ensure that we don't + # have issues importing modules that use ModelSerializers as fields, + # even if Django's app-loading stage has not yet run. + fields = BindingDict(self) + for key, value in self.get_fields().items(): + fields[key] = value + return fields + + @property + def _writable_fields(self): + for field in self.fields.values(): + if not field.read_only: + yield field + + @property + def _readable_fields(self): + for field in self.fields.values(): + if not field.write_only: + yield field + + def get_fields(self): + """ + Returns a dictionary of {field_name: field_instance}. + """ + # Every new serializer is created with a clone of the field instances. + # This allows users to dynamically modify the fields on a serializer + # instance without affecting every other serializer instance. + return copy.deepcopy(self._declared_fields) + + def get_validators(self): + """ + Returns a list of validator callables. + """ + # Used by the lazily-evaluated `validators` property. + meta = getattr(self, 'Meta', None) + validators = getattr(meta, 'validators', None) + return list(validators) if validators else [] + + def get_initial(self): + if hasattr(self, 'initial_data'): + # initial_data may not be a valid type + if not isinstance(self.initial_data, Mapping): + return OrderedDict() + + return OrderedDict([ + (field_name, field.get_value(self.initial_data)) + for field_name, field in self.fields.items() + if (field.get_value(self.initial_data) is not empty) and + not field.read_only + ]) + + return OrderedDict([ + (field.field_name, field.get_initial()) + for field in self.fields.values() + if not field.read_only + ]) + + def get_value(self, dictionary): + # We override the default field access in order to support + # nested HTML forms. + if html.is_html_input(dictionary): + return html.parse_html_dict(dictionary, prefix=self.field_name) or empty + return dictionary.get(self.field_name, empty) + + def run_validation(self, data=empty): + """ + We override the default `run_validation`, because the validation + performed by validators and the `.validate()` method should + be coerced into an error dictionary with a 'non_fields_error' key. + """ + (is_empty_value, data) = self.validate_empty_values(data) + if is_empty_value: + return data + + value = self.to_internal_value(data) + try: + self.run_validators(value) + value = self.validate(value) + assert value is not None, '.validate() should return the validated data' + except (ValidationError, DjangoValidationError) as exc: + raise ValidationError(detail=as_serializer_error(exc)) + + return value + + def _read_only_defaults(self): + fields = [ + field for field in self.fields.values() + if (field.read_only) and (field.default != empty) and (field.source != '*') and ('.' not in field.source) + ] + + defaults = OrderedDict() + for field in fields: + try: + default = field.get_default() + except SkipField: + continue + defaults[field.source] = default + + return defaults + + def run_validators(self, value): + """ + Add read_only fields with defaults to value before running validators. + """ + if isinstance(value, dict): + to_validate = self._read_only_defaults() + to_validate.update(value) + else: + to_validate = value + super().run_validators(to_validate) + + def to_internal_value(self, data): + """ + Dict of native values <- Dict of primitive datatypes. + """ + if not isinstance(data, Mapping): + message = self.error_messages['invalid'].format( + datatype=type(data).__name__ + ) + raise ValidationError({ + api_settings.NON_FIELD_ERRORS_KEY: [message] + }, code='invalid') + + ret = OrderedDict() + errors = OrderedDict() + fields = self._writable_fields + + for field in fields: + validate_method = getattr(self, 'validate_' + field.field_name, None) + primitive_value = field.get_value(data) + try: + validated_value = field.run_validation(primitive_value) + if validate_method is not None: + validated_value = validate_method(validated_value) + except ValidationError as exc: + errors[field.field_name] = exc.detail + except DjangoValidationError as exc: + errors[field.field_name] = get_error_detail(exc) + except SkipField: + pass + else: + set_value(ret, field.source_attrs, validated_value) + + if errors: + raise ValidationError(errors) + + return ret + + def to_representation(self, instance): + """ + Object instance -> Dict of primitive datatypes. + """ + ret = OrderedDict() + fields = self._readable_fields + + for field in fields: + try: + attribute = field.get_attribute(instance) + except SkipField: + continue + + # We skip `to_representation` for `None` values so that fields do + # not have to explicitly deal with that case. + # + # For related fields with `use_pk_only_optimization` we need to + # resolve the pk value. + check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute + if check_for_none is None: + ret[field.field_name] = None + else: + ret[field.field_name] = field.to_representation(attribute) + + return ret + + def validate(self, attrs): + return attrs + + def __repr__(self): + return representation.serializer_repr(self, indent=1) + + # The following are used for accessing `BoundField` instances on the + # serializer, for the purposes of presenting a form-like API onto the + # field values and field errors. + + def __iter__(self): + for field in self.fields.values(): + yield self[field.field_name] + + def __getitem__(self, key): + field = self.fields[key] + value = self.data.get(key) + error = self.errors.get(key) if hasattr(self, '_errors') else None + if isinstance(field, Serializer): + return NestedBoundField(field, value, error) + if isinstance(field, JSONField): + return JSONBoundField(field, value, error) + return BoundField(field, value, error) + + # Include a backlink to the serializer class on return objects. + # Allows renderers such as HTMLFormRenderer to get the full field info. + + @property + def data(self): + ret = super().data + return ReturnDict(ret, serializer=self) + + @property + def errors(self): + ret = super().errors + if isinstance(ret, list) and len(ret) == 1 and getattr(ret[0], 'code', None) == 'null': + # Edge case. Provide a more descriptive error than + # "this field may not be null", when no data is passed. + detail = ErrorDetail('No data provided', code='null') + ret = {api_settings.NON_FIELD_ERRORS_KEY: [detail]} + return ReturnDict(ret, serializer=self) + + +# There's some replication of `ListField` here, +# but that's probably better than obfuscating the call hierarchy. + +class ListSerializer(BaseSerializer): + child = None + many = True + + default_error_messages = { + 'not_a_list': _('Expected a list of items but got type "{input_type}".'), + 'empty': _('This list may not be empty.'), + 'max_length': _('Ensure this field has no more than {max_length} elements.'), + 'min_length': _('Ensure this field has at least {min_length} elements.') + } + + def __init__(self, *args, **kwargs): + self.child = kwargs.pop('child', copy.deepcopy(self.child)) + self.allow_empty = kwargs.pop('allow_empty', True) + self.max_length = kwargs.pop('max_length', None) + self.min_length = kwargs.pop('min_length', None) + assert self.child is not None, '`child` is a required argument.' + assert not inspect.isclass(self.child), '`child` has not been instantiated.' + super().__init__(*args, **kwargs) + self.child.bind(field_name='', parent=self) + + def get_initial(self): + if hasattr(self, 'initial_data'): + return self.to_representation(self.initial_data) + return [] + + def get_value(self, dictionary): + """ + Given the input dictionary, return the field value. + """ + # We override the default field access in order to support + # lists in HTML forms. + if html.is_html_input(dictionary): + return html.parse_html_list(dictionary, prefix=self.field_name, default=empty) + return dictionary.get(self.field_name, empty) + + def run_validation(self, data=empty): + """ + We override the default `run_validation`, because the validation + performed by validators and the `.validate()` method should + be coerced into an error dictionary with a 'non_fields_error' key. + """ + (is_empty_value, data) = self.validate_empty_values(data) + if is_empty_value: + return data + + value = self.to_internal_value(data) + try: + self.run_validators(value) + value = self.validate(value) + assert value is not None, '.validate() should return the validated data' + except (ValidationError, DjangoValidationError) as exc: + raise ValidationError(detail=as_serializer_error(exc)) + + return value + + def to_internal_value(self, data): + """ + List of dicts of native values <- List of dicts of primitive datatypes. + """ + if html.is_html_input(data): + data = html.parse_html_list(data, default=[]) + + if not isinstance(data, list): + message = self.error_messages['not_a_list'].format( + input_type=type(data).__name__ + ) + raise ValidationError({ + api_settings.NON_FIELD_ERRORS_KEY: [message] + }, code='not_a_list') + + if not self.allow_empty and len(data) == 0: + message = self.error_messages['empty'] + raise ValidationError({ + api_settings.NON_FIELD_ERRORS_KEY: [message] + }, code='empty') + + if self.max_length is not None and len(data) > self.max_length: + message = self.error_messages['max_length'].format(max_length=self.max_length) + raise ValidationError({ + api_settings.NON_FIELD_ERRORS_KEY: [message] + }, code='max_length') + + if self.min_length is not None and len(data) < self.min_length: + message = self.error_messages['min_length'].format(min_length=self.min_length) + raise ValidationError({ + api_settings.NON_FIELD_ERRORS_KEY: [message] + }, code='min_length') + + ret = [] + errors = [] + + for item in data: + try: + validated = self.child.run_validation(item) + except ValidationError as exc: + errors.append(exc.detail) + else: + ret.append(validated) + errors.append({}) + + if any(errors): + raise ValidationError(errors) + + return ret + + def to_representation(self, data): + """ + List of object instances -> List of dicts of primitive datatypes. + """ + # Dealing with nested relationships, data can be a Manager, + # so, first get a queryset from the Manager if needed + iterable = data.all() if isinstance(data, models.Manager) else data + + return [ + self.child.to_representation(item) for item in iterable + ] + + def validate(self, attrs): + return attrs + + def update(self, instance, validated_data): + raise NotImplementedError( + "Serializers with many=True do not support multiple update by " + "default, only multiple create. For updates it is unclear how to " + "deal with insertions and deletions. If you need to support " + "multiple update, use a `ListSerializer` class and override " + "`.update()` so you can specify the behavior exactly." + ) + + def create(self, validated_data): + return [ + self.child.create(attrs) for attrs in validated_data + ] + + def save(self, **kwargs): + """ + Save and return a list of object instances. + """ + # Guard against incorrect use of `serializer.save(commit=False)` + assert 'commit' not in kwargs, ( + "'commit' is not a valid keyword argument to the 'save()' method. " + "If you need to access data before committing to the database then " + "inspect 'serializer.validated_data' instead. " + "You can also pass additional keyword arguments to 'save()' if you " + "need to set extra attributes on the saved model instance. " + "For example: 'serializer.save(owner=request.user)'.'" + ) + + validated_data = [ + {**attrs, **kwargs} for attrs in self.validated_data + ] + + if self.instance is not None: + self.instance = self.update(self.instance, validated_data) + assert self.instance is not None, ( + '`update()` did not return an object instance.' + ) + else: + self.instance = self.create(validated_data) + assert self.instance is not None, ( + '`create()` did not return an object instance.' + ) + + return self.instance + + def is_valid(self, *, raise_exception=False): + # This implementation is the same as the default, + # except that we use lists, rather than dicts, as the empty case. + assert hasattr(self, 'initial_data'), ( + 'Cannot call `.is_valid()` as no `data=` keyword argument was ' + 'passed when instantiating the serializer instance.' + ) + + if not hasattr(self, '_validated_data'): + try: + self._validated_data = self.run_validation(self.initial_data) + except ValidationError as exc: + self._validated_data = [] + self._errors = exc.detail + else: + self._errors = [] + + if self._errors and raise_exception: + raise ValidationError(self.errors) + + return not bool(self._errors) + + def __repr__(self): + return representation.list_repr(self, indent=1) + + # Include a backlink to the serializer class on return objects. + # Allows renderers such as HTMLFormRenderer to get the full field info. + + @property + def data(self): + ret = super().data + return ReturnList(ret, serializer=self) + + @property + def errors(self): + ret = super().errors + if isinstance(ret, list) and len(ret) == 1 and getattr(ret[0], 'code', None) == 'null': + # Edge case. Provide a more descriptive error than + # "this field may not be null", when no data is passed. + detail = ErrorDetail('No data provided', code='null') + ret = {api_settings.NON_FIELD_ERRORS_KEY: [detail]} + if isinstance(ret, dict): + return ReturnDict(ret, serializer=self) + return ReturnList(ret, serializer=self) + + +# ModelSerializer & HyperlinkedModelSerializer +# -------------------------------------------- + +def raise_errors_on_nested_writes(method_name, serializer, validated_data): + """ + Give explicit errors when users attempt to pass writable nested data. + + If we don't do this explicitly they'd get a less helpful error when + calling `.save()` on the serializer. + + We don't *automatically* support these sorts of nested writes because + there are too many ambiguities to define a default behavior. + + Eg. Suppose we have a `UserSerializer` with a nested profile. How should + we handle the case of an update, where the `profile` relationship does + not exist? Any of the following might be valid: + + * Raise an application error. + * Silently ignore the nested part of the update. + * Automatically create a profile instance. + """ + ModelClass = serializer.Meta.model + model_field_info = model_meta.get_field_info(ModelClass) + + # Ensure we don't have a writable nested field. For example: + # + # class UserSerializer(ModelSerializer): + # ... + # profile = ProfileSerializer() + assert not any( + isinstance(field, BaseSerializer) and + (field.source in validated_data) and + (field.source in model_field_info.relations) and + isinstance(validated_data[field.source], (list, dict)) + for field in serializer._writable_fields + ), ( + 'The `.{method_name}()` method does not support writable nested ' + 'fields by default.\nWrite an explicit `.{method_name}()` method for ' + 'serializer `{module}.{class_name}`, or set `read_only=True` on ' + 'nested serializer fields.'.format( + method_name=method_name, + module=serializer.__class__.__module__, + class_name=serializer.__class__.__name__ + ) + ) + + # Ensure we don't have a writable dotted-source field. For example: + # + # class UserSerializer(ModelSerializer): + # ... + # address = serializer.CharField('profile.address') + # + # Though, non-relational fields (e.g., JSONField) are acceptable. For example: + # + # class NonRelationalPersonModel(models.Model): + # profile = JSONField() + # + # class UserSerializer(ModelSerializer): + # ... + # address = serializer.CharField('profile.address') + assert not any( + len(field.source_attrs) > 1 and + (field.source_attrs[0] in validated_data) and + (field.source_attrs[0] in model_field_info.relations) and + isinstance(validated_data[field.source_attrs[0]], (list, dict)) + for field in serializer._writable_fields + ), ( + 'The `.{method_name}()` method does not support writable dotted-source ' + 'fields by default.\nWrite an explicit `.{method_name}()` method for ' + 'serializer `{module}.{class_name}`, or set `read_only=True` on ' + 'dotted-source serializer fields.'.format( + method_name=method_name, + module=serializer.__class__.__module__, + class_name=serializer.__class__.__name__ + ) + ) + + +class ModelSerializer(Serializer): + """ + A `ModelSerializer` is just a regular `Serializer`, except that: + + * A set of default fields are automatically populated. + * A set of default validators are automatically populated. + * Default `.create()` and `.update()` implementations are provided. + + The process of automatically determining a set of serializer fields + based on the model fields is reasonably complex, but you almost certainly + don't need to dig into the implementation. + + If the `ModelSerializer` class *doesn't* generate the set of fields that + you need you should either declare the extra/differing fields explicitly on + the serializer class, or simply use a `Serializer` class. + """ + serializer_field_mapping = { + models.AutoField: IntegerField, + models.BigIntegerField: IntegerField, + models.BooleanField: BooleanField, + models.CharField: CharField, + models.CommaSeparatedIntegerField: CharField, + models.DateField: DateField, + models.DateTimeField: DateTimeField, + models.DecimalField: DecimalField, + models.DurationField: DurationField, + models.EmailField: EmailField, + models.Field: ModelField, + models.FileField: FileField, + models.FloatField: FloatField, + models.ImageField: ImageField, + models.IntegerField: IntegerField, + models.NullBooleanField: BooleanField, + models.PositiveIntegerField: IntegerField, + models.PositiveSmallIntegerField: IntegerField, + models.SlugField: SlugField, + models.SmallIntegerField: IntegerField, + models.TextField: CharField, + models.TimeField: TimeField, + models.URLField: URLField, + models.UUIDField: UUIDField, + models.GenericIPAddressField: IPAddressField, + models.FilePathField: FilePathField, + } + if hasattr(models, 'JSONField'): + serializer_field_mapping[models.JSONField] = JSONField + if postgres_fields: + serializer_field_mapping[postgres_fields.HStoreField] = HStoreField + serializer_field_mapping[postgres_fields.ArrayField] = ListField + serializer_field_mapping[postgres_fields.JSONField] = JSONField + serializer_related_field = PrimaryKeyRelatedField + serializer_related_to_field = SlugRelatedField + serializer_url_field = HyperlinkedIdentityField + serializer_choice_field = ChoiceField + + # The field name for hyperlinked identity fields. Defaults to 'url'. + # You can modify this using the API setting. + # + # Note that if you instead need modify this on a per-serializer basis, + # you'll also need to ensure you update the `create` method on any generic + # views, to correctly handle the 'Location' response header for + # "HTTP 201 Created" responses. + url_field_name = None + + # Default `create` and `update` behavior... + def create(self, validated_data): + """ + We have a bit of extra checking around this in order to provide + descriptive messages when something goes wrong, but this method is + essentially just: + + return ExampleModel.objects.create(**validated_data) + + If there are many to many fields present on the instance then they + cannot be set until the model is instantiated, in which case the + implementation is like so: + + example_relationship = validated_data.pop('example_relationship') + instance = ExampleModel.objects.create(**validated_data) + instance.example_relationship = example_relationship + return instance + + The default implementation also does not handle nested relationships. + If you want to support writable nested relationships you'll need + to write an explicit `.create()` method. + """ + raise_errors_on_nested_writes('create', self, validated_data) + + ModelClass = self.Meta.model + + # Remove many-to-many relationships from validated_data. + # They are not valid arguments to the default `.create()` method, + # as they require that the instance has already been saved. + info = model_meta.get_field_info(ModelClass) + many_to_many = {} + for field_name, relation_info in info.relations.items(): + if relation_info.to_many and (field_name in validated_data): + many_to_many[field_name] = validated_data.pop(field_name) + + try: + instance = ModelClass._default_manager.create(**validated_data) + except TypeError: + tb = traceback.format_exc() + msg = ( + 'Got a `TypeError` when calling `%s.%s.create()`. ' + 'This may be because you have a writable field on the ' + 'serializer class that is not a valid argument to ' + '`%s.%s.create()`. You may need to make the field ' + 'read-only, or override the %s.create() method to handle ' + 'this correctly.\nOriginal exception was:\n %s' % + ( + ModelClass.__name__, + ModelClass._default_manager.name, + ModelClass.__name__, + ModelClass._default_manager.name, + self.__class__.__name__, + tb + ) + ) + raise TypeError(msg) + + # Save many-to-many relationships after the instance is created. + if many_to_many: + for field_name, value in many_to_many.items(): + field = getattr(instance, field_name) + field.set(value) + + return instance + + def update(self, instance, validated_data): + raise_errors_on_nested_writes('update', self, validated_data) + info = model_meta.get_field_info(instance) + + # Simply set each attribute on the instance, and then save it. + # Note that unlike `.create()` we don't need to treat many-to-many + # relationships as being a special case. During updates we already + # have an instance pk for the relationships to be associated with. + m2m_fields = [] + for attr, value in validated_data.items(): + if attr in info.relations and info.relations[attr].to_many: + m2m_fields.append((attr, value)) + else: + setattr(instance, attr, value) + + instance.save() + + # Note that many-to-many fields are set after updating instance. + # Setting m2m fields triggers signals which could potentially change + # updated instance and we do not want it to collide with .update() + for attr, value in m2m_fields: + field = getattr(instance, attr) + field.set(value) + + return instance + + # Determine the fields to apply... + + def get_fields(self): + """ + Return the dict of field names -> field instances that should be + used for `self.fields` when instantiating the serializer. + """ + if self.url_field_name is None: + self.url_field_name = api_settings.URL_FIELD_NAME + + assert hasattr(self, 'Meta'), ( + 'Class {serializer_class} missing "Meta" attribute'.format( + serializer_class=self.__class__.__name__ + ) + ) + assert hasattr(self.Meta, 'model'), ( + 'Class {serializer_class} missing "Meta.model" attribute'.format( + serializer_class=self.__class__.__name__ + ) + ) + if model_meta.is_abstract_model(self.Meta.model): + raise ValueError( + 'Cannot use ModelSerializer with Abstract Models.' + ) + + declared_fields = copy.deepcopy(self._declared_fields) + model = getattr(self.Meta, 'model') + depth = getattr(self.Meta, 'depth', 0) + + if depth is not None: + assert depth >= 0, "'depth' may not be negative." + assert depth <= 10, "'depth' may not be greater than 10." + + # Retrieve metadata about fields & relationships on the model class. + info = model_meta.get_field_info(model) + field_names = self.get_field_names(declared_fields, info) + + # Determine any extra field arguments and hidden fields that + # should be included + extra_kwargs = self.get_extra_kwargs() + extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs( + field_names, declared_fields, extra_kwargs + ) + + # Determine the fields that should be included on the serializer. + fields = OrderedDict() + + for field_name in field_names: + # If the field is explicitly declared on the class then use that. + if field_name in declared_fields: + fields[field_name] = declared_fields[field_name] + continue + + extra_field_kwargs = extra_kwargs.get(field_name, {}) + source = extra_field_kwargs.get('source', '*') + if source == '*': + source = field_name + + # Determine the serializer field class and keyword arguments. + field_class, field_kwargs = self.build_field( + source, info, model, depth + ) + + # Include any kwargs defined in `Meta.extra_kwargs` + field_kwargs = self.include_extra_kwargs( + field_kwargs, extra_field_kwargs + ) + + # Create the serializer field. + fields[field_name] = field_class(**field_kwargs) + + # Add in any hidden fields. + fields.update(hidden_fields) + + return fields + + # Methods for determining the set of field names to include... + + def get_field_names(self, declared_fields, info): + """ + Returns the list of all field names that should be created when + instantiating this serializer class. This is based on the default + set of fields, but also takes into account the `Meta.fields` or + `Meta.exclude` options if they have been specified. + """ + fields = getattr(self.Meta, 'fields', None) + exclude = getattr(self.Meta, 'exclude', None) + + if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)): + raise TypeError( + 'The `fields` option must be a list or tuple or "__all__". ' + 'Got %s.' % type(fields).__name__ + ) + + if exclude and not isinstance(exclude, (list, tuple)): + raise TypeError( + 'The `exclude` option must be a list or tuple. Got %s.' % + type(exclude).__name__ + ) + + assert not (fields and exclude), ( + "Cannot set both 'fields' and 'exclude' options on " + "serializer {serializer_class}.".format( + serializer_class=self.__class__.__name__ + ) + ) + + assert not (fields is None and exclude is None), ( + "Creating a ModelSerializer without either the 'fields' attribute " + "or the 'exclude' attribute has been deprecated since 3.3.0, " + "and is now disallowed. Add an explicit fields = '__all__' to the " + "{serializer_class} serializer.".format( + serializer_class=self.__class__.__name__ + ), + ) + + if fields == ALL_FIELDS: + fields = None + + if fields is not None: + # Ensure that all declared fields have also been included in the + # `Meta.fields` option. + + # Do not require any fields that are declared in a parent class, + # in order to allow serializer subclasses to only include + # a subset of fields. + required_field_names = set(declared_fields) + for cls in self.__class__.__bases__: + required_field_names -= set(getattr(cls, '_declared_fields', [])) + + for field_name in required_field_names: + assert field_name in fields, ( + "The field '{field_name}' was declared on serializer " + "{serializer_class}, but has not been included in the " + "'fields' option.".format( + field_name=field_name, + serializer_class=self.__class__.__name__ + ) + ) + return fields + + # Use the default set of field names if `Meta.fields` is not specified. + fields = self.get_default_field_names(declared_fields, info) + + if exclude is not None: + # If `Meta.exclude` is included, then remove those fields. + for field_name in exclude: + assert field_name not in self._declared_fields, ( + "Cannot both declare the field '{field_name}' and include " + "it in the {serializer_class} 'exclude' option. Remove the " + "field or, if inherited from a parent serializer, disable " + "with `{field_name} = None`." + .format( + field_name=field_name, + serializer_class=self.__class__.__name__ + ) + ) + + assert field_name in fields, ( + "The field '{field_name}' was included on serializer " + "{serializer_class} in the 'exclude' option, but does " + "not match any model field.".format( + field_name=field_name, + serializer_class=self.__class__.__name__ + ) + ) + fields.remove(field_name) + + return fields + + def get_default_field_names(self, declared_fields, model_info): + """ + Return the default list of field names that will be used if the + `Meta.fields` option is not specified. + """ + return ( + [model_info.pk.name] + + list(declared_fields) + + list(model_info.fields) + + list(model_info.forward_relations) + ) + + # Methods for constructing serializer fields... + + def build_field(self, field_name, info, model_class, nested_depth): + """ + Return a two tuple of (cls, kwargs) to build a serializer field with. + """ + if field_name in info.fields_and_pk: + model_field = info.fields_and_pk[field_name] + return self.build_standard_field(field_name, model_field) + + elif field_name in info.relations: + relation_info = info.relations[field_name] + if not nested_depth: + return self.build_relational_field(field_name, relation_info) + else: + return self.build_nested_field(field_name, relation_info, nested_depth) + + elif hasattr(model_class, field_name): + return self.build_property_field(field_name, model_class) + + elif field_name == self.url_field_name: + return self.build_url_field(field_name, model_class) + + return self.build_unknown_field(field_name, model_class) + + def build_standard_field(self, field_name, model_field): + """ + Create regular model fields. + """ + field_mapping = ClassLookupDict(self.serializer_field_mapping) + + field_class = field_mapping[model_field] + field_kwargs = get_field_kwargs(field_name, model_field) + + # Special case to handle when a OneToOneField is also the primary key + if model_field.one_to_one and model_field.primary_key: + field_class = self.serializer_related_field + field_kwargs['queryset'] = model_field.related_model.objects + + if 'choices' in field_kwargs: + # Fields with choices get coerced into `ChoiceField` + # instead of using their regular typed field. + field_class = self.serializer_choice_field + # Some model fields may introduce kwargs that would not be valid + # for the choice field. We need to strip these out. + # Eg. models.DecimalField(max_digits=3, decimal_places=1, choices=DECIMAL_CHOICES) + valid_kwargs = { + 'read_only', 'write_only', + 'required', 'default', 'initial', 'source', + 'label', 'help_text', 'style', + 'error_messages', 'validators', 'allow_null', 'allow_blank', + 'choices' + } + for key in list(field_kwargs): + if key not in valid_kwargs: + field_kwargs.pop(key) + + if not issubclass(field_class, ModelField): + # `model_field` is only valid for the fallback case of + # `ModelField`, which is used when no other typed field + # matched to the model field. + field_kwargs.pop('model_field', None) + + if not issubclass(field_class, CharField) and not issubclass(field_class, ChoiceField): + # `allow_blank` is only valid for textual fields. + field_kwargs.pop('allow_blank', None) + + is_django_jsonfield = hasattr(models, 'JSONField') and isinstance(model_field, models.JSONField) + if (postgres_fields and isinstance(model_field, postgres_fields.JSONField)) or is_django_jsonfield: + # Populate the `encoder` argument of `JSONField` instances generated + # for the model `JSONField`. + field_kwargs['encoder'] = getattr(model_field, 'encoder', None) + if is_django_jsonfield: + field_kwargs['decoder'] = getattr(model_field, 'decoder', None) + + if postgres_fields and isinstance(model_field, postgres_fields.ArrayField): + # Populate the `child` argument on `ListField` instances generated + # for the PostgreSQL specific `ArrayField`. + child_model_field = model_field.base_field + child_field_class, child_field_kwargs = self.build_standard_field( + 'child', child_model_field + ) + field_kwargs['child'] = child_field_class(**child_field_kwargs) + + return field_class, field_kwargs + + def build_relational_field(self, field_name, relation_info): + """ + Create fields for forward and reverse relationships. + """ + field_class = self.serializer_related_field + field_kwargs = get_relation_kwargs(field_name, relation_info) + + to_field = field_kwargs.pop('to_field', None) + if to_field and not relation_info.reverse and not relation_info.related_model._meta.get_field(to_field).primary_key: + field_kwargs['slug_field'] = to_field + field_class = self.serializer_related_to_field + + # `view_name` is only valid for hyperlinked relationships. + if not issubclass(field_class, HyperlinkedRelatedField): + field_kwargs.pop('view_name', None) + + return field_class, field_kwargs + + def build_nested_field(self, field_name, relation_info, nested_depth): + """ + Create nested fields for forward and reverse relationships. + """ + class NestedSerializer(ModelSerializer): + class Meta: + model = relation_info.related_model + depth = nested_depth - 1 + fields = '__all__' + + field_class = NestedSerializer + field_kwargs = get_nested_relation_kwargs(relation_info) + + return field_class, field_kwargs + + def build_property_field(self, field_name, model_class): + """ + Create a read only field for model methods and properties. + """ + field_class = ReadOnlyField + field_kwargs = {} + + return field_class, field_kwargs + + def build_url_field(self, field_name, model_class): + """ + Create a field representing the object's own URL. + """ + field_class = self.serializer_url_field + field_kwargs = get_url_kwargs(model_class) + + return field_class, field_kwargs + + def build_unknown_field(self, field_name, model_class): + """ + Raise an error on any unknown fields. + """ + raise ImproperlyConfigured( + 'Field name `%s` is not valid for model `%s`.' % + (field_name, model_class.__name__) + ) + + def include_extra_kwargs(self, kwargs, extra_kwargs): + """ + Include any 'extra_kwargs' that have been included for this field, + possibly removing any incompatible existing keyword arguments. + """ + if extra_kwargs.get('read_only', False): + for attr in [ + 'required', 'default', 'allow_blank', 'min_length', + 'max_length', 'min_value', 'max_value', 'validators', 'queryset' + ]: + kwargs.pop(attr, None) + + if extra_kwargs.get('default') and kwargs.get('required') is False: + kwargs.pop('required') + + if extra_kwargs.get('read_only', kwargs.get('read_only', False)): + extra_kwargs.pop('required', None) # Read only fields should always omit the 'required' argument. + + kwargs.update(extra_kwargs) + + return kwargs + + # Methods for determining additional keyword arguments to apply... + + def get_extra_kwargs(self): + """ + Return a dictionary mapping field names to a dictionary of + additional keyword arguments. + """ + extra_kwargs = copy.deepcopy(getattr(self.Meta, 'extra_kwargs', {})) + + read_only_fields = getattr(self.Meta, 'read_only_fields', None) + if read_only_fields is not None: + if not isinstance(read_only_fields, (list, tuple)): + raise TypeError( + 'The `read_only_fields` option must be a list or tuple. ' + 'Got %s.' % type(read_only_fields).__name__ + ) + for field_name in read_only_fields: + kwargs = extra_kwargs.get(field_name, {}) + kwargs['read_only'] = True + extra_kwargs[field_name] = kwargs + + else: + # Guard against the possible misspelling `readonly_fields` (used + # by the Django admin and others). + assert not hasattr(self.Meta, 'readonly_fields'), ( + 'Serializer `%s.%s` has field `readonly_fields`; ' + 'the correct spelling for the option is `read_only_fields`.' % + (self.__class__.__module__, self.__class__.__name__) + ) + + return extra_kwargs + + def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs): + """ + Return any additional field options that need to be included as a + result of uniqueness constraints on the model. This is returned as + a two-tuple of: + + ('dict of updated extra kwargs', 'mapping of hidden fields') + """ + if getattr(self.Meta, 'validators', None) is not None: + return (extra_kwargs, {}) + + model = getattr(self.Meta, 'model') + model_fields = self._get_model_fields( + field_names, declared_fields, extra_kwargs + ) + + # Determine if we need any additional `HiddenField` or extra keyword + # arguments to deal with `unique_for` dates that are required to + # be in the input data in order to validate it. + unique_constraint_names = set() + + for model_field in model_fields.values(): + # Include each of the `unique_for_*` field names. + unique_constraint_names |= {model_field.unique_for_date, model_field.unique_for_month, + model_field.unique_for_year} + + unique_constraint_names -= {None} + + # Include each of the `unique_together` field names, + # so long as all the field names are included on the serializer. + for parent_class in [model] + list(model._meta.parents): + for unique_together_list in parent_class._meta.unique_together: + if set(field_names).issuperset(unique_together_list): + unique_constraint_names |= set(unique_together_list) + + # Now we have all the field names that have uniqueness constraints + # applied, we can add the extra 'required=...' or 'default=...' + # arguments that are appropriate to these fields, or add a `HiddenField` for it. + hidden_fields = {} + uniqueness_extra_kwargs = {} + + for unique_constraint_name in unique_constraint_names: + # Get the model field that is referred too. + unique_constraint_field = model._meta.get_field(unique_constraint_name) + + if getattr(unique_constraint_field, 'auto_now_add', None): + default = CreateOnlyDefault(timezone.now) + elif getattr(unique_constraint_field, 'auto_now', None): + default = timezone.now + elif unique_constraint_field.has_default(): + default = unique_constraint_field.default + else: + default = empty + + if unique_constraint_name in model_fields: + # The corresponding field is present in the serializer + if default is empty: + uniqueness_extra_kwargs[unique_constraint_name] = {'required': True} + else: + uniqueness_extra_kwargs[unique_constraint_name] = {'default': default} + elif default is not empty: + # The corresponding field is not present in the + # serializer. We have a default to use for it, so + # add in a hidden field that populates it. + hidden_fields[unique_constraint_name] = HiddenField(default=default) + + # Update `extra_kwargs` with any new options. + for key, value in uniqueness_extra_kwargs.items(): + if key in extra_kwargs: + value.update(extra_kwargs[key]) + extra_kwargs[key] = value + + return extra_kwargs, hidden_fields + + def _get_model_fields(self, field_names, declared_fields, extra_kwargs): + """ + Returns all the model fields that are being mapped to by fields + on the serializer class. + Returned as a dict of 'model field name' -> 'model field'. + Used internally by `get_uniqueness_field_options`. + """ + model = getattr(self.Meta, 'model') + model_fields = {} + + for field_name in field_names: + if field_name in declared_fields: + # If the field is declared on the serializer + field = declared_fields[field_name] + source = field.source or field_name + else: + try: + source = extra_kwargs[field_name]['source'] + except KeyError: + source = field_name + + if '.' in source or source == '*': + # Model fields will always have a simple source mapping, + # they can't be nested attribute lookups. + continue + + try: + field = model._meta.get_field(source) + if isinstance(field, DjangoModelField): + model_fields[source] = field + except FieldDoesNotExist: + pass + + return model_fields + + # Determine the validators to apply... + + def get_validators(self): + """ + Determine the set of validators to use when instantiating serializer. + """ + # If the validators have been declared explicitly then use that. + validators = getattr(getattr(self, 'Meta', None), 'validators', None) + if validators is not None: + return list(validators) + + # Otherwise use the default set of validators. + return ( + self.get_unique_together_validators() + + self.get_unique_for_date_validators() + ) + + def get_unique_together_validators(self): + """ + Determine a default set of validators for any unique_together constraints. + """ + model_class_inheritance_tree = ( + [self.Meta.model] + + list(self.Meta.model._meta.parents) + ) + + # The field names we're passing though here only include fields + # which may map onto a model field. Any dotted field name lookups + # cannot map to a field, and must be a traversal, so we're not + # including those. + field_sources = OrderedDict( + (field.field_name, field.source) for field in self._writable_fields + if (field.source != '*') and ('.' not in field.source) + ) + + # Special Case: Add read_only fields with defaults. + field_sources.update(OrderedDict( + (field.field_name, field.source) for field in self.fields.values() + if (field.read_only) and (field.default != empty) and (field.source != '*') and ('.' not in field.source) + )) + + # Invert so we can find the serializer field names that correspond to + # the model field names in the unique_together sets. This also allows + # us to check that multiple fields don't map to the same source. + source_map = defaultdict(list) + for name, source in field_sources.items(): + source_map[source].append(name) + + # Note that we make sure to check `unique_together` both on the + # base model class, but also on any parent classes. + validators = [] + for parent_class in model_class_inheritance_tree: + for unique_together in parent_class._meta.unique_together: + # Skip if serializer does not map to all unique together sources + if not set(source_map).issuperset(unique_together): + continue + + for source in unique_together: + assert len(source_map[source]) == 1, ( + "Unable to create `UniqueTogetherValidator` for " + "`{model}.{field}` as `{serializer}` has multiple " + "fields ({fields}) that map to this model field. " + "Either remove the extra fields, or override " + "`Meta.validators` with a `UniqueTogetherValidator` " + "using the desired field names." + .format( + model=self.Meta.model.__name__, + serializer=self.__class__.__name__, + field=source, + fields=', '.join(source_map[source]), + ) + ) + + field_names = tuple(source_map[f][0] for f in unique_together) + validator = UniqueTogetherValidator( + queryset=parent_class._default_manager, + fields=field_names + ) + validators.append(validator) + return validators + + def get_unique_for_date_validators(self): + """ + Determine a default set of validators for the following constraints: + + * unique_for_date + * unique_for_month + * unique_for_year + """ + info = model_meta.get_field_info(self.Meta.model) + default_manager = self.Meta.model._default_manager + field_names = [field.source for field in self.fields.values()] + + validators = [] + + for field_name, field in info.fields_and_pk.items(): + if field.unique_for_date and field_name in field_names: + validator = UniqueForDateValidator( + queryset=default_manager, + field=field_name, + date_field=field.unique_for_date + ) + validators.append(validator) + + if field.unique_for_month and field_name in field_names: + validator = UniqueForMonthValidator( + queryset=default_manager, + field=field_name, + date_field=field.unique_for_month + ) + validators.append(validator) + + if field.unique_for_year and field_name in field_names: + validator = UniqueForYearValidator( + queryset=default_manager, + field=field_name, + date_field=field.unique_for_year + ) + validators.append(validator) + + return validators + + +class HyperlinkedModelSerializer(ModelSerializer): + """ + A type of `ModelSerializer` that uses hyperlinked relationships instead + of primary key relationships. Specifically: + + * A 'url' field is included instead of the 'id' field. + * Relationships to other instances are hyperlinks, instead of primary keys. + """ + serializer_related_field = HyperlinkedRelatedField + + def get_default_field_names(self, declared_fields, model_info): + """ + Return the default list of field names that will be used if the + `Meta.fields` option is not specified. + """ + return ( + [self.url_field_name] + + list(declared_fields) + + list(model_info.fields) + + list(model_info.forward_relations) + ) + + def build_nested_field(self, field_name, relation_info, nested_depth): + """ + Create nested fields for forward and reverse relationships. + """ + class NestedSerializer(HyperlinkedModelSerializer): + class Meta: + model = relation_info.related_model + depth = nested_depth - 1 + fields = '__all__' + + field_class = NestedSerializer + field_kwargs = get_nested_relation_kwargs(relation_info) + + return field_class, field_kwargs diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/settings.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..9eb4c5653b20f6314782f6a03122270ca3937290 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/settings.py @@ -0,0 +1,256 @@ +""" +Settings for REST framework are all namespaced in the REST_FRAMEWORK setting. +For example your project's `settings.py` file might look like this: + +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': [ + 'rest_framework.renderers.JSONRenderer', + 'rest_framework.renderers.TemplateHTMLRenderer', + ], + 'DEFAULT_PARSER_CLASSES': [ + 'rest_framework.parsers.JSONParser', + 'rest_framework.parsers.FormParser', + 'rest_framework.parsers.MultiPartParser', + ], +} + +This module provides the `api_setting` object, that is used to access +REST framework settings, checking for user settings first, then falling +back to the defaults. +""" +from django.conf import settings +from django.test.signals import setting_changed +from django.utils.module_loading import import_string + +from rest_framework import ISO_8601 + +DEFAULTS = { + # Base API policies + 'DEFAULT_RENDERER_CLASSES': [ + 'rest_framework.renderers.JSONRenderer', + 'rest_framework.renderers.BrowsableAPIRenderer', + ], + 'DEFAULT_PARSER_CLASSES': [ + 'rest_framework.parsers.JSONParser', + 'rest_framework.parsers.FormParser', + 'rest_framework.parsers.MultiPartParser' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.BasicAuthentication' + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.AllowAny', + ], + 'DEFAULT_THROTTLE_CLASSES': [], + 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation', + 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata', + 'DEFAULT_VERSIONING_CLASS': None, + + # Generic view behavior + 'DEFAULT_PAGINATION_CLASS': None, + 'DEFAULT_FILTER_BACKENDS': [], + + # Schema + 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema', + + # Throttling + 'DEFAULT_THROTTLE_RATES': { + 'user': None, + 'anon': None, + }, + 'NUM_PROXIES': None, + + # Pagination + 'PAGE_SIZE': None, + + # Filtering + 'SEARCH_PARAM': 'search', + 'ORDERING_PARAM': 'ordering', + + # Versioning + 'DEFAULT_VERSION': None, + 'ALLOWED_VERSIONS': None, + 'VERSION_PARAM': 'version', + + # Authentication + 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', + 'UNAUTHENTICATED_TOKEN': None, + + # View configuration + 'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name', + 'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description', + + # Exception handling + 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', + 'NON_FIELD_ERRORS_KEY': 'non_field_errors', + + # Testing + 'TEST_REQUEST_RENDERER_CLASSES': [ + 'rest_framework.renderers.MultiPartRenderer', + 'rest_framework.renderers.JSONRenderer' + ], + 'TEST_REQUEST_DEFAULT_FORMAT': 'multipart', + + # Hyperlink settings + 'URL_FORMAT_OVERRIDE': 'format', + 'FORMAT_SUFFIX_KWARG': 'format', + 'URL_FIELD_NAME': 'url', + + # Input and output formats + 'DATE_FORMAT': ISO_8601, + 'DATE_INPUT_FORMATS': [ISO_8601], + + 'DATETIME_FORMAT': ISO_8601, + 'DATETIME_INPUT_FORMATS': [ISO_8601], + + 'TIME_FORMAT': ISO_8601, + 'TIME_INPUT_FORMATS': [ISO_8601], + + # Encoding + 'UNICODE_JSON': True, + 'COMPACT_JSON': True, + 'STRICT_JSON': True, + 'COERCE_DECIMAL_TO_STRING': True, + 'UPLOADED_FILES_USE_URL': True, + + # Browseable API + 'HTML_SELECT_CUTOFF': 1000, + 'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...", + + # Schemas + 'SCHEMA_COERCE_PATH_PK': True, + 'SCHEMA_COERCE_METHOD_NAMES': { + 'retrieve': 'read', + 'destroy': 'delete' + }, +} + + +# List of settings that may be in string import notation. +IMPORT_STRINGS = [ + 'DEFAULT_RENDERER_CLASSES', + 'DEFAULT_PARSER_CLASSES', + 'DEFAULT_AUTHENTICATION_CLASSES', + 'DEFAULT_PERMISSION_CLASSES', + 'DEFAULT_THROTTLE_CLASSES', + 'DEFAULT_CONTENT_NEGOTIATION_CLASS', + 'DEFAULT_METADATA_CLASS', + 'DEFAULT_VERSIONING_CLASS', + 'DEFAULT_PAGINATION_CLASS', + 'DEFAULT_FILTER_BACKENDS', + 'DEFAULT_SCHEMA_CLASS', + 'EXCEPTION_HANDLER', + 'TEST_REQUEST_RENDERER_CLASSES', + 'UNAUTHENTICATED_USER', + 'UNAUTHENTICATED_TOKEN', + 'VIEW_NAME_FUNCTION', + 'VIEW_DESCRIPTION_FUNCTION' +] + + +# List of settings that have been removed +REMOVED_SETTINGS = [ + 'PAGINATE_BY', 'PAGINATE_BY_PARAM', 'MAX_PAGINATE_BY', +] + + +def perform_import(val, setting_name): + """ + If the given setting is a string import notation, + then perform the necessary import or imports. + """ + if val is None: + return None + elif isinstance(val, str): + return import_from_string(val, setting_name) + elif isinstance(val, (list, tuple)): + return [import_from_string(item, setting_name) for item in val] + return val + + +def import_from_string(val, setting_name): + """ + Attempt to import a class from a string representation. + """ + try: + return import_string(val) + except ImportError as e: + msg = "Could not import '%s' for API setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e) + raise ImportError(msg) + + +class APISettings: + """ + A settings object that allows REST Framework settings to be accessed as + properties. For example: + + from rest_framework.settings import api_settings + print(api_settings.DEFAULT_RENDERER_CLASSES) + + Any setting with string import paths will be automatically resolved + and return the class, rather than the string literal. + + Note: + This is an internal class that is only compatible with settings namespaced + under the REST_FRAMEWORK name. It is not intended to be used by 3rd-party + apps, and test helpers like `override_settings` may not work as expected. + """ + def __init__(self, user_settings=None, defaults=None, import_strings=None): + if user_settings: + self._user_settings = self.__check_user_settings(user_settings) + self.defaults = defaults or DEFAULTS + self.import_strings = import_strings or IMPORT_STRINGS + self._cached_attrs = set() + + @property + def user_settings(self): + if not hasattr(self, '_user_settings'): + self._user_settings = getattr(settings, 'REST_FRAMEWORK', {}) + return self._user_settings + + def __getattr__(self, attr): + if attr not in self.defaults: + raise AttributeError("Invalid API setting: '%s'" % attr) + + try: + # Check if present in user settings + val = self.user_settings[attr] + except KeyError: + # Fall back to defaults + val = self.defaults[attr] + + # Coerce import strings into classes + if attr in self.import_strings: + val = perform_import(val, attr) + + # Cache the result + self._cached_attrs.add(attr) + setattr(self, attr, val) + return val + + def __check_user_settings(self, user_settings): + SETTINGS_DOC = "https://www.django-rest-framework.org/api-guide/settings/" + for setting in REMOVED_SETTINGS: + if setting in user_settings: + raise RuntimeError("The '%s' setting has been removed. Please refer to '%s' for available settings." % (setting, SETTINGS_DOC)) + return user_settings + + def reload(self): + for attr in self._cached_attrs: + delattr(self, attr) + self._cached_attrs.clear() + if hasattr(self, '_user_settings'): + delattr(self, '_user_settings') + + +api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) + + +def reload_api_settings(*args, **kwargs): + setting = kwargs['setting'] + if setting == 'REST_FRAMEWORK': + api_settings.reload() + + +setting_changed.connect(reload_api_settings) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css new file mode 100644 index 0000000000000000000000000000000000000000..2a69f48c7f5badb22c914953a6b49d6fbf3df9ba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x;background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x;background-color:#2e6da4}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} +/*# sourceMappingURL=bootstrap-theme.min.css.map */ \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css.map b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css.map new file mode 100644 index 0000000000000000000000000000000000000000..5d75106e042b7a66107a0d44abea854895076733 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-theme.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap-theme.css","dist/css/bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAAA;;;;ACUA,YCWA,aDbA,UAFA,aACA,aAEA,aCkBE,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,iBF7CV,mBANA,mBACA,oBCWE,oBDRF,iBANA,iBAIA,oBANA,oBAOA,oBANA,oBAQA,oBANA,oBEmDE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBFpCV,qBAMA,sBCJE,sBDDF,uBAHA,mBAMA,oBARA,sBAMA,uBALA,sBAMA,uBAJA,sBAMA,uBAOA,+BALA,gCAGA,6BAFA,gCACA,gCAEA,gCEwBE,mBAAA,KACQ,WAAA,KFfV,mBCnCA,oBDiCA,iBAFA,oBACA,oBAEA,oBCXI,YAAA,KDgBJ,YCyBE,YAEE,iBAAA,KAKJ,aEvEI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QAyCA,YAAA,EAAA,IAAA,EAAA,KACA,aAAA,KDnBF,mBCrBE,mBAEE,iBAAA,QACA,oBAAA,EAAA,MDuBJ,oBCpBE,oBAEE,iBAAA,QACA,aAAA,QAMA,sBD8BJ,6BANA,4BAGA,6BANA,4BAHA,4BAFA,uBAeA,8BANA,6BAGA,8BANA,6BAHA,6BAFA,gCAeA,uCANA,sCAGA,uCANA,sCAHA,sCCdM,iBAAA,QACA,iBAAA,KAoBN,aE5EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QDgEF,mBC9DE,mBAEE,iBAAA,QACA,oBAAA,EAAA,MDgEJ,oBC7DE,oBAEE,iBAAA,QACA,aAAA,QAMA,sBDuEJ,6BANA,4BAGA,6BANA,4BAHA,4BAFA,uBAeA,8BANA,6BAGA,8BANA,6BAHA,6BAFA,gCAeA,uCANA,sCAGA,uCANA,sCAHA,sCCvDM,iBAAA,QACA,iBAAA,KAqBN,aE7EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QDyGF,mBCvGE,mBAEE,iBAAA,QACA,oBAAA,EAAA,MDyGJ,oBCtGE,oBAEE,iBAAA,QACA,aAAA,QAMA,sBDgHJ,6BANA,4BAGA,6BANA,4BAHA,4BAFA,uBAeA,8BANA,6BAGA,8BANA,6BAHA,6BAFA,gCAeA,uCANA,sCAGA,uCANA,sCAHA,sCChGM,iBAAA,QACA,iBAAA,KAsBN,UE9EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QDkJF,gBChJE,gBAEE,iBAAA,QACA,oBAAA,EAAA,MDkJJ,iBC/IE,iBAEE,iBAAA,QACA,aAAA,QAMA,mBDyJJ,0BANA,yBAGA,0BANA,yBAHA,yBAFA,oBAeA,2BANA,0BAGA,2BANA,0BAHA,0BAFA,6BAeA,oCANA,mCAGA,oCANA,mCAHA,mCCzIM,iBAAA,QACA,iBAAA,KAuBN,aE/EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QD2LF,mBCzLE,mBAEE,iBAAA,QACA,oBAAA,EAAA,MD2LJ,oBCxLE,oBAEE,iBAAA,QACA,aAAA,QAMA,sBDkMJ,6BANA,4BAGA,6BANA,4BAHA,4BAFA,uBAeA,8BANA,6BAGA,8BANA,6BAHA,6BAFA,gCAeA,uCANA,sCAGA,uCANA,sCAHA,sCClLM,iBAAA,QACA,iBAAA,KAwBN,YEhFI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GClBF,OAAA,0DH8CA,kBAAA,SACA,aAAA,QDoOF,kBClOE,kBAEE,iBAAA,QACA,oBAAA,EAAA,MDoOJ,mBCjOE,mBAEE,iBAAA,QACA,aAAA,QAMA,qBD2OJ,4BANA,2BAGA,4BANA,2BAHA,2BAFA,sBAeA,6BANA,4BAGA,6BANA,4BAHA,4BAFA,+BAeA,sCANA,qCAGA,sCANA,qCAHA,qCC3NM,iBAAA,QACA,iBAAA,KD2ON,eC5MA,WCtCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBFsPV,0BCvMA,0BEjGI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFgGF,iBAAA,QAEF,yBD6MA,+BADA,+BGlTI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsGF,iBAAA,QASF,gBEnHI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,kBAAA,SCnBF,OAAA,0DHqIA,cAAA,ICrEA,mBAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,iBFuRV,sCCtNA,oCEnHI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD6CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD8EV,cDoNA,iBClNE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEtII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,kBAAA,SCnBF,OAAA,0DHwJA,cAAA,IDyNF,sCC5NA,oCEtII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD6CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDoFV,8BDuOA,iCC3NI,YAAA,EAAA,KAAA,EAAA,gBDgOJ,qBADA,kBC1NA,mBAGE,cAAA,EAIF,yBAEI,mDDwNF,yDADA,yDCpNI,MAAA,KEnKF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UF2KJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC/HA,mBAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,CAAA,EAAA,IAAA,IAAA,gBD0IV,eE5LI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoLF,aAAA,QAKF,YE7LI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoLF,aAAA,QAMF,eE9LI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoLF,aAAA,QAOF,cE/LI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoLF,aAAA,QAeF,UEvMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6MJ,cEjNI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8MJ,sBElNI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,mBEnNI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFgNJ,sBEpNI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiNJ,qBErNI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFqNJ,sBExLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKF+LJ,YACE,cAAA,IClLA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDoLV,wBDiQA,8BADA,8BC7PE,YAAA,EAAA,KAAA,EAAA,QEzOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuOF,aAAA,QALF,+BD6QA,qCADA,qCCpQI,YAAA,KAUJ,OCvME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBDgNV,8BElQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+PJ,8BEnQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFgQJ,8BEpQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiQJ,2BErQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFkQJ,8BEtQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFmQJ,6BEvQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0QJ,ME9QI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4QF,aAAA,QC/NA,mBAAA,MAAA,EAAA,IAAA,IAAA,eAAA,CAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,eAAA,CAAA,EAAA,IAAA,EAAA","sourcesContent":["/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-repeat: repeat-x;\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n background-repeat: repeat-x;\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n background-repeat: repeat-x;\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n background-repeat: repeat-x;\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n background-repeat: repeat-x;\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n background-repeat: repeat-x;\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n background-repeat: repeat-x;\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n background-repeat: repeat-x;\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n background-repeat: repeat-x;\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n background-repeat: repeat-x;\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));\n background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-repeat: repeat-x;\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8));\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n background-repeat: repeat-x;\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n background-repeat: repeat-x;\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n background-repeat: repeat-x;\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n background-repeat: repeat-x;\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n background-repeat: repeat-x;\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n background-repeat: repeat-x;\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n background-repeat: repeat-x;\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n background-repeat: repeat-x;\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n background-repeat: repeat-x;\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n background-repeat: repeat-x;\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n background-repeat: repeat-x;\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// stylelint-disable selector-no-qualifying-type, selector-max-compound-selectors\n\n/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);\n @shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0, 0, 0, .125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default {\n .btn-styles(@btn-default-bg);\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0, 0, 0, .075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0, 0, 0, .075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, .25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0, 0, 0, .25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, .2);\n @shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0, 0, 0, .075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0, 0, 0, .05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n .box-shadow(@shadow);\n}\n","// stylelint-disable indentation, property-no-vendor-prefix, selector-no-vendor-prefix\n\n// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n word-wrap: break-word;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// stylelint-disable value-no-vendor-prefix, selector-max-id\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\", argb(@start-color), argb(@end-color))); // IE9 and down\n background-repeat: repeat-x;\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\", argb(@start-color), argb(@end-color))); // IE9 and down\n background-repeat: repeat-x;\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\", argb(@start-color), argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n background-repeat: no-repeat;\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\", argb(@start-color), argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n background-repeat: no-repeat;\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255, 255, 255, .15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-tweaks.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-tweaks.css new file mode 100644 index 0000000000000000000000000000000000000000..c2fcb303d919997fa47ed13606c3411d11b9927b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap-tweaks.css @@ -0,0 +1,233 @@ +/* + +This CSS file contains some tweaks specific to the included Bootstrap theme. +It's separate from `style.css` so that it can be easily overridden by replacing +a single block in the template. + +*/ + +.form-actions { + background: transparent; + border-top-color: transparent; + padding-top: 0; + text-align: right; +} + +#generic-content-form textarea { + font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; + font-size: 80%; +} + +.navbar-inverse .brand a { + color: #999999; +} +.navbar-inverse .brand:hover a { + color: white; + text-decoration: none; +} + +/* custom navigation styles */ +.navbar { + width: 100%; + position: fixed; + left: 0; + top: 0; +} + +.navbar { + background: #2C2C2C; + color: white; + border: none; + border-top: 5px solid #A30000; + border-radius: 0px; +} + +.navbar .nav li, .navbar .nav li a, .navbar .brand:hover { + color: white; +} + +.nav-list > .active > a, .nav-list > .active > a:hover { + background: #2C2C2C; +} + +.navbar .dropdown-menu li a, .navbar .dropdown-menu li { + color: #A30000; +} + +.navbar .dropdown-menu li a:hover { + background: #EEEEEE; + color: #C20000; +} + +ul.breadcrumb { + margin: 70px 0 0 0; +} + +.breadcrumb li.active a { + color: #777; +} + +.pagination>.disabled>a, +.pagination>.disabled>a:hover, +.pagination>.disabled>a:focus { + cursor: not-allowed; + pointer-events: none; +} + +.pager>.disabled>a, +.pager>.disabled>a:hover, +.pager>.disabled>a:focus { + pointer-events: none; +} + +.pager .next { + margin-left: 10px; +} + +/*=== dabapps bootstrap styles ====*/ + +html { + width:100%; + background: none; +} + +/*body, .navbar .container-fluid { + max-width: 1150px; + margin: 0 auto; +}*/ + +body { + background: url("../img/grid.png") repeat-x; + background-attachment: fixed; +} + +#content { + margin: 0; + padding-bottom: 60px; +} + +/* sticky footer and footer */ +html, body { + height: 100%; +} + +.wrapper { + position: relative; + top: 0; + left: 0; + padding-top: 60px; + margin: -60px 0; + min-height: 100%; +} + +.form-switcher { + margin-bottom: 0; +} + +.well { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.well .form-actions { + padding-bottom: 0; + margin-bottom: 0; +} + +.well form { + margin-bottom: 0; +} + +.nav-tabs { + border: 0; +} + +.nav-tabs > li { + float: right; +} + +.nav-tabs li a { + margin-right: 0; +} + +.nav-tabs > .active > a { + background: #F5F5F5; +} + +.nav-tabs > .active > a:hover { + background: #F5F5F5; +} + +.tabbable.first-tab-active .tab-content { + border-top-right-radius: 0; +} + +footer { + position: absolute; + bottom: 0; + left: 0; + clear: both; + z-index: 10; + height: 60px; + width: 95%; + margin: 0 2.5%; +} + +footer p { + text-align: center; + color: gray; + border-top: 1px solid #DDDDDD; + padding-top: 10px; +} + +footer a { + color: gray !important; + font-weight: bold; +} + +footer a:hover { + color: gray; +} + +.page-header { + border-bottom: none; + padding-bottom: 0px; + margin: 0; +} + +/* custom general page styles */ +.hero-unit h1, .hero-unit h2 { + color: #A30000; +} + +body a { + color: #A30000; +} + +body a:hover { + color: #c20000; +} + +.request-info { + clear:both; +} + +.horizontal-checkbox label { + padding-top: 0; +} + +.horizontal-checkbox label { + padding-top: 0 !important; +} + +.horizontal-checkbox input { + float: left; + width: 20px; + margin-top: 3px; +} + +.modal-footer form { + margin-left: 5px; + margin-right: 5px; +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css new file mode 100644 index 0000000000000000000000000000000000000000..5b96335ff6a02021199d731eaa19ccadd1dc8af8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:"Glyphicons Halflings";src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/glyphicons-halflings-regular.woff2) format("woff2"),url(../fonts/glyphicons-halflings-regular.woff) format("woff"),url(../fonts/glyphicons-halflings-regular.ttf) format("truetype"),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format("svg")}.glyphicon{position:relative;top:1px;display:inline-block;font-family:"Glyphicons Halflings";font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:"\2014 \00A0"}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:""}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:"\00A0 \2014"}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.row-no-gutters{margin-right:0;margin-left:0}.row-no-gutters [class*=col-]{padding-right:0;padding-left:0}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s,-webkit-box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);opacity:.65;-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;background-image:none;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;background-image:none;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;background-image:none;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;background-image:none;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;background-image:none;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-right:15px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-right:-15px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover>.arrow{border-width:11px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;filter:alpha(opacity=90);opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203a"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css.map b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css.map new file mode 100644 index 0000000000000000000000000000000000000000..0ae3de50864d93c1f79a4e659641a5d248bca2bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap.css","less/normalize.less","dist/css/bootstrap.css","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA;;;;AAKA,4ECKA,KACE,YAAA,WACA,qBAAA,KACA,yBAAA,KAOF,KACE,OAAA,EAaF,QCnBA,MACA,QACA,WACA,OACA,OACA,OACA,OACA,KACA,KACA,IACA,QACA,QDqBE,QAAA,MAQF,MCzBA,OACA,SACA,MD2BE,QAAA,aACA,eAAA,SAQF,sBACE,QAAA,KACA,OAAA,EAQF,SCrCA,SDuCE,QAAA,KAUF,EACE,iBAAA,YAQF,SCnDA,QDqDE,QAAA,EAWF,YACE,cAAA,KACA,gBAAA,UACA,wBAAA,UAAA,OAAA,qBAAA,UAAA,OAAA,gBAAA,UAAA,OAOF,EC/DA,ODiEE,YAAA,IAOF,IACE,WAAA,OAQF,GACE,UAAA,IACA,OAAA,MAAA,EAOF,KACE,WAAA,KACA,MAAA,KAOF,MACE,UAAA,IAOF,ICzFA,ID2FE,UAAA,IACA,YAAA,EACA,SAAA,SACA,eAAA,SAGF,IACE,IAAA,MAGF,IACE,OAAA,OAUF,IACE,OAAA,EAOF,eACE,SAAA,OAUF,OACE,OAAA,IAAA,KAOF,GACE,mBAAA,YAAA,gBAAA,YAAA,WAAA,YACA,OAAA,EAOF,IACE,SAAA,KAOF,KC7HA,IACA,IACA,KD+HE,YAAA,SAAA,CAAA,UACA,UAAA,IAkBF,OC7IA,MACA,SACA,OACA,SD+IE,MAAA,QACA,KAAA,QACA,OAAA,EAOF,OACE,SAAA,QAUF,OC1JA,OD4JE,eAAA,KAWF,OCnKA,wBACA,kBACA,mBDqKE,mBAAA,OACA,OAAA,QAOF,iBCxKA,qBD0KE,OAAA,QAOF,yBC7KA,wBD+KE,OAAA,EACA,QAAA,EAQF,MACE,YAAA,OAWF,qBC5LA,kBD8LE,mBAAA,WAAA,gBAAA,WAAA,WAAA,WACA,QAAA,EASF,8CCjMA,8CDmME,OAAA,KAQF,mBACE,mBAAA,UACA,mBAAA,YAAA,gBAAA,YAAA,WAAA,YASF,iDC5MA,8CD8ME,mBAAA,KAOF,SACE,OAAA,IAAA,MAAA,OACA,OAAA,EAAA,IACA,QAAA,MAAA,OAAA,MAQF,OACE,OAAA,EACA,QAAA,EAOF,SACE,SAAA,KAQF,SACE,YAAA,IAUF,MACE,gBAAA,SACA,eAAA,EAGF,GC3OA,GD6OE,QAAA,EDlPF,qFGhLA,aACE,ED2LA,OADA,QCvLE,MAAA,eACA,YAAA,eACA,WAAA,cACA,mBAAA,eAAA,WAAA,eAGF,ED0LA,UCxLE,gBAAA,UAGF,cACE,QAAA,KAAA,WAAA,IAGF,kBACE,QAAA,KAAA,YAAA,IAKF,mBDqLA,6BCnLE,QAAA,GDuLF,WCpLA,IAEE,OAAA,IAAA,MAAA,KACA,kBAAA,MAGF,MACE,QAAA,mBDqLF,IClLA,GAEE,kBAAA,MAGF,IACE,UAAA,eDmLF,GACA,GCjLA,EAGE,QAAA,EACA,OAAA,EAGF,GD+KA,GC7KE,iBAAA,MAMF,QACE,QAAA,KAEF,YD2KA,oBCxKI,iBAAA,eAGJ,OACE,OAAA,IAAA,MAAA,KAGF,OACE,gBAAA,mBADF,UD2KA,UCtKI,iBAAA,eD0KJ,mBCvKA,mBAGI,OAAA,IAAA,MAAA,gBCrFN,WACE,YAAA,uBACA,IAAA,+CACA,IAAA,sDAAA,2BAAA,CAAA,iDAAA,eAAA,CAAA,gDAAA,cAAA,CAAA,+CAAA,kBAAA,CAAA,2EAAA,cAQF,WACE,SAAA,SACA,IAAA,IACA,QAAA,aACA,YAAA,uBACA,WAAA,OACA,YAAA,IACA,YAAA,EACA,uBAAA,YACA,wBAAA,UAIkC,2BAAW,QAAA,QACX,uBAAW,QAAA,QF2P/C,sBEzPoC,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,qBAAW,QAAA,QACX,0BAAW,QAAA,QACX,qBAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,sBAAW,QAAA,QACX,yBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,+BAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,gCAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,gCAAW,QAAA,QACX,gCAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,0BAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,mCAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,sBAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,0BAAW,QAAA,QACX,4BAAW,QAAA,QACX,qCAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,mCAAW,QAAA,QACX,uCAAW,QAAA,QACX,gCAAW,QAAA,QACX,oCAAW,QAAA,QACX,qCAAW,QAAA,QACX,yCAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,iCAAW,QAAA,QACX,oCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,qBAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QASX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,+BAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,mCAAW,QAAA,QACX,4BAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,kCAAW,QAAA,QACX,mCAAW,QAAA,QACX,sCAAW,QAAA,QACX,0CAAW,QAAA,QACX,oCAAW,QAAA,QACX,wCAAW,QAAA,QACX,qCAAW,QAAA,QACX,iCAAW,QAAA,QACX,gCAAW,QAAA,QACX,kCAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,0BAAW,QAAA,QCxS/C,ECkEE,mBAAA,WACG,gBAAA,WACK,WAAA,WJo+BV,OGriCA,QC+DE,mBAAA,WACG,gBAAA,WACK,WAAA,WDzDV,KACE,UAAA,KACA,4BAAA,cAGF,KACE,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,iBAAA,KHoiCF,OGhiCA,MHiiCA,OACA,SG9hCE,YAAA,QACA,UAAA,QACA,YAAA,QAMF,EACE,MAAA,QACA,gBAAA,KH8hCF,QG5hCE,QAEE,MAAA,QACA,gBAAA,UAGF,QEnDA,QAAA,IAAA,KAAA,yBACA,eAAA,KF6DF,OACE,OAAA,EAMF,IACE,eAAA,OHqhCF,4BADA,0BGhhCA,gBH+gCA,iBADA,eMxlCE,QAAA,MACA,UAAA,KACA,OAAA,KH6EF,aACE,cAAA,IAMF,eACE,QAAA,IACA,YAAA,WACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IC+FA,mBAAA,IAAA,IAAA,YACK,cAAA,IAAA,IAAA,YACG,WAAA,IAAA,IAAA,YE5LR,QAAA,aACA,UAAA,KACA,OAAA,KHiGF,YACE,cAAA,IAMF,GACE,WAAA,KACA,cAAA,KACA,OAAA,EACA,WAAA,IAAA,MAAA,KAQF,SACE,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EACA,OAAA,KACA,SAAA,OACA,KAAA,cACA,OAAA,EAQA,0BH8/BF,yBG5/BI,SAAA,OACA,MAAA,KACA,OAAA,KACA,OAAA,EACA,SAAA,QACA,KAAA,KAWJ,cACE,OAAA,QH4/BF,IACA,IACA,IACA,IACA,IACA,IOtpCA,GP4oCA,GACA,GACA,GACA,GACA,GO9oCE,YAAA,QACA,YAAA,IACA,YAAA,IACA,MAAA,QPyqCF,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UACA,UOxqCA,SPyqCA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SOxpCI,YAAA,IACA,YAAA,EACA,MAAA,KP8qCJ,IAEA,IAEA,IO9qCA,GP2qCA,GAEA,GO1qCE,WAAA,KACA,cAAA,KPqrCF,WANA,UAQA,WANA,UAQA,WANA,UACA,UOxrCA,SP0rCA,UANA,SAQA,UANA,SO9qCI,UAAA,IPyrCJ,IAEA,IAEA,IO1rCA,GPurCA,GAEA,GOtrCE,WAAA,KACA,cAAA,KPisCF,WANA,UAQA,WANA,UAQA,WANA,UACA,UOpsCA,SPssCA,UANA,SAQA,UANA,SO1rCI,UAAA,IPqsCJ,IOjsCA,GAAU,UAAA,KPqsCV,IOpsCA,GAAU,UAAA,KPwsCV,IOvsCA,GAAU,UAAA,KP2sCV,IO1sCA,GAAU,UAAA,KP8sCV,IO7sCA,GAAU,UAAA,KPitCV,IOhtCA,GAAU,UAAA,KAMV,EACE,OAAA,EAAA,EAAA,KAGF,MACE,cAAA,KACA,UAAA,KACA,YAAA,IACA,YAAA,IAEA,yBAAA,MACE,UAAA,MPitCJ,OOxsCA,MAEE,UAAA,IP0sCF,MOvsCA,KAEE,QAAA,KACA,iBAAA,QAIF,WAAuB,WAAA,KACvB,YAAuB,WAAA,MACvB,aAAuB,WAAA,OACvB,cAAuB,WAAA,QACvB,aAAuB,YAAA,OAGvB,gBAAuB,eAAA,UACvB,gBAAuB,eAAA,UACvB,iBAAuB,eAAA,WAGvB,YACE,MAAA,KAEF,cCvGE,MAAA,QR2zCF,qBQ1zCE,qBAEE,MAAA,QDuGJ,cC1GE,MAAA,QRk0CF,qBQj0CE,qBAEE,MAAA,QD0GJ,WC7GE,MAAA,QRy0CF,kBQx0CE,kBAEE,MAAA,QD6GJ,cChHE,MAAA,QRg1CF,qBQ/0CE,qBAEE,MAAA,QDgHJ,aCnHE,MAAA,QRu1CF,oBQt1CE,oBAEE,MAAA,QDuHJ,YAGE,MAAA,KE7HA,iBAAA,QT+1CF,mBS91CE,mBAEE,iBAAA,QF6HJ,YEhIE,iBAAA,QTs2CF,mBSr2CE,mBAEE,iBAAA,QFgIJ,SEnIE,iBAAA,QT62CF,gBS52CE,gBAEE,iBAAA,QFmIJ,YEtIE,iBAAA,QTo3CF,mBSn3CE,mBAEE,iBAAA,QFsIJ,WEzIE,iBAAA,QT23CF,kBS13CE,kBAEE,iBAAA,QF8IJ,aACE,eAAA,IACA,OAAA,KAAA,EAAA,KACA,cAAA,IAAA,MAAA,KPgvCF,GOxuCA,GAEE,WAAA,EACA,cAAA,KP4uCF,MAFA,MACA,MO9uCA,MAMI,cAAA,EAOJ,eACE,aAAA,EACA,WAAA,KAIF,aALE,aAAA,EACA,WAAA,KAMA,YAAA,KAFF,gBAKI,QAAA,aACA,cAAA,IACA,aAAA,IAKJ,GACE,WAAA,EACA,cAAA,KPouCF,GOluCA,GAEE,YAAA,WAEF,GACE,YAAA,IAEF,GACE,YAAA,EAaA,yBAAA,kBAEI,MAAA,KACA,MAAA,MACA,MAAA,KACA,WAAA,MGxNJ,SAAA,OACA,cAAA,SACA,YAAA,OHiNA,kBASI,YAAA,OP4tCN,0BOjtCA,YAEE,OAAA,KAGF,YACE,UAAA,IA9IqB,eAAA,UAmJvB,WACE,QAAA,KAAA,KACA,OAAA,EAAA,EAAA,KACA,UAAA,OACA,YAAA,IAAA,MAAA,KPitCF,yBO5sCI,wBP2sCJ,yBO1sCM,cAAA,EPgtCN,kBO1tCA,kBPytCA,iBOtsCI,QAAA,MACA,UAAA,IACA,YAAA,WACA,MAAA,KP4sCJ,yBO1sCI,yBPysCJ,wBOxsCM,QAAA,cAQN,oBPqsCA,sBOnsCE,cAAA,KACA,aAAA,EACA,WAAA,MACA,aAAA,IAAA,MAAA,KACA,YAAA,EP0sCF,kCOpsCI,kCPksCJ,iCAGA,oCAJA,oCAEA,mCOnsCe,QAAA,GP4sCf,iCO3sCI,iCPysCJ,gCAGA,mCAJA,mCAEA,kCOzsCM,QAAA,cAMN,QACE,cAAA,KACA,WAAA,OACA,YAAA,WIxSF,KXm/CA,IACA,IACA,KWj/CE,YAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,aAAA,CAAA,UAIF,KACE,QAAA,IAAA,IACA,UAAA,IACA,MAAA,QACA,iBAAA,QACA,cAAA,IAIF,IACE,QAAA,IAAA,IACA,UAAA,IACA,MAAA,KACA,iBAAA,KACA,cAAA,IACA,mBAAA,MAAA,EAAA,KAAA,EAAA,gBAAA,WAAA,MAAA,EAAA,KAAA,EAAA,gBANF,QASI,QAAA,EACA,UAAA,KACA,YAAA,IACA,mBAAA,KAAA,WAAA,KAKJ,IACE,QAAA,MACA,QAAA,MACA,OAAA,EAAA,EAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,WAAA,UACA,UAAA,WACA,iBAAA,QACA,OAAA,IAAA,MAAA,KACA,cAAA,IAXF,SAeI,QAAA,EACA,UAAA,QACA,MAAA,QACA,YAAA,SACA,iBAAA,YACA,cAAA,EAKJ,gBACE,WAAA,MACA,WAAA,OC1DF,WCHE,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KDGA,yBAAA,WACE,MAAA,OAEF,yBAAA,WACE,MAAA,OAEF,0BAAA,WACE,MAAA,QAUJ,iBCvBE,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KD6BF,KCvBE,aAAA,MACA,YAAA,MD0BF,gBACE,aAAA,EACA,YAAA,EAFF,8BAKI,cAAA,EACA,aAAA,EZwiDJ,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAjCA,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAjCA,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UatnDC,UbynDD,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UcpmDM,SAAA,SAEA,WAAA,IAEA,cAAA,KACA,aAAA,KDtBL,UbmpDD,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,Uc3mDM,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,EFCJ,yBCzEC,Ub2zDC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UcnxDI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GFUJ,yBClFC,Ubo+DC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,Uc57DI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GFmBJ,0BC3FC,Ub6oEC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UcrmEI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GCjEJ,MACE,iBAAA,YADF,uBAQI,SAAA,OACA,QAAA,aACA,MAAA,KAKA,sBf+xEJ,sBe9xEM,SAAA,OACA,QAAA,WACA,MAAA,KAKN,QACE,YAAA,IACA,eAAA,IACA,MAAA,KACA,WAAA,KAGF,GACE,WAAA,KAMF,OACE,MAAA,KACA,UAAA,KACA,cAAA,Kf6xEF,mBAHA,mBAIA,mBAHA,mBACA,mBe/xEA,mBAWQ,QAAA,IACA,YAAA,WACA,eAAA,IACA,WAAA,IAAA,MAAA,KAdR,mBAoBI,eAAA,OACA,cAAA,IAAA,MAAA,KfyxEJ,uCe9yEA,uCf+yEA,wCAHA,wCAIA,2CAHA,2Ce/wEQ,WAAA,EA9BR,mBAoCI,WAAA,IAAA,MAAA,KApCJ,cAyCI,iBAAA,KfoxEJ,6BAHA,6BAIA,6BAHA,6BACA,6Be5wEA,6BAOQ,QAAA,IAWR,gBACE,OAAA,IAAA,MAAA,KfqwEF,4BAHA,4BAIA,4BAHA,4BACA,4BerwEA,4BAQQ,OAAA,IAAA,MAAA,KfmwER,4Be3wEA,4BAeM,oBAAA,IAUN,yCAEI,iBAAA,QASJ,4BAEI,iBAAA,QfqvEJ,0BAGA,0BATA,0BAGA,0BAIA,0BAGA,0BATA,0BAGA,0BACA,0BAGA,0BgBt4EE,0BhBg4EF,0BgBz3EM,iBAAA,QhBs4EN,sCAEA,sCADA,oCgBj4EE,sChB+3EF,sCgBz3EM,iBAAA,QhBs4EN,2BAGA,2BATA,2BAGA,2BAIA,2BAGA,2BATA,2BAGA,2BACA,2BAGA,2BgB35EE,2BhBq5EF,2BgB94EM,iBAAA,QhB25EN,uCAEA,uCADA,qCgBt5EE,uChBo5EF,uCgB94EM,iBAAA,QhB25EN,wBAGA,wBATA,wBAGA,wBAIA,wBAGA,wBATA,wBAGA,wBACA,wBAGA,wBgBh7EE,wBhB06EF,wBgBn6EM,iBAAA,QhBg7EN,oCAEA,oCADA,kCgB36EE,oChBy6EF,oCgBn6EM,iBAAA,QhBg7EN,2BAGA,2BATA,2BAGA,2BAIA,2BAGA,2BATA,2BAGA,2BACA,2BAGA,2BgBr8EE,2BhB+7EF,2BgBx7EM,iBAAA,QhBq8EN,uCAEA,uCADA,qCgBh8EE,uChB87EF,uCgBx7EM,iBAAA,QhBq8EN,0BAGA,0BATA,0BAGA,0BAIA,0BAGA,0BATA,0BAGA,0BACA,0BAGA,0BgB19EE,0BhBo9EF,0BgB78EM,iBAAA,QhB09EN,sCAEA,sCADA,oCgBr9EE,sChBm9EF,sCgB78EM,iBAAA,QDoJN,kBACE,WAAA,KACA,WAAA,KAEA,oCAAA,kBACE,MAAA,KACA,cAAA,KACA,WAAA,OACA,mBAAA,yBACA,OAAA,IAAA,MAAA,KALF,yBASI,cAAA,Efq0EJ,qCAHA,qCAIA,qCAHA,qCACA,qCe70EA,qCAkBU,YAAA,OAlBV,kCA0BI,OAAA,Ef+zEJ,0DAHA,0DAIA,0DAHA,0DACA,0Dex1EA,0DAmCU,YAAA,Ef8zEV,yDAHA,yDAIA,yDAHA,yDACA,yDeh2EA,yDAuCU,aAAA,Efg0EV,yDev2EA,yDfw2EA,yDAFA,yDelzEU,cAAA,GEzNZ,SAIE,UAAA,EACA,QAAA,EACA,OAAA,EACA,OAAA,EAGF,OACE,QAAA,MACA,MAAA,KACA,QAAA,EACA,cAAA,KACA,UAAA,KACA,YAAA,QACA,MAAA,KACA,OAAA,EACA,cAAA,IAAA,MAAA,QAGF,MACE,QAAA,aACA,UAAA,KACA,cAAA,IACA,YAAA,IAUF,mBb6BE,mBAAA,WACG,gBAAA,WACK,WAAA,WarBR,mBAAA,KACA,gBAAA,KAAA,WAAA,KjBkgFF,qBiB9/EA,kBAEE,OAAA,IAAA,EAAA,EACA,WAAA,MACA,YAAA,OjBogFF,wCADA,qCADA,8BAFA,+BACA,2BiB3/EE,4BAGE,OAAA,YAIJ,iBACE,QAAA,MAIF,kBACE,QAAA,MACA,MAAA,KAIF,iBjBu/EA,aiBr/EE,OAAA,KjB0/EF,2BiBt/EA,uBjBq/EA,wBK/kFE,QAAA,IAAA,KAAA,yBACA,eAAA,KYgGF,OACE,QAAA,MACA,YAAA,IACA,UAAA,KACA,YAAA,WACA,MAAA,KA0BF,cACE,QAAA,MACA,MAAA,KACA,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,iBAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,Ib3EA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBAyHR,mBAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KACK,cAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KACG,mBAAA,aAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,Kc1IR,oBACE,aAAA,QACA,QAAA,EdYF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,qBAiCR,gCACE,MAAA,KACA,QAAA,EAEF,oCAA0B,MAAA,KAC1B,yCAAgC,MAAA,Ka+ChC,0BACE,iBAAA,YACA,OAAA,EAQF,wBjBq+EF,wBACA,iCiBn+EI,iBAAA,KACA,QAAA,EAGF,wBjBo+EF,iCiBl+EI,OAAA,YAIF,sBACE,OAAA,KAcJ,qDAKI,8BjBm9EF,wCACA,+BAFA,8BiBj9EI,YAAA,KjB09EJ,iCAEA,2CACA,kCAFA,iCiBx9EE,0BjBq9EF,oCACA,2BAFA,0BiBl9EI,YAAA,KjB+9EJ,iCAEA,2CACA,kCAFA,iCiB79EE,0BjB09EF,oCACA,2BAFA,0BiBv9EI,YAAA,MAWN,YACE,cAAA,KjBy9EF,UiBj9EA,OAEE,SAAA,SACA,QAAA,MACA,WAAA,KACA,cAAA,KjBm9EF,yBiBh9EE,sBjBk9EF,mCADA,gCiB98EM,OAAA,YjBm9EN,gBiB99EA,aAgBI,WAAA,KACA,aAAA,KACA,cAAA,EACA,YAAA,IACA,OAAA,QjBm9EJ,+BACA,sCiBj9EA,yBjB+8EA,gCiB38EE,SAAA,SACA,WAAA,MACA,YAAA,MjBi9EF,oBiB98EA,cAEE,WAAA,KjBg9EF,iBiB58EA,cAEE,SAAA,SACA,QAAA,aACA,aAAA,KACA,cAAA,EACA,YAAA,IACA,eAAA,OACA,OAAA,QjB88EF,0BiB38EE,uBjB68EF,oCADA,iCiB18EI,OAAA,YjB+8EJ,kCiB58EA,4BAEE,WAAA,EACA,YAAA,KASF,qBACE,WAAA,KAEA,YAAA,IACA,eAAA,IAEA,cAAA,EAEA,8BjBm8EF,8BiBj8EI,cAAA,EACA,aAAA,EAaJ,UC3PE,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IAEA,gBACE,OAAA,KACA,YAAA,KlBsrFJ,0BkBnrFE,kBAEE,OAAA,KDiPJ,6BAEI,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IANJ,mCASI,OAAA,KACA,YAAA,KjBq8EJ,6CiB/8EA,qCAcI,OAAA,KAdJ,oCAiBI,OAAA,KACA,WAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IAIJ,UCvRE,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IAEA,gBACE,OAAA,KACA,YAAA,KlB2tFJ,0BkBxtFE,kBAEE,OAAA,KD6QJ,6BAEI,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IANJ,mCASI,OAAA,KACA,YAAA,KjB88EJ,6CiBx9EA,qCAcI,OAAA,KAdJ,oCAiBI,OAAA,KACA,WAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UASJ,cAEE,SAAA,SAFF,4BAMI,cAAA,OAIJ,uBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,QAAA,EACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,YAAA,KACA,WAAA,OACA,eAAA,KjBo8EF,oDADA,uCiBj8EA,iCAGE,MAAA,KACA,OAAA,KACA,YAAA,KjBo8EF,oDADA,uCiBj8EA,iCAGE,MAAA,KACA,OAAA,KACA,YAAA,KjBq8EF,uBAEA,8BAJA,4BiB/7EA,yBjBg8EA,oBAEA,2BAGA,4BAEA,mCAHA,yBAEA,gCkBx1FI,MAAA,QDkZJ,2BC9YI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,iCACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,Qa4VV,gCCpYI,MAAA,QACA,iBAAA,QACA,aAAA,QDkYJ,oCC9XI,MAAA,QlB61FJ,uBAEA,8BAJA,4BiB19EA,yBjB29EA,oBAEA,2BAGA,4BAEA,mCAHA,yBAEA,gCkBt3FI,MAAA,QDqZJ,2BCjZI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,iCACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,Qa+VV,gCCvYI,MAAA,QACA,iBAAA,QACA,aAAA,QDqYJ,oCCjYI,MAAA,QlB23FJ,qBAEA,4BAJA,0BiBr/EA,uBjBs/EA,kBAEA,yBAGA,0BAEA,iCAHA,uBAEA,8BkBp5FI,MAAA,QDwZJ,yBCpZI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,+BACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QakWV,8BC1YI,MAAA,QACA,iBAAA,QACA,aAAA,QDwYJ,kCCpYI,MAAA,QD2YF,2CACE,IAAA,KAEF,mDACE,IAAA,EAUJ,YACE,QAAA,MACA,WAAA,IACA,cAAA,KACA,MAAA,QAkBA,yBAAA,yBAGI,QAAA,aACA,cAAA,EACA,eAAA,OALJ,2BAUI,QAAA,aACA,MAAA,KACA,eAAA,OAZJ,kCAiBI,QAAA,aAjBJ,0BAqBI,QAAA,aACA,eAAA,OjBi/EJ,wCiBvgFA,6CjBsgFA,2CiB3+EM,MAAA,KA3BN,wCAiCI,MAAA,KAjCJ,4BAqCI,cAAA,EACA,eAAA,OjB4+EJ,uBiBlhFA,oBA6CI,QAAA,aACA,WAAA,EACA,cAAA,EACA,eAAA,OjBy+EJ,6BiBzhFA,0BAmDM,aAAA,EjB0+EN,4CiB7hFA,sCAwDI,SAAA,SACA,YAAA,EAzDJ,kDA8DI,IAAA,GjBw+EN,2BAEA,kCiB/9EA,wBjB89EA,+BiBr9EI,YAAA,IACA,WAAA,EACA,cAAA,EjB09EJ,2BiBr+EA,wBAiBI,WAAA,KAjBJ,6BJ9gBE,aAAA,MACA,YAAA,MIwiBA,yBAAA,gCAEI,YAAA,IACA,cAAA,EACA,WAAA,OA/BN,sDAwCI,MAAA,KAQA,yBAAA,+CAEI,YAAA,KACA,UAAA,MAKJ,yBAAA,+CAEI,YAAA,IACA,UAAA,ME9kBR,KACE,QAAA,aACA,cAAA,EACA,YAAA,IACA,WAAA,OACA,YAAA,OACA,eAAA,OACA,iBAAA,aAAA,aAAA,aACA,OAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,YCoCA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,cAAA,IhBqKA,oBAAA,KACG,iBAAA,KACC,gBAAA,KACI,YAAA,KJs1FV,kBAHA,kBACA,WACA,kBAHA,kBmB1hGI,WdrBF,QAAA,IAAA,KAAA,yBACA,eAAA,KLwjGF,WADA,WmB7hGE,WAGE,MAAA,KACA,gBAAA,KnB+hGJ,YmB5hGE,YAEE,iBAAA,KACA,QAAA,Ef2BF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBexBR,cnB4hGF,eACA,wBmB1hGI,OAAA,YE9CF,OAAA,kBACA,QAAA,IjBiEA,mBAAA,KACQ,WAAA,KefN,enB4hGJ,yBmB1hGM,eAAA,KASN,aC7DE,MAAA,KACA,iBAAA,KACA,aAAA,KpBqlGF,mBoBnlGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpBqlGJ,oBoBnlGE,oBpBolGF,mCoBjlGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB2lGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoBrlGI,0BpB0lGJ,yCAHA,yCAHA,yCoBjlGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBgmGN,4BAHA,4BoBvlGI,4BpB2lGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBnlGM,iBAAA,KACA,aAAA,KDuBN,oBClBI,MAAA,KACA,iBAAA,KDoBJ,aChEE,MAAA,KACA,iBAAA,QACA,aAAA,QpB0oGF,mBoBxoGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB0oGJ,oBoBxoGE,oBpByoGF,mCoBtoGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBgpGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoB1oGI,0BpB+oGJ,yCAHA,yCAHA,yCoBtoGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBqpGN,4BAHA,4BoB5oGI,4BpBgpGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBxoGM,iBAAA,QACA,aAAA,QD0BN,oBCrBI,MAAA,QACA,iBAAA,KDwBJ,aCpEE,MAAA,KACA,iBAAA,QACA,aAAA,QpB+rGF,mBoB7rGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB+rGJ,oBoB7rGE,oBpB8rGF,mCoB3rGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBqsGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoB/rGI,0BpBosGJ,yCAHA,yCAHA,yCoB3rGM,MAAA,KACA,iBAAA,QACA,aAAA,QpB0sGN,4BAHA,4BoBjsGI,4BpBqsGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoB7rGM,iBAAA,QACA,aAAA,QD8BN,oBCzBI,MAAA,QACA,iBAAA,KD4BJ,UCxEE,MAAA,KACA,iBAAA,QACA,aAAA,QpBovGF,gBoBlvGE,gBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,gBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpBovGJ,iBoBlvGE,iBpBmvGF,gCoBhvGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB0vGJ,uBAHA,uBAHA,uBAKA,uBAHA,uBoBpvGI,uBpByvGJ,sCAHA,sCAHA,sCoBhvGM,MAAA,KACA,iBAAA,QACA,aAAA,QpB+vGN,yBAHA,yBoBtvGI,yBpB0vGJ,0BAHA,0BAHA,0BAOA,mCAHA,mCAHA,mCoBlvGM,iBAAA,QACA,aAAA,QDkCN,iBC7BI,MAAA,QACA,iBAAA,KDgCJ,aC5EE,MAAA,KACA,iBAAA,QACA,aAAA,QpByyGF,mBoBvyGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpByyGJ,oBoBvyGE,oBpBwyGF,mCoBryGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB+yGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoBzyGI,0BpB8yGJ,yCAHA,yCAHA,yCoBryGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBozGN,4BAHA,4BoB3yGI,4BpB+yGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBvyGM,iBAAA,QACA,aAAA,QDsCN,oBCjCI,MAAA,QACA,iBAAA,KDoCJ,YChFE,MAAA,KACA,iBAAA,QACA,aAAA,QpB81GF,kBoB51GE,kBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,kBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB81GJ,mBoB51GE,mBpB61GF,kCoB11GI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBo2GJ,yBAHA,yBAHA,yBAKA,yBAHA,yBoB91GI,yBpBm2GJ,wCAHA,wCAHA,wCoB11GM,MAAA,KACA,iBAAA,QACA,aAAA,QpBy2GN,2BAHA,2BoBh2GI,2BpBo2GJ,4BAHA,4BAHA,4BAOA,qCAHA,qCAHA,qCoB51GM,iBAAA,QACA,aAAA,QD0CN,mBCrCI,MAAA,QACA,iBAAA,KD6CJ,UACE,YAAA,IACA,MAAA,QACA,cAAA,EAEA,UnBwzGF,iBADA,iBAEA,oBACA,6BmBrzGI,iBAAA,YfnCF,mBAAA,KACQ,WAAA,KeqCR,UnB0zGF,iBADA,gBADA,gBmBpzGI,aAAA,YnB0zGJ,gBmBxzGE,gBAEE,MAAA,QACA,gBAAA,UACA,iBAAA,YnB2zGJ,0BmBvzGI,0BnBwzGJ,mCAFA,mCmBpzGM,MAAA,KACA,gBAAA,KnB0zGN,mBmBjzGA,QC9EE,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IpBm4GF,mBmBpzGA,QClFE,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IpB04GF,mBmBvzGA,QCtFE,QAAA,IAAA,IACA,UAAA,KACA,YAAA,IACA,cAAA,ID2FF,WACE,QAAA,MACA,MAAA,KAIF,sBACE,WAAA,InBuzGF,6BADA,4BmB/yGE,6BACE,MAAA,KG1JJ,MACE,QAAA,ElBoLA,mBAAA,QAAA,KAAA,OACK,cAAA,QAAA,KAAA,OACG,WAAA,QAAA,KAAA,OkBnLR,SACE,QAAA,EAIJ,UACE,QAAA,KAEA,aAAY,QAAA,MACZ,eAAY,QAAA,UACZ,kBAAY,QAAA,gBAGd,YACE,SAAA,SACA,OAAA,EACA,SAAA,OlBsKA,4BAAA,MAAA,CAAA,WACQ,uBAAA,MAAA,CAAA,WAAA,oBAAA,MAAA,CAAA,WAOR,4BAAA,KACQ,uBAAA,KAAA,oBAAA,KAGR,mCAAA,KACQ,8BAAA,KAAA,2BAAA,KmB5MV,OACE,QAAA,aACA,MAAA,EACA,OAAA,EACA,YAAA,IACA,eAAA,OACA,WAAA,IAAA,OACA,WAAA,IAAA,QACA,aAAA,IAAA,MAAA,YACA,YAAA,IAAA,MAAA,YvBu/GF,UuBn/GA,QAEE,SAAA,SAIF,uBACE,QAAA,EAIF,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,IAAA,EACA,OAAA,IAAA,EAAA,EACA,UAAA,KACA,WAAA,KACA,WAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,gBACA,cAAA,InBuBA,mBAAA,EAAA,IAAA,KAAA,iBACQ,WAAA,EAAA,IAAA,KAAA,iBmBlBR,0BACE,MAAA,EACA,KAAA,KAzBJ,wBCzBE,OAAA,IACA,OAAA,IAAA,EACA,SAAA,OACA,iBAAA,QDsBF,oBAmCI,QAAA,MACA,QAAA,IAAA,KACA,MAAA,KACA,YAAA,IACA,YAAA,WACA,MAAA,KACA,YAAA,OvB8+GJ,0BuB5+GI,0BAEE,MAAA,QACA,gBAAA,KACA,iBAAA,QAOJ,yBvBw+GF,+BADA,+BuBp+GI,MAAA,KACA,gBAAA,KACA,iBAAA,QACA,QAAA,EASF,2BvBi+GF,iCADA,iCuB79GI,MAAA,KvBk+GJ,iCuB99GE,iCAEE,gBAAA,KACA,OAAA,YACA,iBAAA,YACA,iBAAA,KEzGF,OAAA,0DF+GF,qBAGI,QAAA,MAHJ,QAQI,QAAA,EAQJ,qBACE,MAAA,EACA,KAAA,KAQF,oBACE,MAAA,KACA,KAAA,EAIF,iBACE,QAAA,MACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,YAAA,OAIF,mBACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,IAIF,2BACE,MAAA,EACA,KAAA,KAQF,evB+7GA,sCuB37GI,QAAA,GACA,WAAA,EACA,cAAA,IAAA,OACA,cAAA,IAAA,QAPJ,uBvBs8GA,8CuB37GI,IAAA,KACA,OAAA,KACA,cAAA,IASJ,yBACE,6BApEA,MAAA,EACA,KAAA,KAmEA,kCA1DA,MAAA,KACA,KAAA,GG1IF,W1BkoHA,oB0BhoHE,SAAA,SACA,QAAA,aACA,eAAA,O1BooHF,yB0BxoHA,gBAMI,SAAA,SACA,MAAA,K1B4oHJ,gCAFA,gCAFA,+BAFA,+BAKA,uBAFA,uBAFA,sB0BroHI,sBAIE,QAAA,EAMN,qB1BooHA,2BACA,2BACA,iC0BjoHI,YAAA,KAKJ,aACE,YAAA,KADF,kB1BmoHA,wBACA,0B0B7nHI,MAAA,KAPJ,kB1BwoHA,wBACA,0B0B7nHI,YAAA,IAIJ,yEACE,cAAA,EAIF,4BACE,YAAA,EACA,mECpDA,wBAAA,EACA,2BAAA,EDwDF,6C1B2nHA,8C2B5qHE,uBAAA,EACA,0BAAA,EDsDF,sBACE,MAAA,KAEF,8DACE,cAAA,EAEF,mE1B0nHA,oE2B/rHE,wBAAA,EACA,2BAAA,ED0EF,oECnEE,uBAAA,EACA,0BAAA,EDuEF,mC1BwnHA,iC0BtnHE,QAAA,EAiBF,iCACE,cAAA,IACA,aAAA,IAEF,oCACE,cAAA,KACA,aAAA,KAKF,iCtB/CE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBsBkDR,0CtBnDA,mBAAA,KACQ,WAAA,KsByDV,YACE,YAAA,EAGF,eACE,aAAA,IAAA,IAAA,EACA,oBAAA,EAGF,uBACE,aAAA,EAAA,IAAA,IAOF,yB1B4lHA,+BACA,oC0BzlHI,QAAA,MACA,MAAA,KACA,MAAA,KACA,UAAA,KAPJ,oCAcM,MAAA,KAdN,8B1BumHA,oCACA,oCACA,0C0BnlHI,WAAA,KACA,YAAA,EAKF,4DACE,cAAA,EAEF,sDC7KA,uBAAA,IACA,wBAAA,IAOA,2BAAA,EACA,0BAAA,EDwKA,sDCjLA,uBAAA,EACA,wBAAA,EAOA,2BAAA,IACA,0BAAA,ID6KF,uEACE,cAAA,EAEF,4E1BqlHA,6E2BtwHE,2BAAA,EACA,0BAAA,EDsLF,6EC/LE,uBAAA,EACA,wBAAA,EDsMF,qBACE,QAAA,MACA,MAAA,KACA,aAAA,MACA,gBAAA,SAJF,0B1BslHA,gC0B/kHI,QAAA,WACA,MAAA,KACA,MAAA,GATJ,qCAYI,MAAA,KAZJ,+CAgBI,KAAA,K1BmlHJ,gD0BlkHA,6C1BmkHA,2DAFA,wD0B5jHM,SAAA,SACA,KAAA,cACA,eAAA,KE1ON,aACE,SAAA,SACA,QAAA,MACA,gBAAA,SAGA,0BACE,MAAA,KACA,cAAA,EACA,aAAA,EATJ,2BAeI,SAAA,SACA,QAAA,EAKA,MAAA,KAEA,MAAA,KACA,cAAA,EAEA,iCACE,QAAA,EAUN,8B5B2xHA,mCACA,sCkBpwHE,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IAEA,oClBswHF,yCACA,4CkBtwHI,OAAA,KACA,YAAA,KlB4wHJ,8CACA,mDACA,sDkB3wHE,sClBuwHF,2CACA,8CkBtwHI,OAAA,KUhCJ,8B5B6yHA,mCACA,sCkB3xHE,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IAEA,oClB6xHF,yCACA,4CkB7xHI,OAAA,KACA,YAAA,KlBmyHJ,8CACA,mDACA,sDkBlyHE,sClB8xHF,2CACA,8CkB7xHI,OAAA,KlBqyHJ,2B4B5zHA,mB5B2zHA,iB4BxzHE,QAAA,W5B8zHF,8D4B5zHE,sD5B2zHF,oD4B1zHI,cAAA,EAIJ,mB5B2zHA,iB4BzzHE,MAAA,GACA,YAAA,OACA,eAAA,OAKF,mBACE,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IAGA,4BACE,QAAA,IAAA,KACA,UAAA,KACA,cAAA,IAEF,4BACE,QAAA,KAAA,KACA,UAAA,KACA,cAAA,I5ByzHJ,wC4B70HA,qCA0BI,WAAA,EAKJ,uC5BkzHA,+BACA,kCACA,6CACA,8CAEA,6DADA,wE2B55HE,wBAAA,EACA,2BAAA,EC8GF,+BACE,aAAA,EAEF,sC5BmzHA,8BAKA,+DADA,oDAHA,iCACA,4CACA,6C2Bh6HE,uBAAA,EACA,0BAAA,ECkHF,8BACE,YAAA,EAKF,iBACE,SAAA,SAGA,UAAA,EACA,YAAA,OALF,sBAUI,SAAA,SAVJ,2BAYM,YAAA,K5BizHN,6BADA,4B4B7yHI,4BAGE,QAAA,EAKJ,kC5B0yHF,wC4BvyHM,aAAA,KAGJ,iC5BwyHF,uC4BryHM,QAAA,EACA,YAAA,KC/JN,KACE,aAAA,EACA,cAAA,EACA,WAAA,KAHF,QAOI,SAAA,SACA,QAAA,MARJ,UAWM,SAAA,SACA,QAAA,MACA,QAAA,KAAA,K7By8HN,gB6Bx8HM,gBAEE,gBAAA,KACA,iBAAA,KAKJ,mBACE,MAAA,K7Bu8HN,yB6Br8HM,yBAEE,MAAA,KACA,gBAAA,KACA,OAAA,YACA,iBAAA,YAOJ,a7Bi8HJ,mBADA,mB6B77HM,iBAAA,KACA,aAAA,QAzCN,kBLLE,OAAA,IACA,OAAA,IAAA,EACA,SAAA,OACA,iBAAA,QKEF,cA0DI,UAAA,KASJ,UACE,cAAA,IAAA,MAAA,KADF,aAGI,MAAA,KAEA,cAAA,KALJ,eASM,aAAA,IACA,YAAA,WACA,OAAA,IAAA,MAAA,YACA,cAAA,IAAA,IAAA,EAAA,EACA,qBACE,aAAA,KAAA,KAAA,KAMF,sB7B86HN,4BADA,4B6B16HQ,MAAA,KACA,OAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,oBAAA,YAKN,wBAqDA,MAAA,KA8BA,cAAA,EAnFA,2BAwDE,MAAA,KAxDF,6BA0DI,cAAA,IACA,WAAA,OA3DJ,iDAgEE,IAAA,KACA,KAAA,KAGF,yBAAA,2BAEI,QAAA,WACA,MAAA,GAHJ,6BAKM,cAAA,GAzEN,6BAuFE,aAAA,EACA,cAAA,IAxFF,kC7Bu8HF,wCADA,wC6Bx2HI,OAAA,IAAA,MAAA,KAGF,yBAAA,6BAEI,cAAA,IAAA,MAAA,KACA,cAAA,IAAA,IAAA,EAAA,EAHJ,kC7Bg3HA,wCADA,wC6Bv2HI,oBAAA,MAhGN,cAEI,MAAA,KAFJ,gBAMM,cAAA,IANN,iBASM,YAAA,IAKA,uB7By8HN,6BADA,6B6Br8HQ,MAAA,KACA,iBAAA,QAQR,gBAEI,MAAA,KAFJ,mBAIM,WAAA,IACA,YAAA,EAYN,eACE,MAAA,KADF,kBAII,MAAA,KAJJ,oBAMM,cAAA,IACA,WAAA,OAPN,wCAYI,IAAA,KACA,KAAA,KAGF,yBAAA,kBAEI,QAAA,WACA,MAAA,GAHJ,oBAKM,cAAA,GASR,oBACE,cAAA,EADF,yBAKI,aAAA,EACA,cAAA,IANJ,8B7By7HA,oCADA,oC6B56HI,OAAA,IAAA,MAAA,KAGF,yBAAA,yBAEI,cAAA,IAAA,MAAA,KACA,cAAA,IAAA,IAAA,EAAA,EAHJ,8B7Bo7HA,oCADA,oC6B36HI,oBAAA,MAUN,uBAEI,QAAA,KAFJ,qBAKI,QAAA,MASJ,yBAEE,WAAA,KF7OA,uBAAA,EACA,wBAAA,EGQF,QACE,SAAA,SACA,WAAA,KACA,cAAA,KACA,OAAA,IAAA,MAAA,YAKA,yBAAA,QACE,cAAA,KAaF,yBAAA,eACE,MAAA,MAeJ,iBACE,cAAA,KACA,aAAA,KACA,WAAA,QACA,WAAA,IAAA,MAAA,YACA,mBAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,WAAA,MAAA,EAAA,IAAA,EAAA,qBAEA,2BAAA,MAEA,oBACE,WAAA,KAGF,yBAAA,iBACE,MAAA,KACA,WAAA,EACA,mBAAA,KAAA,WAAA,KAEA,0BACE,QAAA,gBACA,OAAA,eACA,eAAA,EACA,SAAA,kBAGF,oBACE,WAAA,Q9BknIJ,sC8B7mIE,mC9B4mIF,oC8BzmII,cAAA,EACA,aAAA,G9B+mIN,qB8B1mIA,kBAWE,SAAA,MACA,MAAA,EACA,KAAA,EACA,QAAA,K9BmmIF,sC8BjnIA,mCAGI,WAAA,MAEA,4D9BinIF,sC8BjnIE,mCACE,WAAA,OAWJ,yB9B2mIA,qB8B3mIA,kBACE,cAAA,GAIJ,kBACE,IAAA,EACA,aAAA,EAAA,EAAA,IAEF,qBACE,OAAA,EACA,cAAA,EACA,aAAA,IAAA,EAAA,E9B+mIF,kCAFA,gCACA,4B8BtmIA,0BAII,aAAA,MACA,YAAA,MAEA,yB9BwmIF,kCAFA,gCACA,4B8BvmIE,0BACE,aAAA,EACA,YAAA,GAaN,mBACE,QAAA,KACA,aAAA,EAAA,EAAA,IAEA,yBAAA,mBACE,cAAA,GAOJ,cACE,MAAA,KACA,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,K9B8lIF,oB8B5lIE,oBAEE,gBAAA,KATJ,kBAaI,QAAA,MAGF,yBACE,iC9B0lIF,uC8BxlII,YAAA,OAWN,eACE,SAAA,SACA,MAAA,MACA,QAAA,IAAA,KACA,aAAA,KC9LA,WAAA,IACA,cAAA,ID+LA,iBAAA,YACA,iBAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,IAIA,qBACE,QAAA,EAdJ,yBAmBI,QAAA,MACA,MAAA,KACA,OAAA,IACA,cAAA,IAtBJ,mCAyBI,WAAA,IAGF,yBAAA,eACE,QAAA,MAUJ,YACE,OAAA,MAAA,MADF,iBAII,YAAA,KACA,eAAA,KACA,YAAA,KAGF,yBAAA,iCAGI,SAAA,OACA,MAAA,KACA,MAAA,KACA,WAAA,EACA,iBAAA,YACA,OAAA,EACA,mBAAA,KAAA,WAAA,K9BykIJ,kD8BllIA,sCAYM,QAAA,IAAA,KAAA,IAAA,KAZN,sCAeM,YAAA,K9B0kIN,4C8BzkIM,4CAEE,iBAAA,MAOR,yBAAA,YACE,MAAA,KACA,OAAA,EAFF,eAKI,MAAA,KALJ,iBAOM,YAAA,KACA,eAAA,MAYR,aACE,QAAA,KAAA,KACA,aAAA,MACA,YAAA,MACA,WAAA,IAAA,MAAA,YACA,cAAA,IAAA,MAAA,Y1B5NA,mBAAA,MAAA,EAAA,IAAA,EAAA,oBAAA,CAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,oBAAA,CAAA,EAAA,IAAA,EAAA,qB2BjER,WAAA,IACA,cAAA,Id6cA,yBAAA,yBAGI,QAAA,aACA,cAAA,EACA,eAAA,OALJ,2BAUI,QAAA,aACA,MAAA,KACA,eAAA,OAZJ,kCAiBI,QAAA,aAjBJ,0BAqBI,QAAA,aACA,eAAA,OjB+4HJ,wCiBr6HA,6CjBo6HA,2CiBz4HM,MAAA,KA3BN,wCAiCI,MAAA,KAjCJ,4BAqCI,cAAA,EACA,eAAA,OjB04HJ,uBiBh7HA,oBA6CI,QAAA,aACA,WAAA,EACA,cAAA,EACA,eAAA,OjBu4HJ,6BiBv7HA,0BAmDM,aAAA,EjBw4HN,4CiB37HA,sCAwDI,SAAA,SACA,YAAA,EAzDJ,kDA8DI,IAAA,GaxOF,yBAAA,yBACE,cAAA,IAEA,oCACE,cAAA,GASN,yBAAA,aACE,MAAA,KACA,YAAA,EACA,eAAA,EACA,aAAA,EACA,YAAA,EACA,OAAA,E1BvPF,mBAAA,KACQ,WAAA,M0B+PV,8BACE,WAAA,EHpUA,uBAAA,EACA,wBAAA,EGuUF,mDACE,cAAA,EHzUA,uBAAA,IACA,wBAAA,IAOA,2BAAA,EACA,0BAAA,EG0UF,YChVE,WAAA,IACA,cAAA,IDkVA,mBCnVA,WAAA,KACA,cAAA,KDqVA,mBCtVA,WAAA,KACA,cAAA,KD+VF,aChWE,WAAA,KACA,cAAA,KDkWA,yBAAA,aACE,MAAA,KACA,aAAA,KACA,YAAA,MAaJ,yBACE,aEtWA,MAAA,eFuWA,cE1WA,MAAA,gBF4WE,aAAA,MAFF,4BAKI,aAAA,GAUN,gBACE,iBAAA,QACA,aAAA,QAFF,8BAKI,MAAA,K9BmlIJ,oC8BllII,oCAEE,MAAA,QACA,iBAAA,YATN,6BAcI,MAAA,KAdJ,iCAmBM,MAAA,K9BglIN,uC8B9kIM,uCAEE,MAAA,KACA,iBAAA,YAIF,sC9B6kIN,4CADA,4C8BzkIQ,MAAA,KACA,iBAAA,QAIF,wC9B2kIN,8CADA,8C8BvkIQ,MAAA,KACA,iBAAA,YAOF,oC9BskIN,0CADA,0C8BlkIQ,MAAA,KACA,iBAAA,QAIJ,yBAAA,sDAIM,MAAA,K9BmkIR,4D8BlkIQ,4DAEE,MAAA,KACA,iBAAA,YAIF,2D9BikIR,iEADA,iE8B7jIU,MAAA,KACA,iBAAA,QAIF,6D9B+jIR,mEADA,mE8B3jIU,MAAA,KACA,iBAAA,aA/EZ,+BAuFI,aAAA,K9B4jIJ,qC8B3jII,qCAEE,iBAAA,KA1FN,yCA6FM,iBAAA,KA7FN,iC9B0pIA,6B8BvjII,aAAA,QAnGJ,6BA4GI,MAAA,KACA,mCACE,MAAA,KA9GN,0BAmHI,MAAA,K9BojIJ,gC8BnjII,gCAEE,MAAA,K9BsjIN,0C8BljIM,0C9BmjIN,mDAFA,mD8B/iIQ,MAAA,KAQR,gBACE,iBAAA,KACA,aAAA,QAFF,8BAKI,MAAA,Q9B+iIJ,oC8B9iII,oCAEE,MAAA,KACA,iBAAA,YATN,6BAcI,MAAA,QAdJ,iCAmBM,MAAA,Q9B4iIN,uC8B1iIM,uCAEE,MAAA,KACA,iBAAA,YAIF,sC9ByiIN,4CADA,4C8BriIQ,MAAA,KACA,iBAAA,QAIF,wC9BuiIN,8CADA,8C8BniIQ,MAAA,KACA,iBAAA,YAMF,oC9BmiIN,0CADA,0C8B/hIQ,MAAA,KACA,iBAAA,QAIJ,yBAAA,kEAIM,aAAA,QAJN,0DAOM,iBAAA,QAPN,sDAUM,MAAA,Q9BgiIR,4D8B/hIQ,4DAEE,MAAA,KACA,iBAAA,YAIF,2D9B8hIR,iEADA,iE8B1hIU,MAAA,KACA,iBAAA,QAIF,6D9B4hIR,mEADA,mE8BxhIU,MAAA,KACA,iBAAA,aApFZ,+BA6FI,aAAA,K9BwhIJ,qC8BvhII,qCAEE,iBAAA,KAhGN,yCAmGM,iBAAA,KAnGN,iC9B4nIA,6B8BnhII,aAAA,QAzGJ,6BA6GI,MAAA,QACA,mCACE,MAAA,KA/GN,0BAoHI,MAAA,Q9BqhIJ,gC8BphII,gCAEE,MAAA,K9BuhIN,0C8BnhIM,0C9BohIN,mDAFA,mD8BhhIQ,MAAA,KGtoBR,YACE,QAAA,IAAA,KACA,cAAA,KACA,WAAA,KACA,iBAAA,QACA,cAAA,IALF,eAQI,QAAA,aARJ,yBAWM,QAAA,EAAA,IACA,MAAA,KACA,QAAA,SAbN,oBAkBI,MAAA,KCpBJ,YACE,QAAA,aACA,aAAA,EACA,OAAA,KAAA,EACA,cAAA,IAJF,eAOI,QAAA,OAPJ,iBlCyrJA,oBkC/qJM,SAAA,SACA,MAAA,KACA,QAAA,IAAA,KACA,YAAA,KACA,YAAA,WACA,MAAA,QACA,gBAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KlCorJN,uBkClrJM,uBlCmrJN,0BAFA,0BkC/qJQ,QAAA,EACA,MAAA,QACA,iBAAA,KACA,aAAA,KAGJ,6BlCkrJJ,gCkC/qJQ,YAAA,EPnBN,uBAAA,IACA,0BAAA,IOsBE,4BlCirJJ,+B2BhtJE,wBAAA,IACA,2BAAA,IOwCE,sBlC+qJJ,4BAFA,4BADA,yBAIA,+BAFA,+BkC3qJM,QAAA,EACA,MAAA,KACA,OAAA,QACA,iBAAA,QACA,aAAA,QlCmrJN,wBAEA,8BADA,8BkCxuJA,2BlCsuJA,iCADA,iCkCtqJM,MAAA,KACA,OAAA,YACA,iBAAA,KACA,aAAA,KASN,oBlCqqJA,uBmC7uJM,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UAEF,gCnC+uJJ,mC2B1uJE,uBAAA,IACA,0BAAA,IQAE,+BnC8uJJ,kC2BvvJE,wBAAA,IACA,2BAAA,IO2EF,oBlCgrJA,uBmC7vJM,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IAEF,gCnC+vJJ,mC2B1vJE,uBAAA,IACA,0BAAA,IQAE,+BnC8vJJ,kC2BvwJE,wBAAA,IACA,2BAAA,ISHF,OACE,aAAA,EACA,OAAA,KAAA,EACA,WAAA,OACA,WAAA,KAJF,UAOI,QAAA,OAPJ,YpCuxJA,eoC7wJM,QAAA,aACA,QAAA,IAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,KpCixJN,kBoC/xJA,kBAmBM,gBAAA,KACA,iBAAA,KApBN,epCoyJA,kBoCzwJM,MAAA,MA3BN,mBpCwyJA,sBoCtwJM,MAAA,KAlCN,mBpC6yJA,yBADA,yBAEA,sBoCnwJM,MAAA,KACA,OAAA,YACA,iBAAA,KC9CN,OACE,QAAA,OACA,QAAA,KAAA,KAAA,KACA,UAAA,IACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,eAAA,SACA,cAAA,MrCuzJF,cqCnzJI,cAEE,MAAA,KACA,gBAAA,KACA,OAAA,QAKJ,aACE,QAAA,KAIF,YACE,SAAA,SACA,IAAA,KAOJ,eCtCE,iBAAA,KtCk1JF,2BsC/0JI,2BAEE,iBAAA,QDqCN,eC1CE,iBAAA,QtCy1JF,2BsCt1JI,2BAEE,iBAAA,QDyCN,eC9CE,iBAAA,QtCg2JF,2BsC71JI,2BAEE,iBAAA,QD6CN,YClDE,iBAAA,QtCu2JF,wBsCp2JI,wBAEE,iBAAA,QDiDN,eCtDE,iBAAA,QtC82JF,2BsC32JI,2BAEE,iBAAA,QDqDN,cC1DE,iBAAA,QtCq3JF,0BsCl3JI,0BAEE,iBAAA,QCFN,OACE,QAAA,aACA,UAAA,KACA,QAAA,IAAA,IACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,eAAA,OACA,iBAAA,KACA,cAAA,KAGA,aACE,QAAA,KAIF,YACE,SAAA,SACA,IAAA,KvCq3JJ,0BuCl3JE,eAEE,IAAA,EACA,QAAA,IAAA,IvCo3JJ,cuC/2JI,cAEE,MAAA,KACA,gBAAA,KACA,OAAA,QAKJ,+BvC42JF,4BuC12JI,MAAA,QACA,iBAAA,KAGF,wBACE,MAAA,MAGF,+BACE,aAAA,IAGF,uBACE,YAAA,IC1DJ,WACE,YAAA,KACA,eAAA,KACA,cAAA,KACA,MAAA,QACA,iBAAA,KxCu6JF,ewC56JA,cASI,MAAA,QATJ,aAaI,cAAA,KACA,UAAA,KACA,YAAA,IAfJ,cAmBI,iBAAA,QAGF,sBxCk6JF,4BwCh6JI,cAAA,KACA,aAAA,KACA,cAAA,IA1BJ,sBA8BI,UAAA,KAGF,oCAAA,WACE,YAAA,KACA,eAAA,KAEA,sBxCi6JF,4BwC/5JI,cAAA,KACA,aAAA,KxCm6JJ,ewC16JA,cAYI,UAAA,MC1CN,WACE,QAAA,MACA,QAAA,IACA,cAAA,KACA,YAAA,WACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IrCiLA,mBAAA,OAAA,IAAA,YACK,cAAA,OAAA,IAAA,YACG,WAAA,OAAA,IAAA,YJ+xJV,iByCz9JA,eAaI,aAAA,KACA,YAAA,KzCi9JJ,mBADA,kByC58JE,kBAGE,aAAA,QArBJ,oBA0BI,QAAA,IACA,MAAA,KC3BJ,OACE,QAAA,KACA,cAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,IAJF,UAQI,WAAA,EACA,MAAA,QATJ,mBAcI,YAAA,IAdJ,S1Co/JA,U0Ch+JI,cAAA,EApBJ,WAwBI,WAAA,IASJ,mB1C09JA,mB0Cx9JE,cAAA,KAFF,0B1C89JA,0B0Cx9JI,SAAA,SACA,IAAA,KACA,MAAA,MACA,MAAA,QAQJ,eCvDE,MAAA,QACA,iBAAA,QACA,aAAA,QDqDF,kBClDI,iBAAA,QDkDJ,2BC9CI,MAAA,QDkDJ,YC3DE,MAAA,QACA,iBAAA,QACA,aAAA,QDyDF,eCtDI,iBAAA,QDsDJ,wBClDI,MAAA,QDsDJ,eC/DE,MAAA,QACA,iBAAA,QACA,aAAA,QD6DF,kBC1DI,iBAAA,QD0DJ,2BCtDI,MAAA,QD0DJ,cCnEE,MAAA,QACA,iBAAA,QACA,aAAA,QDiEF,iBC9DI,iBAAA,QD8DJ,0BC1DI,MAAA,QCDJ,wCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAIV,mCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAFV,gCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAQV,UACE,OAAA,KACA,cAAA,KACA,SAAA,OACA,iBAAA,QACA,cAAA,IxCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,eACQ,WAAA,MAAA,EAAA,IAAA,IAAA,ewClCV,cACE,MAAA,KACA,MAAA,GACA,OAAA,KACA,UAAA,KACA,YAAA,KACA,MAAA,KACA,WAAA,OACA,iBAAA,QxCyBA,mBAAA,MAAA,EAAA,KAAA,EAAA,gBACQ,WAAA,MAAA,EAAA,KAAA,EAAA,gBAyHR,mBAAA,MAAA,IAAA,KACK,cAAA,MAAA,IAAA,KACG,WAAA,MAAA,IAAA,KJw6JV,sB4CnjKA,gCCDI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKDEF,wBAAA,KAAA,KAAA,gBAAA,KAAA,K5CwjKF,qB4CjjKA,+BxC5CE,kBAAA,qBAAA,GAAA,OAAA,SACK,aAAA,qBAAA,GAAA,OAAA,SACG,UAAA,qBAAA,GAAA,OAAA,SwCmDV,sBEvEE,iBAAA,QAGA,wCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKDsBJ,mBE3EE,iBAAA,QAGA,qCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKD0BJ,sBE/EE,iBAAA,QAGA,wCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKD8BJ,qBEnFE,iBAAA,QAGA,uCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKExDJ,OAEE,WAAA,KAEA,mBACE,WAAA,EAIJ,O/CqpKA,Y+CnpKE,SAAA,OACA,KAAA,EAGF,YACE,MAAA,QAGF,cACE,QAAA,MAGA,4BACE,UAAA,KAIJ,a/CgpKA,mB+C9oKE,aAAA,KAGF,Y/C+oKA,kB+C7oKE,cAAA,K/CkpKF,Y+C/oKA,Y/C8oKA,a+C3oKE,QAAA,WACA,eAAA,IAGF,cACE,eAAA,OAGF,cACE,eAAA,OAIF,eACE,WAAA,EACA,cAAA,IAMF,YACE,aAAA,EACA,WAAA,KCrDF,YAEE,aAAA,EACA,cAAA,KAQF,iBACE,SAAA,SACA,QAAA,MACA,QAAA,KAAA,KAEA,cAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KAGA,6BrB7BA,uBAAA,IACA,wBAAA,IqB+BA,4BACE,cAAA,ErBzBF,2BAAA,IACA,0BAAA,IqB6BA,0BhDqrKF,gCADA,gCgDjrKI,MAAA,KACA,OAAA,YACA,iBAAA,KALF,mDhD4rKF,yDADA,yDgDlrKM,MAAA,QATJ,gDhDisKF,sDADA,sDgDprKM,MAAA,KAKJ,wBhDqrKF,8BADA,8BgDjrKI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QANF,iDhDisKF,wDAHA,uDADA,uDAMA,8DAHA,6DAJA,uDAMA,8DAHA,6DgDnrKM,MAAA,QAZJ,8ChDwsKF,oDADA,oDgDxrKM,MAAA,QAWN,kBhDkrKA,uBgDhrKE,MAAA,KAFF,2ChDsrKA,gDgDjrKI,MAAA,KhDsrKJ,wBgDlrKE,wBhDmrKF,6BAFA,6BgD/qKI,MAAA,KACA,gBAAA,KACA,iBAAA,QAIJ,uBACE,MAAA,KACA,WAAA,KnCvGD,yBoCIG,MAAA,QACA,iBAAA,QAEA,0BjDuxKJ,+BiDrxKM,MAAA,QAFF,mDjD2xKJ,wDiDtxKQ,MAAA,QjD2xKR,gCiDxxKM,gCjDyxKN,qCAFA,qCiDrxKQ,MAAA,QACA,iBAAA,QAEF,iCjD4xKN,uCAFA,uCADA,sCAIA,4CAFA,4CiDxxKQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,sBoCIG,MAAA,QACA,iBAAA,QAEA,uBjDozKJ,4BiDlzKM,MAAA,QAFF,gDjDwzKJ,qDiDnzKQ,MAAA,QjDwzKR,6BiDrzKM,6BjDszKN,kCAFA,kCiDlzKQ,MAAA,QACA,iBAAA,QAEF,8BjDyzKN,oCAFA,oCADA,mCAIA,yCAFA,yCiDrzKQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,yBoCIG,MAAA,QACA,iBAAA,QAEA,0BjDi1KJ,+BiD/0KM,MAAA,QAFF,mDjDq1KJ,wDiDh1KQ,MAAA,QjDq1KR,gCiDl1KM,gCjDm1KN,qCAFA,qCiD/0KQ,MAAA,QACA,iBAAA,QAEF,iCjDs1KN,uCAFA,uCADA,sCAIA,4CAFA,4CiDl1KQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,wBoCIG,MAAA,QACA,iBAAA,QAEA,yBjD82KJ,8BiD52KM,MAAA,QAFF,kDjDk3KJ,uDiD72KQ,MAAA,QjDk3KR,+BiD/2KM,+BjDg3KN,oCAFA,oCiD52KQ,MAAA,QACA,iBAAA,QAEF,gCjDm3KN,sCAFA,sCADA,qCAIA,2CAFA,2CiD/2KQ,MAAA,KACA,iBAAA,QACA,aAAA,QDiGR,yBACE,WAAA,EACA,cAAA,IAEF,sBACE,cAAA,EACA,YAAA,IExHF,OACE,cAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,I9C0DA,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gB8CtDV,YACE,QAAA,KAKF,eACE,QAAA,KAAA,KACA,cAAA,IAAA,MAAA,YvBtBA,uBAAA,IACA,wBAAA,IuBmBF,0CAMI,MAAA,QAKJ,aACE,WAAA,EACA,cAAA,EACA,UAAA,KACA,MAAA,QlD24KF,oBAEA,sBkDj5KA,elD84KA,mBAEA,qBkDr4KI,MAAA,QAKJ,cACE,QAAA,KAAA,KACA,iBAAA,QACA,WAAA,IAAA,MAAA,KvB1CA,2BAAA,IACA,0BAAA,IuBmDF,mBlD+3KA,mCkD53KI,cAAA,EAHJ,oClDm4KA,oDkD73KM,aAAA,IAAA,EACA,cAAA,EAIF,4DlD63KJ,4EkD33KQ,WAAA,EvBzEN,uBAAA,IACA,wBAAA,IuB8EE,0DlD23KJ,0EkDz3KQ,cAAA,EvBzEN,2BAAA,IACA,0BAAA,IuBmDF,+EvB5DE,uBAAA,EACA,wBAAA,EuB4FF,wDAEI,iBAAA,EAGJ,0BACE,iBAAA,ElDw3KF,8BkDh3KA,clD+2KA,gCkD32KI,cAAA,ElDi3KJ,sCkDr3KA,sBlDo3KA,wCkD72KM,cAAA,KACA,aAAA,KlDk3KN,wDkD13KA,0BvB3GE,uBAAA,IACA,wBAAA,I3B2+KF,yFAFA,yFACA,2DkDh4KA,2DAmBQ,uBAAA,IACA,wBAAA,IlDo3KR,wGAIA,wGANA,wGAIA,wGAHA,0EAIA,0EkD34KA,0ElDy4KA,0EkDj3KU,uBAAA,IlD03KV,uGAIA,uGANA,uGAIA,uGAHA,yEAIA,yEkDr5KA,yElDm5KA,yEkDv3KU,wBAAA,IlD83KV,sDkD15KA,yBvBnGE,2BAAA,IACA,0BAAA,I3BigLF,qFAEA,qFkDj6KA,wDlDg6KA,wDkDv3KQ,2BAAA,IACA,0BAAA,IlD43KR,oGAIA,oGAFA,oGAIA,oGkD56KA,uElDy6KA,uEAFA,uEAIA,uEkD73KU,0BAAA,IlDk4KV,mGAIA,mGAFA,mGAIA,mGkDt7KA,sElDm7KA,sEAFA,sEAIA,sEkDn4KU,2BAAA,IAlDV,0BlD07KA,qCACA,0BACA,qCkDj4KI,WAAA,IAAA,MAAA,KlDq4KJ,kDkDh8KA,kDA+DI,WAAA,EA/DJ,uBlDo8KA,yCkDj4KI,OAAA,ElD44KJ,+CANA,+CAQA,+CANA,+CAEA,+CkD78KA,+ClDg9KA,iEANA,iEAQA,iEANA,iEAEA,iEANA,iEkD93KU,YAAA,ElDm5KV,8CANA,8CAQA,8CANA,8CAEA,8CkD39KA,8ClD89KA,gEANA,gEAQA,gEANA,gEAEA,gEANA,gEkDx4KU,aAAA,ElDu5KV,+CAIA,+CkDz+KA,+ClDu+KA,+CADA,iEAIA,iEANA,iEAIA,iEkDj5KU,cAAA,EAvFV,8ClDi/KA,8CAFA,8CAIA,8CALA,gEAIA,gEAFA,gEAIA,gEkDp5KU,cAAA,EAhGV,yBAsGI,cAAA,EACA,OAAA,EAUJ,aACE,cAAA,KADF,oBAKI,cAAA,EACA,cAAA,IANJ,2BASM,WAAA,IATN,4BAcI,cAAA,ElD04KJ,wDkDx5KA,wDAkBM,WAAA,IAAA,MAAA,KAlBN,2BAuBI,WAAA,EAvBJ,uDAyBM,cAAA,IAAA,MAAA,KAON,eC5PE,aAAA,KAEA,8BACE,MAAA,KACA,iBAAA,QACA,aAAA,KAHF,0DAMI,iBAAA,KANJ,qCASI,MAAA,QACA,iBAAA,KAGJ,yDAEI,oBAAA,KD8ON,eC/PE,aAAA,QAEA,8BACE,MAAA,KACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,KAGJ,yDAEI,oBAAA,QDiPN,eClQE,aAAA,QAEA,8BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,QAGJ,yDAEI,oBAAA,QDoPN,YCrQE,aAAA,QAEA,2BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,uDAMI,iBAAA,QANJ,kCASI,MAAA,QACA,iBAAA,QAGJ,sDAEI,oBAAA,QDuPN,eCxQE,aAAA,QAEA,8BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,QAGJ,yDAEI,oBAAA,QD0PN,cC3QE,aAAA,QAEA,6BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,yDAMI,iBAAA,QANJ,oCASI,MAAA,QACA,iBAAA,QAGJ,wDAEI,oBAAA,QChBN,kBACE,SAAA,SACA,QAAA,MACA,OAAA,EACA,QAAA,EACA,SAAA,OALF,yCpDivLA,wBADA,yBAEA,yBACA,wBoDvuLI,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,KACA,OAAA,KACA,OAAA,EAKJ,wBACE,eAAA,OAIF,uBACE,eAAA,IC3BF,MACE,WAAA,KACA,QAAA,KACA,cAAA,KACA,iBAAA,QACA,OAAA,IAAA,MAAA,QACA,cAAA,IjD0DA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBiDjEV,iBASI,aAAA,KACA,aAAA,gBAKJ,SACE,QAAA,KACA,cAAA,IAEF,SACE,QAAA,IACA,cAAA,ICpBF,OACE,MAAA,MACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,YAAA,EAAA,IAAA,EAAA,KjCTA,OAAA,kBACA,QAAA,GrBkyLF,asDvxLE,aAEE,MAAA,KACA,gBAAA,KACA,OAAA,QjChBF,OAAA,kBACA,QAAA,GiCuBA,aACE,QAAA,EACA,OAAA,QACA,WAAA,IACA,OAAA,EACA,mBAAA,KACA,gBAAA,KAAA,WAAA,KCxBJ,YACE,SAAA,OAIF,OACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,SAAA,OACA,2BAAA,MAIA,QAAA,EAGA,0BnDiHA,kBAAA,kBACI,cAAA,kBACC,aAAA,kBACG,UAAA,kBAkER,mBAAA,kBAAA,IAAA,SAEK,cAAA,aAAA,IAAA,SACG,WAAA,kBAAA,IAAA,SAAA,WAAA,UAAA,IAAA,SAAA,WAAA,UAAA,IAAA,QAAA,CAAA,kBAAA,IAAA,QAAA,CAAA,aAAA,IAAA,SmDrLR,wBnD6GA,kBAAA,eACI,cAAA,eACC,aAAA,eACG,UAAA,emD9GV,mBACE,WAAA,OACA,WAAA,KAIF,cACE,SAAA,SACA,MAAA,KACA,OAAA,KAIF,eACE,SAAA,SACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,eACA,cAAA,InDcA,mBAAA,EAAA,IAAA,IAAA,eACQ,WAAA,EAAA,IAAA,IAAA,emDZR,QAAA,EAIF,gBACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,iBAAA,KAEA,qBlCpEA,OAAA,iBACA,QAAA,EkCoEA,mBlCrEA,OAAA,kBACA,QAAA,GkCyEF,cACE,QAAA,KACA,cAAA,IAAA,MAAA,QAIF,qBACE,WAAA,KAIF,aACE,OAAA,EACA,YAAA,WAKF,YACE,SAAA,SACA,QAAA,KAIF,cACE,QAAA,KACA,WAAA,MACA,WAAA,IAAA,MAAA,QAHF,wBAQI,cAAA,EACA,YAAA,IATJ,mCAaI,YAAA,KAbJ,oCAiBI,YAAA,EAKJ,yBACE,SAAA,SACA,IAAA,QACA,MAAA,KACA,OAAA,KACA,SAAA,OAIF,yBAEE,cACE,MAAA,MACA,OAAA,KAAA,KAEF,enDrEA,mBAAA,EAAA,IAAA,KAAA,eACQ,WAAA,EAAA,IAAA,KAAA,emDyER,UAAY,MAAA,OAGd,yBACE,UAAY,MAAA,OC9Id,SACE,SAAA,SACA,QAAA,KACA,QAAA,MCRA,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,UAAA,OACA,YAAA,ODHA,UAAA,KnCTA,OAAA,iBACA,QAAA,EmCYA,YnCbA,OAAA,kBACA,QAAA,GmCaA,aACE,QAAA,IAAA,EACA,WAAA,KAEF,eACE,QAAA,EAAA,IACA,YAAA,IAEF,gBACE,QAAA,IAAA,EACA,WAAA,IAEF,cACE,QAAA,EAAA,IACA,YAAA,KAIF,4BACE,OAAA,EACA,KAAA,IACA,YAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,iCACE,MAAA,IACA,OAAA,EACA,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,kCACE,OAAA,EACA,KAAA,IACA,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,8BACE,IAAA,IACA,KAAA,EACA,WAAA,KACA,aAAA,IAAA,IAAA,IAAA,EACA,mBAAA,KAEF,6BACE,IAAA,IACA,MAAA,EACA,WAAA,KACA,aAAA,IAAA,EAAA,IAAA,IACA,kBAAA,KAEF,+BACE,IAAA,EACA,KAAA,IACA,YAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEF,oCACE,IAAA,EACA,MAAA,IACA,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEF,qCACE,IAAA,EACA,KAAA,IACA,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAKJ,eACE,UAAA,MACA,QAAA,IAAA,IACA,MAAA,KACA,WAAA,OACA,iBAAA,KACA,cAAA,IAIF,eACE,SAAA,SACA,MAAA,EACA,OAAA,EACA,aAAA,YACA,aAAA,MEzGF,SACE,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,UAAA,MACA,QAAA,IDXA,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,UAAA,OACA,YAAA,OCAA,UAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,eACA,cAAA,ItDiDA,mBAAA,EAAA,IAAA,KAAA,eACQ,WAAA,EAAA,IAAA,KAAA,esD9CR,aAAQ,WAAA,MACR,eAAU,YAAA,KACV,gBAAW,WAAA,KACX,cAAS,YAAA,MAvBX,gBA4BI,aAAA,KAEA,gB1DkjMJ,sB0DhjMM,SAAA,SACA,QAAA,MACA,MAAA,EACA,OAAA,EACA,aAAA,YACA,aAAA,MAGF,sBACE,QAAA,GACA,aAAA,KAIJ,oBACE,OAAA,MACA,KAAA,IACA,YAAA,MACA,iBAAA,KACA,iBAAA,gBACA,oBAAA,EACA,0BACE,OAAA,IACA,YAAA,MACA,QAAA,IACA,iBAAA,KACA,oBAAA,EAGJ,sBACE,IAAA,IACA,KAAA,MACA,WAAA,MACA,mBAAA,KACA,mBAAA,gBACA,kBAAA,EACA,4BACE,OAAA,MACA,KAAA,IACA,QAAA,IACA,mBAAA,KACA,kBAAA,EAGJ,uBACE,IAAA,MACA,KAAA,IACA,YAAA,MACA,iBAAA,EACA,oBAAA,KACA,oBAAA,gBACA,6BACE,IAAA,IACA,YAAA,MACA,QAAA,IACA,iBAAA,EACA,oBAAA,KAIJ,qBACE,IAAA,IACA,MAAA,MACA,WAAA,MACA,mBAAA,EACA,kBAAA,KACA,kBAAA,gBACA,2BACE,MAAA,IACA,OAAA,MACA,QAAA,IACA,mBAAA,EACA,kBAAA,KAKN,eACE,QAAA,IAAA,KACA,OAAA,EACA,UAAA,KACA,iBAAA,QACA,cAAA,IAAA,MAAA,QACA,cAAA,IAAA,IAAA,EAAA,EAGF,iBACE,QAAA,IAAA,KCpHF,UACE,SAAA,SAGF,gBACE,SAAA,SACA,MAAA,KACA,SAAA,OAHF,sBAMI,SAAA,SACA,QAAA,KvD6KF,mBAAA,IAAA,YAAA,KACK,cAAA,IAAA,YAAA,KACG,WAAA,IAAA,YAAA,KJs/LV,4B2D5qMA,0BAcM,YAAA,EAIF,8BAAA,uBAAA,sBvDuLF,mBAAA,kBAAA,IAAA,YAEK,cAAA,aAAA,IAAA,YACG,WAAA,kBAAA,IAAA,YAAA,WAAA,UAAA,IAAA,YAAA,WAAA,UAAA,IAAA,WAAA,CAAA,kBAAA,IAAA,WAAA,CAAA,aAAA,IAAA,YA7JR,4BAAA,OAEQ,oBAAA,OA+GR,oBAAA,OAEQ,YAAA,OJ0hMR,mC2DrqMI,2BvDmHJ,kBAAA,sBACQ,UAAA,sBuDjHF,KAAA,E3DwqMN,kC2DtqMI,2BvD8GJ,kBAAA,uBACQ,UAAA,uBuD5GF,KAAA,E3D0qMN,6B2DxqMI,gC3DuqMJ,iCI9jMA,kBAAA,mBACQ,UAAA,mBuDtGF,KAAA,GArCR,wB3DgtMA,sBACA,sB2DpqMI,QAAA,MA7CJ,wBAiDI,KAAA,EAjDJ,sB3DwtMA,sB2DlqMI,SAAA,SACA,IAAA,EACA,MAAA,KAxDJ,sBA4DI,KAAA,KA5DJ,sBA+DI,KAAA,MA/DJ,2B3DouMA,4B2DjqMI,KAAA,EAnEJ,6BAuEI,KAAA,MAvEJ,8BA0EI,KAAA,KAQJ,kBACE,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,IACA,UAAA,KACA,MAAA,KACA,WAAA,OACA,YAAA,EAAA,IAAA,IAAA,eACA,iBAAA,ctCpGA,OAAA,kBACA,QAAA,GsCyGA,uBdrGE,iBAAA,sEACA,iBAAA,iEACA,iBAAA,uFAAA,iBAAA,kEACA,OAAA,+GACA,kBAAA,ScoGF,wBACE,MAAA,EACA,KAAA,Kd1GA,iBAAA,sEACA,iBAAA,iEACA,iBAAA,uFAAA,iBAAA,kEACA,OAAA,+GACA,kBAAA,S7C6wMJ,wB2DlqME,wBAEE,MAAA,KACA,gBAAA,KACA,QAAA,EtCxHF,OAAA,kBACA,QAAA,GrB8xMF,0CACA,2CAFA,6B2DpsMA,6BAuCI,SAAA,SACA,IAAA,IACA,QAAA,EACA,QAAA,aACA,WAAA,M3DmqMJ,0C2D9sMA,6BA+CI,KAAA,IACA,YAAA,M3DmqMJ,2C2DntMA,6BAoDI,MAAA,IACA,aAAA,M3DmqMJ,6B2DxtMA,6BAyDI,MAAA,KACA,OAAA,KACA,YAAA,MACA,YAAA,EAIA,oCACE,QAAA,QAIF,oCACE,QAAA,QAUN,qBACE,SAAA,SACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,MAAA,IACA,aAAA,EACA,YAAA,KACA,WAAA,OACA,WAAA,KATF,wBAYI,QAAA,aACA,MAAA,KACA,OAAA,KACA,OAAA,IACA,YAAA,OACA,OAAA,QAUA,iBAAA,OACA,iBAAA,cAEA,OAAA,IAAA,MAAA,KACA,cAAA,KA/BJ,6BAmCI,MAAA,KACA,OAAA,KACA,OAAA,EACA,iBAAA,KAOJ,kBACE,SAAA,SACA,MAAA,IACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,YAAA,KACA,eAAA,KACA,MAAA,KACA,WAAA,OACA,YAAA,EAAA,IAAA,IAAA,eAEA,uBACE,YAAA,KAMJ,oCAGE,0C3D+nMA,2CAEA,6BADA,6B2D3nMI,MAAA,KACA,OAAA,KACA,WAAA,MACA,UAAA,KARJ,0C3DwoMA,6B2D5nMI,YAAA,MAZJ,2C3D4oMA,6B2D5nMI,aAAA,MAKJ,kBACE,MAAA,IACA,KAAA,IACA,eAAA,KAIF,qBACE,OAAA,M3D0oMJ,qCADA,sCADA,mBADA,oBAXA,gB4D73ME,iB5Dm4MF,uBADA,wBADA,iBADA,kBADA,wBADA,yBASA,mCADA,oCAqBA,oBADA,qBADA,oBADA,qBAXA,WADA,YAOA,uBADA,wBADA,qBADA,sBADA,cADA,eAOA,aADA,cAGA,kBADA,mBAjBA,WADA,Y4Dl4MI,QAAA,MACA,QAAA,I5Dm6MJ,qCADA,mB4Dh6ME,gB5D65MF,uBADA,iBADA,wBAIA,mCAUA,oBADA,oBANA,WAGA,uBADA,qBADA,cAGA,aACA,kBATA,W4D75MI,MAAA,K5BNJ,c6BVE,QAAA,MACA,aAAA,KACA,YAAA,K7BWF,YACE,MAAA,gBAEF,WACE,MAAA,eAQF,MACE,QAAA,eAEF,MACE,QAAA,gBAEF,WACE,WAAA,OAEF,W8BzBE,KAAA,CAAA,CAAA,EAAA,EACA,MAAA,YACA,YAAA,KACA,iBAAA,YACA,OAAA,E9B8BF,QACE,QAAA,eAOF,OACE,SAAA,M+BjCF,cACE,MAAA,a/D88MF,YADA,YADA,Y+Dt8MA,YClBE,QAAA,ehEs+MF,kBACA,mBACA,yBALA,kBACA,mBACA,yBALA,kBACA,mBACA,yB+Dz8MA,kB/Dq8MA,mBACA,yB+D17ME,QAAA,eAIA,yBAAA,YCjDA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhE4/MV,cgE3/MA,cACU,QAAA,sBDkDV,yBAAA,kBACE,QAAA,iBAIF,yBAAA,mBACE,QAAA,kBAIF,yBAAA,yBACE,QAAA,wBAKF,+CAAA,YCtEA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhE0hNV,cgEzhNA,cACU,QAAA,sBDuEV,+CAAA,kBACE,QAAA,iBAIF,+CAAA,mBACE,QAAA,kBAIF,+CAAA,yBACE,QAAA,wBAKF,gDAAA,YC3FA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhEwjNV,cgEvjNA,cACU,QAAA,sBD4FV,gDAAA,kBACE,QAAA,iBAIF,gDAAA,mBACE,QAAA,kBAIF,gDAAA,yBACE,QAAA,wBAKF,0BAAA,YChHA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhEslNV,cgErlNA,cACU,QAAA,sBDiHV,0BAAA,kBACE,QAAA,iBAIF,0BAAA,mBACE,QAAA,kBAIF,0BAAA,yBACE,QAAA,wBAKF,yBAAA,WC7HA,QAAA,gBDkIA,+CAAA,WClIA,QAAA,gBDuIA,gDAAA,WCvIA,QAAA,gBD4IA,0BAAA,WC5IA,QAAA,gBDuJF,eCvJE,QAAA,eD0JA,aAAA,eClKA,QAAA,gBACA,oBAAU,QAAA,gBACV,iBAAU,QAAA,oBhE2oNV,iBgE1oNA,iBACU,QAAA,sBDkKZ,qBACE,QAAA,eAEA,aAAA,qBACE,QAAA,iBAGJ,sBACE,QAAA,eAEA,aAAA,sBACE,QAAA,kBAGJ,4BACE,QAAA,eAEA,aAAA,4BACE,QAAA,wBAKF,aAAA,cCrLA,QAAA","sourcesContent":["/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: none;\n text-decoration: underline;\n text-decoration: underline dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important;\n text-shadow: none !important;\n background: transparent !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"../fonts/glyphicons-halflings-regular.eot\");\n src: url(\"../fonts/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/glyphicons-halflings-regular.woff2\") format(\"woff2\"), url(\"../fonts/glyphicons-halflings-regular.woff\") format(\"woff\"), url(\"../fonts/glyphicons-halflings-regular.ttf\") format(\"truetype\"), url(\"../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular\") format(\"svg\");\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: 400;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: \"\\2014 \\00A0\";\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: \"\";\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: \"\\00A0 \\2014\";\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n color: #333333;\n word-break: break-all;\n word-wrap: break-word;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n.row {\n margin-right: -15px;\n margin-left: -15px;\n}\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n.row-no-gutters [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n.col-xs-1,\n.col-sm-1,\n.col-md-1,\n.col-lg-1,\n.col-xs-2,\n.col-sm-2,\n.col-md-2,\n.col-lg-2,\n.col-xs-3,\n.col-sm-3,\n.col-md-3,\n.col-lg-3,\n.col-xs-4,\n.col-sm-4,\n.col-md-4,\n.col-lg-4,\n.col-xs-5,\n.col-sm-5,\n.col-md-5,\n.col-lg-5,\n.col-xs-6,\n.col-sm-6,\n.col-md-6,\n.col-lg-6,\n.col-xs-7,\n.col-sm-7,\n.col-md-7,\n.col-lg-7,\n.col-xs-8,\n.col-sm-8,\n.col-md-8,\n.col-lg-8,\n.col-xs-9,\n.col-sm-9,\n.col-md-9,\n.col-lg-9,\n.col-xs-10,\n.col-sm-10,\n.col-md-10,\n.col-lg-10,\n.col-xs-11,\n.col-sm-11,\n.col-md-11,\n.col-lg-11,\n.col-xs-12,\n.col-sm-12,\n.col-md-12,\n.col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n.col-xs-1,\n.col-xs-2,\n.col-xs-3,\n.col-xs-4,\n.col-xs-5,\n.col-xs-6,\n.col-xs-7,\n.col-xs-8,\n.col-xs-9,\n.col-xs-10,\n.col-xs-11,\n.col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1,\n .col-sm-2,\n .col-sm-3,\n .col-sm-4,\n .col-sm-5,\n .col-sm-6,\n .col-sm-7,\n .col-sm-8,\n .col-sm-9,\n .col-sm-10,\n .col-sm-11,\n .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1,\n .col-md-2,\n .col-md-3,\n .col-md-4,\n .col-md-5,\n .col-md-6,\n .col-md-7,\n .col-md-8,\n .col-md-9,\n .col-md-10,\n .col-md-11,\n .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1,\n .col-lg-2,\n .col-lg-3,\n .col-lg-4,\n .col-lg-5,\n .col-lg-6,\n .col-lg-7,\n .col-lg-8,\n .col-lg-9,\n .col-lg-10,\n .col-lg-11,\n .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ntable col[class*=\"col-\"] {\n position: static;\n display: table-column;\n float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n display: table-cell;\n float: none;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n min-height: 0.01%;\n overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: 700;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n -webkit-appearance: none;\n appearance: none;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n vertical-align: middle;\n cursor: pointer;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\n.form-control-static {\n min-height: 34px;\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-right: 0;\n padding-left: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n background-color: #f2dede;\n border-color: #a94442;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n padding-top: 7px;\n margin-top: 0;\n margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n padding-top: 7px;\n margin-bottom: 0;\n text-align: right;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n outline: 0;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n filter: alpha(opacity=65);\n opacity: 0.65;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n background-image: none;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n background-image: none;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n background-image: none;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n background-image: none;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n background-image: none;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n background-image: none;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n font-weight: 400;\n color: #337ab7;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n font-size: 14px;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n color: #262626;\n text-decoration: none;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n background-color: #337ab7;\n outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n content: \"\";\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n right: 0;\n left: auto;\n }\n .navbar-right .dropdown-menu-left {\n right: auto;\n left: 0;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n cursor: default;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n padding-right: 15px;\n padding-left: 15px;\n overflow-x: visible;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-right: 0;\n padding-left: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-brand {\n float: left;\n height: 50px;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-right: 15px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n padding: 10px 15px;\n margin-right: -15px;\n margin-left: -15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n color: #fff;\n background-color: #080808;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n padding: 0 5px;\n color: #ccc;\n content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n margin-left: -1px;\n line-height: 1.42857143;\n color: #337ab7;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-top-left-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n cursor: default;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-top-left-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-top-right-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n text-align: center;\n list-style: none;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n}\n.label {\n display: inline;\n padding: 0.2em 0.6em 0.3em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n padding-right: 15px;\n padding-left: 15px;\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-right: 60px;\n padding-left: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-right: auto;\n margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n height: 20px;\n margin-bottom: 20px;\n overflow: hidden;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n padding-left: 0;\n margin-bottom: 20px;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #eeeeee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n color: #555;\n text-decoration: none;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-right: 15px;\n padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n margin-bottom: 0;\n border: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n filter: alpha(opacity=20);\n opacity: 0.2;\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.modal-backdrop.in {\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 12px;\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.tooltip.in {\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.tooltip.top {\n padding: 5px 0;\n margin-top: -3px;\n}\n.tooltip.right {\n padding: 0 5px;\n margin-left: 3px;\n}\n.tooltip.bottom {\n padding: 5px 0;\n margin-top: 3px;\n}\n.tooltip.left {\n padding: 0 5px;\n margin-left: -3px;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n right: 5px;\n bottom: 0;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow:after {\n content: \"\";\n border-width: 10px;\n}\n.popover.top > .arrow {\n bottom: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n bottom: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-color: #fff;\n border-bottom-width: 0;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n border-left-width: 0;\n}\n.popover.right > .arrow:after {\n bottom: -10px;\n left: 1px;\n content: \" \";\n border-right-color: #fff;\n border-left-width: 0;\n}\n.popover.bottom > .arrow {\n top: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n.popover.bottom > .arrow:after {\n top: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n right: 1px;\n bottom: -10px;\n content: \" \";\n border-right-width: 0;\n border-left-color: #fff;\n}\n.popover-title {\n padding: 8px 14px;\n margin: 0;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner > .item {\n position: relative;\n display: none;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 15%;\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control.right {\n right: 0;\n left: auto;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n}\n.carousel-control .icon-prev:before {\n content: \"\\2039\";\n}\n.carousel-control .icon-next:before {\n content: \"\\203a\";\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n border: 1px solid #fff;\n border-radius: 10px;\n}\n.carousel-indicators .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n display: table;\n content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable\n\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// 1. Remove the bottom border in Chrome 57- and Firefox 39-.\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n//\n\nabbr[title] {\n border-bottom: none; // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: none;\n text-decoration: underline;\n -webkit-text-decoration: underline dotted;\n -moz-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important;\n text-shadow: none !important;\n background: transparent !important;\n -webkit-box-shadow: none !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"../fonts/glyphicons-halflings-regular.eot\");\n src: url(\"../fonts/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/glyphicons-halflings-regular.woff2\") format(\"woff2\"), url(\"../fonts/glyphicons-halflings-regular.woff\") format(\"woff\"), url(\"../fonts/glyphicons-halflings-regular.ttf\") format(\"truetype\"), url(\"../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular\") format(\"svg\");\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: 400;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: \"\\2014 \\00A0\";\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: \"\";\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: \"\\00A0 \\2014\";\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n color: #333333;\n word-break: break-all;\n word-wrap: break-word;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n.row {\n margin-right: -15px;\n margin-left: -15px;\n}\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n.row-no-gutters [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n.col-xs-1,\n.col-sm-1,\n.col-md-1,\n.col-lg-1,\n.col-xs-2,\n.col-sm-2,\n.col-md-2,\n.col-lg-2,\n.col-xs-3,\n.col-sm-3,\n.col-md-3,\n.col-lg-3,\n.col-xs-4,\n.col-sm-4,\n.col-md-4,\n.col-lg-4,\n.col-xs-5,\n.col-sm-5,\n.col-md-5,\n.col-lg-5,\n.col-xs-6,\n.col-sm-6,\n.col-md-6,\n.col-lg-6,\n.col-xs-7,\n.col-sm-7,\n.col-md-7,\n.col-lg-7,\n.col-xs-8,\n.col-sm-8,\n.col-md-8,\n.col-lg-8,\n.col-xs-9,\n.col-sm-9,\n.col-md-9,\n.col-lg-9,\n.col-xs-10,\n.col-sm-10,\n.col-md-10,\n.col-lg-10,\n.col-xs-11,\n.col-sm-11,\n.col-md-11,\n.col-lg-11,\n.col-xs-12,\n.col-sm-12,\n.col-md-12,\n.col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n.col-xs-1,\n.col-xs-2,\n.col-xs-3,\n.col-xs-4,\n.col-xs-5,\n.col-xs-6,\n.col-xs-7,\n.col-xs-8,\n.col-xs-9,\n.col-xs-10,\n.col-xs-11,\n.col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1,\n .col-sm-2,\n .col-sm-3,\n .col-sm-4,\n .col-sm-5,\n .col-sm-6,\n .col-sm-7,\n .col-sm-8,\n .col-sm-9,\n .col-sm-10,\n .col-sm-11,\n .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1,\n .col-md-2,\n .col-md-3,\n .col-md-4,\n .col-md-5,\n .col-md-6,\n .col-md-7,\n .col-md-8,\n .col-md-9,\n .col-md-10,\n .col-md-11,\n .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1,\n .col-lg-2,\n .col-lg-3,\n .col-lg-4,\n .col-lg-5,\n .col-lg-6,\n .col-lg-7,\n .col-lg-8,\n .col-lg-9,\n .col-lg-10,\n .col-lg-11,\n .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ntable col[class*=\"col-\"] {\n position: static;\n display: table-column;\n float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n display: table-cell;\n float: none;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n min-height: 0.01%;\n overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: 700;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n vertical-align: middle;\n cursor: pointer;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\n.form-control-static {\n min-height: 34px;\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-right: 0;\n padding-left: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n background-color: #f2dede;\n border-color: #a94442;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n padding-top: 7px;\n margin-top: 0;\n margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n padding-top: 7px;\n margin-bottom: 0;\n text-align: right;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n outline: 0;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n filter: alpha(opacity=65);\n opacity: 0.65;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n background-image: none;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n background-image: none;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n background-image: none;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n background-image: none;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n background-image: none;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n background-image: none;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n font-weight: 400;\n color: #337ab7;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n -o-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n -o-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n -o-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n font-size: 14px;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n color: #262626;\n text-decoration: none;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n background-color: #337ab7;\n outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n content: \"\";\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n right: 0;\n left: auto;\n }\n .navbar-right .dropdown-menu-left {\n right: auto;\n left: 0;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n cursor: default;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n padding-right: 15px;\n padding-left: 15px;\n overflow-x: visible;\n border-top: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-right: 0;\n padding-left: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-brand {\n float: left;\n height: 50px;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-right: 15px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n padding: 10px 15px;\n margin-right: -15px;\n margin-left: -15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n color: #fff;\n background-color: #080808;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n padding: 0 5px;\n color: #ccc;\n content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n margin-left: -1px;\n line-height: 1.42857143;\n color: #337ab7;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-top-left-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n cursor: default;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-top-left-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-top-right-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n text-align: center;\n list-style: none;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n}\n.label {\n display: inline;\n padding: 0.2em 0.6em 0.3em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n padding-right: 15px;\n padding-left: 15px;\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-right: 60px;\n padding-left: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-right: auto;\n margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@-o-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n height: 20px;\n margin-bottom: 20px;\n overflow: hidden;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n -webkit-background-size: 40px 40px;\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n padding-left: 0;\n margin-bottom: 20px;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #eeeeee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n color: #555;\n text-decoration: none;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-right: 15px;\n padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n margin-bottom: 0;\n border: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n filter: alpha(opacity=20);\n opacity: 0.2;\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: -webkit-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out, -o-transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.modal-backdrop.in {\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 12px;\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.tooltip.in {\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.tooltip.top {\n padding: 5px 0;\n margin-top: -3px;\n}\n.tooltip.right {\n padding: 0 5px;\n margin-left: 3px;\n}\n.tooltip.bottom {\n padding: 5px 0;\n margin-top: 3px;\n}\n.tooltip.left {\n padding: 0 5px;\n margin-left: -3px;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n right: 5px;\n bottom: 0;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow:after {\n content: \"\";\n border-width: 10px;\n}\n.popover.top > .arrow {\n bottom: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n bottom: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-color: #fff;\n border-bottom-width: 0;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n border-left-width: 0;\n}\n.popover.right > .arrow:after {\n bottom: -10px;\n left: 1px;\n content: \" \";\n border-right-color: #fff;\n border-left-width: 0;\n}\n.popover.bottom > .arrow {\n top: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n.popover.bottom > .arrow:after {\n top: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n right: 1px;\n bottom: -10px;\n content: \" \";\n border-right-width: 0;\n border-left-color: #fff;\n}\n.popover-title {\n padding: 8px 14px;\n margin: 0;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner > .item {\n position: relative;\n display: none;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: -webkit-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out, -o-transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 15%;\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control.right {\n right: 0;\n left: auto;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n}\n.carousel-control .icon-prev:before {\n content: \"\\2039\";\n}\n.carousel-control .icon-next:before {\n content: \"\\203a\";\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n border: 1px solid #fff;\n border-radius: 10px;\n}\n.carousel-indicators .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n display: table;\n content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable declaration-no-important, selector-no-qualifying-type\n\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important; // Black prints faster: h5bp.com/s\n text-shadow: none !important;\n background: transparent !important;\n box-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n}\n","// stylelint-disable value-list-comma-newline-after, value-list-comma-space-after, indentation, declaration-colon-newline-after, font-family-no-missing-generic-family-keyword\n\n//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"@{icon-font-path}@{icon-font-name}.eot\");\n src: url(\"@{icon-font-path}@{icon-font-name}.eot?#iefix\") format(\"embedded-opentype\"),\n url(\"@{icon-font-path}@{icon-font-name}.woff2\") format(\"woff2\"),\n url(\"@{icon-font-path}@{icon-font-name}.woff\") format(\"woff\"),\n url(\"@{icon-font-path}@{icon-font-name}.ttf\") format(\"truetype\"),\n url(\"@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}\") format(\"svg\");\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\002a\"; } }\n.glyphicon-plus { &:before { content: \"\\002b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// https://getbootstrap.com/docs/3.4/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: https://a11yproject.com/posts/how-to-hide-content\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// stylelint-disable indentation, property-no-vendor-prefix, selector-no-vendor-prefix\n\n// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n word-wrap: break-word;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // WebKit-specific. Other browsers will keep their default outline style.\n // (Initially tried to also force default via `outline: initial`,\n // but that seems to erroneously remove the outline in Firefox altogether.)\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// stylelint-disable media-feature-name-no-vendor-prefix, media-feature-parentheses-space-inside, media-feature-name-no-unknown, indentation, at-rule-name-space-after\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","// stylelint-disable selector-list-comma-newline-after, selector-no-qualifying-type\n\n//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: 400;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n padding: .2em;\n background-color: @state-warning-bg;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @dl-horizontal-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: \"\\2014 \\00A0\"; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: \"\"; }\n &:after {\n content: \"\\00A0 \\2014\"; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n color: @pre-color;\n word-break: break-all;\n word-wrap: break-word;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n\n [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n padding-right: ceil((@gutter / 2));\n padding-left: floor((@gutter / 2));\n margin-right: auto;\n margin-left: auto;\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-right: floor((@gutter / -2));\n margin-left: ceil((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-right: floor((@grid-gutter-width / 2));\n padding-left: ceil((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","// stylelint-disable selector-max-type, selector-max-compound-selectors, selector-no-qualifying-type\n\n//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n\n // Table cell sizing\n //\n // Reset default table behavior\n\n col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n display: table-column;\n float: none;\n }\n\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n display: table-cell;\n float: none;\n }\n }\n}\n\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\n\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n min-height: .01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n overflow-x: auto;\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * .75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","// stylelint-disable selector-no-qualifying-type, property-no-vendor-prefix, media-feature-name-no-vendor-prefix\n\n//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: 700;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\ninput[type=\"search\"] {\n // Override content-box in Normalize (* isn't specific enough)\n .box-sizing(border-box);\n\n // Search inputs in iOS\n //\n // This overrides the extra rounded corners on search inputs in iOS so that our\n // `.form-control` class can properly style them. Note that this cannot simply\n // be added to `.form-control` as it's not specific enough. For details, see\n // https://github.com/twbs/bootstrap/issues/11586.\n -webkit-appearance: none;\n appearance: none;\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n\n // Apply same disabled cursor tweak as for inputs\n // Some special care is needed because <label>s don't inherit their parent's `cursor`.\n //\n // Note: Neither radios nor checkboxes can be readonly.\n &[disabled],\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Unstyle the caret on `<select>`s in IE10+.\n &::-ms-expand {\n background-color: transparent;\n border: 0;\n }\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n }\n\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n//\n// Note that as of 9.3, iOS doesn't support `week`.\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n &.form-control {\n line-height: @input-height-base;\n }\n\n &.input-sm,\n .input-group-sm & {\n line-height: @input-height-small;\n }\n\n &.input-lg,\n .input-group-lg & {\n line-height: @input-height-large;\n }\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n // These are used on elements with <label> descendants\n &.disabled,\n fieldset[disabled] & {\n label {\n cursor: @cursor-disabled;\n }\n }\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n vertical-align: middle;\n cursor: pointer;\n\n // These are used directly on <label>s\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n min-height: (@line-height-computed + @font-size-base);\n // Size it appropriately next to real form controls\n padding-top: (@padding-base-vertical + 1);\n padding-bottom: (@padding-base-vertical + 1);\n // Remove default margin from `p`\n margin-bottom: 0;\n\n &.input-lg,\n &.input-sm {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n .form-control {\n height: @input-height-small;\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n border-radius: @input-border-radius-small;\n }\n select.form-control {\n height: @input-height-small;\n line-height: @input-height-small;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-small;\n min-height: (@line-height-computed + @font-size-small);\n padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n }\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n .form-control {\n height: @input-height-large;\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n border-radius: @input-border-radius-large;\n }\n select.form-control {\n height: @input-height-large;\n line-height: @input-height-large;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-large;\n min-height: (@line-height-computed + @font-size-large);\n padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2; // Ensure icon is above input groups\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: @input-height-large;\n height: @input-height-large;\n line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: @input-height-small;\n height: @input-height-small;\n line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n & ~ .form-control-feedback {\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n }\n &.sr-only ~ .form-control-feedback {\n top: 0;\n }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n\n // Make static controls behave like regular ones\n .form-control-static {\n display: inline-block;\n }\n\n .input-group {\n display: inline-table;\n vertical-align: middle;\n\n .input-group-addon,\n .input-group-btn,\n .form-control {\n width: auto;\n }\n }\n\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match.\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n\n label {\n padding-left: 0;\n }\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n\n // Re-override the feedback icon.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of radios and checkboxes\n //\n // Labels also get some reset styles, but that is scoped to a media query below.\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n margin-top: 0;\n margin-bottom: 0;\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n // Reset spacing and right align labels, but scope to media queries so that\n // labels on narrow viewports stack the same as a default form example.\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n margin-bottom: 0;\n text-align: right;\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n right: floor((@grid-gutter-width / 2));\n }\n\n // Form group sizes\n //\n // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n // inputs and labels within a `.form-group`.\n .form-group-lg {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-large-vertical + 1);\n font-size: @font-size-large;\n }\n }\n }\n .form-group-sm {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-small-vertical + 1);\n font-size: @font-size-small;\n }\n }\n }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline,\n &.radio label,\n &.checkbox label,\n &.radio-inline label,\n &.checkbox-inline label {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n background-color: @background-color;\n border-color: @border-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n background-image: none;\n outline: 0;\n .box-shadow(inset 0 3px 5px rgba(0, 0, 0, .125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n font-weight: 400;\n color: @link-color;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n background-image: none;\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus,\n &.focus {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n @opacity-ie: (@opacity * 100); // IE8 filter\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n opacity: @opacity;\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n list-style: none;\n background-color: @dropdown-bg;\n background-clip: padding-box;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0, 0, 0, .175));\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n\n &:hover,\n &:focus {\n color: @dropdown-link-hover-color;\n text-decoration: none;\n background-color: @dropdown-link-hover-bg;\n }\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n background-color: @dropdown-link-active-bg;\n outline: 0;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n cursor: @cursor-disabled;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n right: 0;\n left: auto; // Reset the default from `.dropdown-menu`\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n content: \"\";\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","// stylelint-disable selector-no-qualifying-type */\n\n//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0, 0, 0, .125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n .border-top-radius(@btn-border-radius-base);\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n .border-top-radius(0);\n .border-bottom-radius(@btn-border-radius-base);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-left-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-top-right-radius: @radius;\n border-bottom-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-top-left-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n\n &:focus {\n z-index: 3;\n }\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: 400;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @input-border-radius;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @input-border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @input-border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","// stylelint-disable selector-no-qualifying-type, selector-max-type\n\n//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n padding-left: 0; // Override default ul/ol\n margin-bottom: 0;\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n cursor: @cursor-disabled;\n background-color: transparent;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n cursor: default;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n margin-bottom: 5px;\n text-align: center;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","// stylelint-disable selector-max-type, selector-max-compound-selectors, selector-max-combinators, selector-max-class, declaration-no-important, selector-no-qualifying-type\n\n//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n overflow-x: visible;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-right: 0;\n padding-left: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n\n // Fix the top/bottom navbars when screen real estate supports it\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n height: @navbar-height;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-right: @navbar-padding-horizontal;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n padding: 10px @navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-right: @navbar-padding-horizontal;\n margin-left: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n\n // Dropdown menu items\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n\n // Dropdowns\n > .open > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","// stylelint-disable declaration-no-important\n\n//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n padding: 0 5px;\n color: @breadcrumb-color;\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n margin-left: -1px;\n line-height: @line-height-base;\n color: @pagination-color;\n text-decoration: none;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-active-color;\n cursor: default;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n cursor: @cursor-disabled;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n text-align: center;\n list-style: none;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n cursor: @cursor-disabled;\n background-color: @pager-bg;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n line-height: @badge-line-height;\n color: @badge-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n padding-right: (@grid-gutter-width / 2);\n padding-left: (@grid-gutter-width / 2);\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-right: (@jumbotron-padding * 2);\n padding-left: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-right: auto;\n margin-left: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n color: inherit; // Specified for the h4 to prevent conflicts of changing @headings-color\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n// The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissable,\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n color: @text-color;\n background-color: @background;\n border-color: @border;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","// stylelint-disable at-rule-no-vendor-prefix\n\n//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n overflow: hidden;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0, 0, 0, .1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0, 0, 0, .15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// stylelint-disable value-no-vendor-prefix, selector-max-id\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\", argb(@start-color), argb(@end-color))); // IE9 and down\n background-repeat: repeat-x;\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\", argb(@start-color), argb(@end-color))); // IE9 and down\n background-repeat: repeat-x;\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\", argb(@start-color), argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n background-repeat: no-repeat;\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\", argb(@start-color), argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n background-repeat: no-repeat;\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255, 255, 255, .15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n padding-left: 0; // reset padding because ul and ol\n margin-bottom: 20px;\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n\n // Disabled state\n &.disabled,\n &.disabled:hover,\n &.disabled:focus {\n color: @list-group-disabled-color;\n cursor: @cursor-disabled;\n background-color: @list-group-disabled-bg;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-disabled-text-color;\n }\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading,\n .list-group-item-heading > small,\n .list-group-item-heading > .small {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Interactive list items\n//\n// Use anchor or button elements instead of `li`s or `div`s to create interactive items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item,\nbutton.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n color: @list-group-link-hover-color;\n text-decoration: none;\n background-color: @list-group-hover-bg;\n }\n}\n\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a&,\n button& {\n color: @color;\n\n .list-group-item-heading {\n color: inherit;\n }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n","// stylelint-disable selector-max-type, selector-max-compound-selectors, selector-max-combinators, no-duplicate-selectors\n\n//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0, 0, 0, .05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: @panel-heading-padding;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a,\n > small,\n > .small,\n > small > a,\n > .small > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: @panel-footer-padding;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group,\n > .panel-collapse > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n > .panel-heading + .panel-collapse > .list-group {\n .list-group-item:first-child {\n .border-top-radius(0);\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table,\n > .panel-collapse > .table {\n margin-bottom: 0;\n\n caption {\n padding-right: @panel-body-padding;\n padding-left: @panel-body-padding;\n }\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n border-top-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n border-bottom-left-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive,\n > .table + .panel-body,\n > .table-responsive + .panel-body {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n margin-bottom: 0;\n border: 0;\n }\n}\n\n\n// Collapsible panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n\n + .panel-collapse > .panel-body,\n + .panel-collapse > .list-group {\n border-top: 1px solid @panel-inner-border;\n }\n }\n\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse > .panel-body {\n border-top-color: @border;\n }\n .badge {\n color: @heading-bg-color;\n background-color: @heading-text-color;\n }\n }\n & > .panel-footer {\n + .panel-collapse > .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n\n .embed-responsive-item,\n iframe,\n embed,\n object,\n video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, .15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","// stylelint-disable property-no-vendor-prefix\n\n//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0); }\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n background-clip: padding-box;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0, 0, 0, .5));\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n &:extend(.clearfix all);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n padding: @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n margin-left: 5px;\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0, 0, 0, .5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-small;\n\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top {\n padding: @tooltip-arrow-width 0;\n margin-top: -3px;\n }\n &.right {\n padding: 0 @tooltip-arrow-width;\n margin-left: 3px;\n }\n &.bottom {\n padding: @tooltip-arrow-width 0;\n margin-top: 3px;\n }\n &.left {\n padding: 0 @tooltip-arrow-width;\n margin-left: -3px;\n }\n\n // Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n right: @tooltip-arrow-width;\n bottom: 0;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n",".reset-text() {\n font-family: @font-family-base;\n // We deliberately do NOT reset font-size.\n font-style: normal;\n font-weight: 400;\n line-height: @line-height-base;\n line-break: auto;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-base;\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0, 0, 0, .2));\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n\n // Arrows\n // .arrow is outer, .arrow:after is inner\n > .arrow {\n border-width: @popover-arrow-outer-width;\n\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n\n &:after {\n content: \"\";\n border-width: @popover-arrow-width;\n }\n }\n\n &.top > .arrow {\n bottom: -@popover-arrow-outer-width;\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n border-bottom-width: 0;\n &:after {\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n content: \" \";\n border-top-color: @popover-arrow-color;\n border-bottom-width: 0;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n border-left-width: 0;\n &:after {\n bottom: -@popover-arrow-width;\n left: 1px;\n content: \" \";\n border-right-color: @popover-arrow-color;\n border-left-width: 0;\n }\n }\n &.bottom > .arrow {\n top: -@popover-arrow-outer-width;\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n &:after {\n top: 1px;\n margin-left: -@popover-arrow-width;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n right: 1px;\n bottom: -@popover-arrow-width;\n content: \" \";\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n }\n }\n}\n\n.popover-title {\n padding: 8px 14px;\n margin: 0; // reset heading margin\n font-size: @font-size-base;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n","// stylelint-disable media-feature-name-no-unknown\n\n//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n\n > .item {\n position: relative;\n display: none;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n\n // WebKit CSS3 transforms for supported devices\n @media all and (transform-3d), (-webkit-transform-3d) {\n .transition-transform(~\"0.6s ease-in-out\");\n .backface-visibility(~\"hidden\");\n .perspective(1000px);\n\n &.next,\n &.active.right {\n .translate3d(100%, 0, 0);\n left: 0;\n }\n &.prev,\n &.active.left {\n .translate3d(-100%, 0, 0);\n left: 0;\n }\n &.next.left,\n &.prev.right,\n &.active {\n .translate3d(0, 0, 0);\n left: 0;\n }\n }\n }\n\n > .active,\n > .next,\n > .prev {\n display: block;\n }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: @carousel-control-width;\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug\n .opacity(@carousel-control-opacity);\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0, 0, 0, .5); @end-color: rgba(0, 0, 0, .0001));\n }\n &.right {\n right: 0;\n left: auto;\n #gradient > .horizontal(@start-color: rgba(0, 0, 0, .0001); @end-color: rgba(0, 0, 0, .5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n color: @carousel-control-color;\n text-decoration: none;\n outline: 0;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n }\n\n .icon-prev {\n &:before {\n content: \"\\2039\";// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: \"\\203a\";// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0, 0, 0, 0); // IE9\n\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n }\n\n .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: (@carousel-control-font-size * 1.5);\n height: (@carousel-control-font-size * 1.5);\n margin-top: (@carousel-control-font-size / -2);\n font-size: (@carousel-control-font-size * 1.5);\n }\n .glyphicon-chevron-left,\n .icon-prev {\n margin-left: (@carousel-control-font-size / -2);\n }\n .glyphicon-chevron-right,\n .icon-next {\n margin-right: (@carousel-control-font-size / -2);\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n &:before,\n &:after {\n display: table; // 2\n content: \" \"; // 1\n }\n &:after {\n clear: both;\n }\n}\n","// Center-align a block level element\n\n.center-block() {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n","// stylelint-disable font-family-name-quotes, font-family-no-missing-generic-family-keyword\n\n// CSS image replacement\n//\n// Heads up! v3 launched with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (has been removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n","// stylelint-disable declaration-no-important, at-rule-no-vendor-prefix\n\n//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: https://getbootstrap.com/docs/3.4/getting-started/#support-ie10-width\n// Source: https://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: https://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-xs-block {\n @media (max-width: @screen-xs-max) {\n display: block !important;\n }\n}\n.visible-xs-inline {\n @media (max-width: @screen-xs-max) {\n display: inline !important;\n }\n}\n.visible-xs-inline-block {\n @media (max-width: @screen-xs-max) {\n display: inline-block !important;\n }\n}\n\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-sm-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: block !important;\n }\n}\n.visible-sm-inline {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline !important;\n }\n}\n.visible-sm-inline-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline-block !important;\n }\n}\n\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-md-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: block !important;\n }\n}\n.visible-md-inline {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline !important;\n }\n}\n.visible-md-inline-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline-block !important;\n }\n}\n\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n.visible-lg-block {\n @media (min-width: @screen-lg-min) {\n display: block !important;\n }\n}\n.visible-lg-inline {\n @media (min-width: @screen-lg-min) {\n display: inline !important;\n }\n}\n.visible-lg-inline-block {\n @media (min-width: @screen-lg-min) {\n display: inline-block !important;\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n.visible-print-block {\n display: none !important;\n\n @media print {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n\n @media print {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n\n @media print {\n display: inline-block !important;\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n","// stylelint-disable declaration-no-important\n\n.responsive-visibility() {\n display: block !important;\n table& { display: table !important; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n"]} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/default.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/default.css new file mode 100644 index 0000000000000000000000000000000000000000..51ca3ba19ee8d350fe44c5dd6b427c942b25fb7b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/default.css @@ -0,0 +1,82 @@ +/* The navbar is fixed at >= 980px wide, so add padding to the body to prevent +content running up underneath it. */ + +h1 { + font-weight: 300; +} + +h2, h3 { + font-weight: 300; +} + +.resource-description, .response-info { + margin-bottom: 2em; +} + +.version:before { + content: "v"; + opacity: 0.6; + padding-right: 0.25em; +} + +.version { + font-size: 70%; +} + +.format-option { + font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace; +} + +.button-form { + float: right; + margin-right: 1em; +} + +td.nested { + padding: 0 !important; +} + +td.nested > table { + margin: 0; +} + +form select, form input:not([type=checkbox]), form textarea { + width: 90%; +} + +form select[multiple] { + height: 150px; +} + +/* To allow tooltips to work on disabled elements */ +.disabled-tooltip-shield { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.errorlist { + margin-top: 0.5em; +} + +pre { + overflow: auto; + word-wrap: normal; + white-space: pre; + font-size: 12px; +} + +.page-header { + border-bottom: none; + padding-bottom: 0px; +} + +#filtersModal form input[type=submit] { + width: auto; +} + +#filtersModal .modal-body h2 { + margin-top: 0 +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/font-awesome-4.0.3.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/font-awesome-4.0.3.css new file mode 100644 index 0000000000000000000000000000000000000000..048cff973981e8dd4ed8e73c4ca532ffcf02e1e8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/font-awesome-4.0.3.css @@ -0,0 +1,1338 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.0.3'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.3333333333333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.2857142857142858em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.142857142857143em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + top: 0.14285714285714285em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.8571428571428572em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-asc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-desc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-reply-all:before { + content: "\f122"; +} +.fa-mail-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/prettify.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/prettify.css new file mode 100644 index 0000000000000000000000000000000000000000..d437aff62bbbaabb783fa7acd89c9850287f1f6a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/css/prettify.css @@ -0,0 +1,30 @@ +.com { color: #93a1a1; } +.lit { color: #195f91; } +.pun, .opn, .clo { color: #93a1a1; } +.fun { color: #dc322f; } +.str, .atv { color: #D14; } +.kwd, .prettyprint .tag { color: #1e347b; } +.typ, .atn, .dec, .var { color: teal; } +.pln { color: #48484c; } + +.prettyprint { + padding: 8px; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +.prettyprint.linenums { + -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; + -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; + box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin: 0 0 0 33px; /* IE indents via margin-left */ +} +ol.linenums li { + padding-left: 12px; + color: #bebec5; + line-height: 20px; + text-shadow: 0 1px 0 #fff; +} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/base.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/base.css new file mode 100644 index 0000000000000000000000000000000000000000..06b240c522d415759363e0532de6c7a4efd69273 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/base.css @@ -0,0 +1,359 @@ +h1 { + font-size: 45px; +} + +.intro-code { + margin-top: 20px; +} + +pre.highlight code * { + white-space: nowrap; /* this sets all children inside to nowrap */ +} + +pre.highlight { + overflow-x: auto; /* this sets the scrolling in x */ +} + +pre.highlight code { + white-space: pre; /* forces <code> to respect <pre> formatting */ +} + +.main-container { + padding-left: 30px; + padding-right: 30px; +} + +.btn:focus, +.btn:focus:active { + outline: none; +} + +.sidebar { + overflow: auto; + font-family: verdana, sans-serif; + font-size: 12px; + font-weight: 200; + background-color: #2e353d; + position: fixed; + top: 0px; + width: 225px; + height: 100%; + color: #FFF; +} + +.sidebar .brand { + background-color: #23282e; + display: block; + text-align: center; + padding: 25px 0; + margin-top: 0; + margin-bottom: 0; +} + +.sidebar .brand a { + color: #FFF; +} + +.sidebar .brand a:hover, +.sidebar .brand a:active, +.sidebar .brand a:focus { + text-decoration: none; +} + +.sidebar .toggle-btn { + display: none; +} + +.sidebar .menu-list { + width: inherit; +} + +.sidebar .menu-list ul, +.sidebar .menu-list li { + background: #2e353d; + list-style: none; + padding: 0px; + margin: 0px; + line-height: 35px; + cursor: pointer; +} + +.sidebar .menu-list ul :not(collapsed) .arrow:before, +.sidebar .menu-list li :not(collapsed) .arrow:before { + font-family: FontAwesome; + content: "\f078"; + display: inline-block; + padding-left: 10px; + padding-right: 10px; + vertical-align: middle; + float: right; +} + +.sidebar .menu-list ul .active, +.sidebar .menu-list li .active { + border-left: 3px solid #d19b3d; + background-color: #4f5b69; +} + +.sidebar .menu-list ul .sub-menu li.active, +.sidebar .menu-list li .sub-menu li.active { + color: #d19b3d; +} + +.sidebar .menu-list ul .sub-menu li.active a, +.sidebar .menu-list li .sub-menu li.active a { + color: #d19b3d; +} + +.sidebar .menu-list ul .sub-menu li, +.sidebar .menu-list li .sub-menu li { + background-color: #181c20; + border: none; + border-bottom: 1px solid #23282e; + margin-left: 0px; + line-height: 1.4; + padding-top: 10px; + padding-bottom: 10px; + padding-right: 10px; + padding-left: 25px; +} + +.sidebar .menu-list ul .sub-menu li:hover, +.sidebar .menu-list li .sub-menu li:hover { + background-color: #020203; +} + + +.sidebar .menu-list ul .sub-menu li a, +.sidebar .menu-list li .sub-menu li a { + display: block; +} + +.sidebar .menu-list ul .sub-menu li a:before, +.sidebar .menu-list li .sub-menu li a:before { + font-family: FontAwesome; + font-size: 14px; + font-weight: bold; + content: "\f105"; + display: inline; + vertical-align: middle; + padding-left: 0; + padding-right: 7px; + margin-left: -12px; +} + +.sidebar .menu-list li { + padding-left: 0px; + border-left: 3px solid #2e353d; + border-bottom: 1px solid #23282e; +} + +.sidebar .menu-list li a { + text-decoration: none; + color: white; +} + +.sidebar .menu-list li a i { + padding-left: 10px; + width: 20px; + padding-right: 20px; +} + +.sidebar .menu-list li:hover { + border-left: 3px solid #d19b3d; + background-color: #4f5b69; + -webkit-transition: all 1s ease; + -moz-transition: all 1s ease; + -o-transition: all 1s ease; + -ms-transition: all 1s ease; + transition: all 1s ease; +} + +.sidebar #menu-content { + padding-bottom: 70px; +} + +body { + margin: 0px; + padding: 0px; +} + +.coredocs-section-title { + margin-top: 20px; + padding-bottom: 10px; + border-bottom: 1px solid lightgrey; +} + +.coredocs-link-title a, +.coredocs-section-title a { + display: none; +} + +.coredocs-link-title a, +.coredocs-section-title a { + text-decoration: none; +} + +.coredocs-link-title:hover a, +.coredocs-section-title:hover a { + display: inline; + font-size: 20px; +} + +.coredocs-section-title:last-child { + margin-top: 0; +} + + +/* @group Language Switcher */ + +.sidebar .menu-list.menu-list-bottom { + margin-bottom: 0; + position: fixed; + width: inherit; + bottom: 0; + left: 0; + right: 0; + border-top: 1px solid #23282e; +} + +.sidebar .menu-list-bottom li span { + float: right; + margin-right: 20px; + color: #d19b3d; +} + +/* @end Language Switcher */ + + +/* @group Docs Content */ + +.docs-content .meta .label { + vertical-align: middle; + font-size: 14px; + font-weight: normal; +} + +.docs-content .meta code { + vertical-align: middle; + padding: .2em .6em .3em; + font-size: 14px; +} + +.docs-content .btn { + font-size: inherit; +} + +.code-samples pre { + margin-top: 20px; +} + +/* @end Docs Content */ + + +@media (max-width: 767px) { + .main-container { + padding-left: 15px; + padding-right: 15px; + } + + .sidebar { + position: relative; + width: 100%; + margin-bottom: 10px; + overflow: visible; + } + + .sidebar .toggle-btn { + display: block; + cursor: pointer; + position: absolute; + right: 10px; + top: 10px; + z-index: 10 !important; + padding: 3px; + width: 40px; + text-align: center; + } + + .sidebar .menu-list.menu-list-bottom { + position: static; + } + + .sidebar .brand { + margin-top: 0; + margin-bottom: 0; + + text-align: left !important; + font-size: 22px; + padding: 0; + padding-left: 20px; + line-height: 50px !important; + } +} + +@media (min-width: 767px) { + .sidebar .menu-list .menu-content { + display: block; + } + #main { + width:calc(100% - 225px); + float: right; + } +} + +@media (min-width: 992px) { + .modal-lg { + width: 980px; + } +} + +.api-modal .modal-title .fa { + color: #93c54b; +} + +.api-modal .modal-body .request-awaiting { + padding: 35px 10px; + color: #7F8177; + text-align: center; +} + +.api-modal .modal-body .meta { + margin-bottom: 20px; +} + +.api-modal .modal-body .meta .label { + vertical-align: middle; + font-size: 14px; + font-weight: normal; +} + +.api-modal .modal-body .meta code { + vertical-align: middle; + padding: .2em .6em .3em; + font-size: 14px; +} + +.api-modal .modal-content .toggle-view { + text-align: right; + float: right; +} + +.api-modal .modal-content .response .well { + margin: 0; + max-height: 550px; +} + +.highlight { + background-color: #f7f7f9 +} + +.checkbox label.control-label { + font-weight: bold +} + +@media (min-width: 768px) { + .navbar-nav.navbar-right:last-child { + margin-right: 0 !important; + } +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/highlight.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/highlight.css new file mode 100644 index 0000000000000000000000000000000000000000..03754534f81f1d5b9a6505953836890c679c6502 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/highlight.css @@ -0,0 +1,125 @@ +/* +This is the GitHub theme for highlight.js + +github.com style (c) Vasily Polovnyov <vast@whiteants.net> + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + -webkit-text-size-adjust: none; +} + +.hljs-comment, +.diff .hljs-header, +.hljs-javadoc { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.css .rule .hljs-keyword, +.hljs-winutils, +.nginx .hljs-title, +.hljs-subst, +.hljs-request, +.hljs-status { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-hexcolor, +.ruby .hljs-constant { + color: #008080; +} + +.hljs-string, +.hljs-tag .hljs-value, +.hljs-phpdoc, +.hljs-dartdoc, +.tex .hljs-formula { + color: #d14; +} + +.hljs-title, +.hljs-id, +.scss .hljs-preprocessor { + color: #900; + font-weight: bold; +} + +.hljs-list .hljs-keyword, +.hljs-subst { + font-weight: normal; +} + +.hljs-class .hljs-title, +.hljs-type, +.vhdl .hljs-literal, +.tex .hljs-command { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-tag .hljs-title, +.hljs-rule .hljs-property, +.django .hljs-tag .hljs-keyword { + color: #000080; + font-weight: normal; +} + +.hljs-attribute, +.hljs-variable, +.lisp .hljs-body, +.hljs-name { + color: #008080; +} + +.hljs-regexp { + color: #009926; +} + +.hljs-symbol, +.ruby .hljs-symbol .hljs-string, +.lisp .hljs-keyword, +.clojure .hljs-keyword, +.scheme .hljs-keyword, +.tex .hljs-special, +.hljs-prompt { + color: #990073; +} + +.hljs-built_in { + color: #0086b3; +} + +.hljs-preprocessor, +.hljs-pragma, +.hljs-pi, +.hljs-doctype, +.hljs-shebang, +.hljs-cdata { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.diff .hljs-change { + background: #0086b3; +} + +.hljs-chunk { + color: #aaa; +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/jquery.json-view.min.css b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/jquery.json-view.min.css new file mode 100644 index 0000000000000000000000000000000000000000..a0756813668f880b1666181cbb32b22e58bbc012 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/css/jquery.json-view.min.css @@ -0,0 +1,11 @@ +.json-view{position:relative} +.json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer} +.json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)} +.json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative} +.json-view{font-family:monospace} +.json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em} +.json-view ul li{position:relative} +.json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none} +.json-view .comments{padding-left:.8em;font-style:italic;color:#888} +.json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC} +.json-view .str{color:#800} \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/favicon.ico b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..17b2c5d983c9b13b29af3fa0f30bc0c6dc1ae44c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/favicon.ico differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/grid.png b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..878c3ed5c196539c4e2da35b7787ab08e98b9cca Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/img/grid.png differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/api.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/api.js new file mode 100644 index 0000000000000000000000000000000000000000..21663deb67ca643fca629ee276c1a0da6bccf6d3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/api.js @@ -0,0 +1,315 @@ +var responseDisplay = 'data' +var coreapi = window.coreapi +var schema = window.schema + +function normalizeKeys (arr) { + var _normarr = []; + for (var i = 0; i < arr.length; i++) { + _normarr = _normarr.concat(arr[i].split(' > ')); + } + return _normarr; +} + +function normalizeHTTPHeader (str) { + // Capitalize HTTP headers for display. + return (str.charAt(0).toUpperCase() + str.substring(1)) + .replace(/-(.)/g, function ($1) { + return $1.toUpperCase() + }) + .replace(/(Www)/g, function ($1) { + return 'WWW' + }) + .replace(/(Xss)/g, function ($1) { + return 'XSS' + }) + .replace(/(Md5)/g, function ($1) { + return 'MD5' + }) +} + +function formEntries (form) { + // Polyfill for new FormData(form).entries() + var formData = new FormData(form) + if (formData.entries !== undefined) { + return Array.from(formData.entries()) + } + + var entries = [] + + for (var i = 0; i < form.elements.length; i++) { + var element = form.elements[i] + + if (!element.name) { + continue + } + + if (element.type === 'file') { + for (var j = 0; j < element.files.length; j++) { + entries.push([element.name, element.files[j]]) + } + } else if (element.type === 'select-multiple' || element.type === 'select-one') { + for (var j = 0; j < element.selectedOptions.length; j++) { + entries.push([element.name, element.selectedOptions[j].value]) + } + } else if (element.type === 'checkbox') { + if (element.checked) { + entries.push([element.name, element.value]) + } + } else { + entries.push([element.name, element.value]) + } + } + + return entries +} + +$(function () { + var $selectedAuthentication = $('#selected-authentication') + var $authControl = $('#auth-control') + var $authTokenModal = $('#auth_token_modal') + var $authBasicModal = $('#auth_basic_modal') + var $authSessionModal = $('#auth_session_modal') + + // Language Control + $('#language-control li').click(function (event) { + event.preventDefault() + var $languageMenuItem = $(this).find('a') + var $languageControls = $(this).closest('ul').find('li') + var $languageControlLinks = $languageControls.find('a') + var language = $languageMenuItem.data('language') + + $languageControlLinks.not('[data-language="' + language + '"]').parent().removeClass('active') + $languageControlLinks.filter('[data-language="' + language + '"]').parent().addClass('active') + + $('#selected-language').text(language) + + var $codeBlocks = $('pre.highlight') + $codeBlocks.not('[data-language="' + language + '"]').addClass('hide') + $codeBlocks.filter('[data-language="' + language + '"]').removeClass('hide') + }) + + // API Explorer + $('form.api-interaction').submit(function (event) { + event.preventDefault() + + var $form = $(this).closest('form') + var $requestMethod = $form.find('.request-method') + var $requestUrl = $form.find('.request-url') + var $toggleView = $form.closest('.modal-content').find('.toggle-view') + var $responseStatusCode = $form.find('.response-status-code') + var $meta = $form.find('.meta') + var $responseRawResponse = $form.find('.response-raw-response') + var $requestAwaiting = $form.find('.request-awaiting') + var $responseRaw = $form.find('.response-raw') + var $responseData = $form.find('.response-data') + var key = normalizeKeys($form.data('key')) + var params = {} + var entries = formEntries($form.get()[0]) + + for (var i = 0; i < entries.length; i++) { + var entry = entries[i] + var paramKey = entry[0] + var paramValue = entry[1] + var $elem = $form.find('[name="' + paramKey + '"]') + var dataType = $elem.data('type') || 'string' + + if (dataType === 'integer' && paramValue) { + var value = parseInt(paramValue) + if (!isNaN(value)) { + params[paramKey] = value + } + } else if (dataType === 'number' && paramValue) { + var value = parseFloat(paramValue) + if (!isNaN(value)) { + params[paramKey] = value + } + } else if (dataType === 'boolean' && paramValue) { + var value = { + 'true': true, + 'false': false + }[paramValue.toLowerCase()] + if (value !== undefined) { + params[paramKey] = value + } + } else if ((dataType === 'array' && paramValue) || (dataType === 'object' && paramValue)) { + try { + params[paramKey] = JSON.parse(paramValue) + } catch (err) { + // Ignore malformed JSON + } + } else if (dataType === 'string' && paramValue) { + params[paramKey] = paramValue + } + } + + $form.find(':checkbox').each(function (index) { + // Handle unselected checkboxes + var name = $(this).attr('name') + if (!params.hasOwnProperty(name)) { + params[name] = false + } + }) + + function requestCallback (request) { + // Fill in the "GET /foo/" display. + var parser = document.createElement('a') + parser.href = request.url + var method = request.options.method + var path = parser.pathname + parser.hash + parser.search + + $requestMethod.text(method) + $requestUrl.text(path) + } + + function responseCallback (response, responseText) { + // Display the 'Data'/'Raw' control. + $toggleView.removeClass('hide') + + // Fill in the "200 OK" display. + $responseStatusCode.removeClass('label-success').removeClass('label-danger') + if (response.ok) { + $responseStatusCode.addClass('label-success') + } else { + $responseStatusCode.addClass('label-danger') + } + $responseStatusCode.text(response.status) + $meta.removeClass('hide') + + // Fill in the Raw HTTP response display. + var panelText = 'HTTP/1.1 ' + response.status + ' ' + response.statusText + '\n' + response.headers.forEach(function (header, key) { + panelText += normalizeHTTPHeader(key) + ': ' + header + '\n' + }) + if (responseText) { + panelText += '\n' + responseText + } + $responseRawResponse.text(panelText) + } + + // Instantiate a client to make the outgoing request. + var options = { + requestCallback: requestCallback, + responseCallback: responseCallback + } + + // Setup authentication options. + if (window.auth && window.auth.type === 'token') { + // Header authentication + options.auth = new coreapi.auth.TokenAuthentication({ + scheme: window.auth.scheme, + token: window.auth.token + }) + } else if (window.auth && window.auth.type === 'basic') { + // Basic authentication + options.auth = new coreapi.auth.BasicAuthentication({ + username: window.auth.username, + password: window.auth.password + }) + } else if (window.auth && window.auth.type === 'session') { + // Session authentication + options.auth = new coreapi.auth.SessionAuthentication({ + csrfCookieName: 'csrftoken', + csrfHeaderName: 'X-CSRFToken' + }) + } + + var client = new coreapi.Client(options) + client.action(schema, key, params).then(function (data) { + var response = JSON.stringify(data, null, 2) + $requestAwaiting.addClass('hide') + $responseRaw.addClass('hide') + $responseData.addClass('hide').text('').jsonView(response) + + if (responseDisplay === 'data') { + $responseData.removeClass('hide') + } else { + $responseRaw.removeClass('hide') + } + }).catch(function (error) { + var response = JSON.stringify(error.content, null, 2) + $requestAwaiting.addClass('hide') + $responseRaw.addClass('hide') + $responseData.addClass('hide').text('').jsonView(response) + + if (responseDisplay === 'data') { + $responseData.removeClass('hide') + } else { + $responseRaw.removeClass('hide') + } + }) + }) + + // 'Data'/'Raw' control + $('.toggle-view button').click(function () { + var $modalContent = $(this).closest('.modal-content') + var $modalResponseRaw = $modalContent.find('.response-raw') + var $modalResponseData = $modalContent.find('.response-data') + + responseDisplay = $(this).data('display-toggle') + + $(this).removeClass('btn-default').addClass('btn-info').siblings().removeClass('btn-info') + + if (responseDisplay === 'raw') { + $modalResponseRaw.removeClass('hide') + $modalResponseData.addClass('hide') + } else { + $modalResponseData.removeClass('hide') + $modalResponseRaw.addClass('hide') + } + }) + + // Authentication: none + $authControl.find("[data-auth='none']").click(function (event) { + event.preventDefault() + window.auth = null + $selectedAuthentication.text('none') + $authControl.find("[data-auth]").closest('li').removeClass('active') + $authControl.find("[data-auth='none']").closest('li').addClass('active') + }) + + // Authentication: token + $('form.authentication-token-form').submit(function (event) { + event.preventDefault() + var $form = $(this).closest('form') + var scheme = $form.find('input#scheme').val() + var token = $form.find('input#token').val() + window.auth = { + 'type': 'token', + 'scheme': scheme, + 'token': token + } + $selectedAuthentication.text('token') + $authControl.find("[data-auth]").closest('li').removeClass('active') + $authControl.find("[data-auth='token']").closest('li').addClass('active') + $authTokenModal.modal('hide') + }) + + // Authentication: basic + $('form.authentication-basic-form').submit(function (event) { + event.preventDefault() + var $form = $(this).closest('form') + var username = $form.find('input#username').val() + var password = $form.find('input#password').val() + window.auth = { + 'type': 'basic', + 'username': username, + 'password': password + } + $selectedAuthentication.text('basic') + $authControl.find("[data-auth]").closest('li').removeClass('active') + $authControl.find("[data-auth='basic']").closest('li').addClass('active') + $authBasicModal.modal('hide') + }) + + // Authentication: session + $('form.authentication-session-form').submit(function (event) { + event.preventDefault() + window.auth = { + 'type': 'session' + } + $selectedAuthentication.text('session') + $authControl.find("[data-auth]").closest('li').removeClass('active') + $authControl.find("[data-auth='session']").closest('li').addClass('active') + $authSessionModal.modal('hide') + }) +}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/highlight.pack.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/highlight.pack.js new file mode 100644 index 0000000000000000000000000000000000000000..a5818dfb2fc8fdbc582d65fc1ca4c20ebeb532c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/highlight.pack.js @@ -0,0 +1,2 @@ +!function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return window.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){var n=(e.className+" "+(e.parentNode?e.parentNode.className:"")).split(/\s+/);return n=n.map(function(e){return e.replace(/^lang(uage)?-/,"")}),n.filter(function(e){return N(e)||/no(-?)highlight|plain|text/.test(e)})[0]}function i(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function o(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset<r[0].offset?e:r:"start"==r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value)+'"'}l+="<"+t(e)+Array.prototype.map.call(e.attributes,r).join("")+">"}function u(e){l+="</"+t(e)+">"}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);f.reverse().forEach(o)}else"start"==g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function c(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,o){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),o&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&o.tE&&(a.tE+=(a.e?"|":"")+o.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(i(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,o);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function s(e,t,a,i){function o(e,n){for(var t=0;t<n.c.length;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function f(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=E.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":x.classPrefix,i='<span class="'+a,o=t?"":"</span>";return i+=e+'">',i+n+o}function d(){if(!L.k)return n(y);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(y);r;){e+=n(y.substr(t,r.index-t));var a=g(L,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(y)}return e+n(y.substr(t))}function h(){if(L.sL&&!w[L.sL])return n(y);var e=L.sL?s(L.sL,y,!0,M[L.sL]):l(y);return L.r>0&&(B+=e.r),"continuous"==L.subLanguageMode&&(M[L.sL]=e.top),p(e.language,e.value,!1,!0)}function b(){return void 0!==L.sL?h():d()}function v(e,t){var r=e.cN?p(e.cN,"",!0):"";e.rB?(k+=r,y=""):e.eB?(k+=n(t)+r,y=""):(k+=r,y=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(y+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(y+=t),k+=b();do L.cN&&(k+="</span>"),B+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),y="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(f(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"<unnamed>")+'"');return y+=t,t.length||1}var E=N(e);if(!E)throw new Error('Unknown language: "'+e+'"');c(E);var R,L=i||E,M={},k="";for(R=L;R!=E;R=R.parent)R.cN&&(k=p(R.cN,"",!0)+k);var y="",B=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),R=L;R.parent;R=R.parent)R.cN&&(k+="</span>");return{r:B,value:k,language:e,top:L}}catch(S){if(-1!=S.message.indexOf("Illegal"))return{r:0,value:n(t)};throw S}}function l(e,t){t=t||x.languages||Object.keys(w);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(N(n)){var t=s(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function f(e){return x.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,x.tabReplace)})),x.useBR&&(e=e.replace(/\n/g,"<br>")),e}function g(e,n,t){var r=n?E[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=a(e);if(!/no(-?)highlight|plain|text/.test(n)){var t;x.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):t=e;var r=t.textContent,i=n?s(n,r,!0):l(r),c=o(t);if(c.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=i.value,i.value=u(c,o(p),r)}i.value=f(i.value),e.innerHTML=i.value,e.className=g(e.className,n,i.language),e.result={language:i.language,re:i.r},i.second_best&&(e.second_best={language:i.second_best.language,re:i.second_best.r})}}function d(e){x=i(x,e)}function h(){if(!h.called){h.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function b(){addEventListener("DOMContentLoaded",h,!1),addEventListener("load",h,!1)}function v(n,t){var r=w[n]=t(e);r.aliases&&r.aliases.forEach(function(e){E[e]=n})}function m(){return Object.keys(w)}function N(e){return w[e]||w[E[e]]}var x={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},w={},E={};return e.highlight=s,e.highlightAuto=l,e.fixMarkup=f,e.highlightBlock=p,e.configure=d,e.initHighlighting=h,e.initHighlightingOnLoad=b,e.registerLanguage=v,e.listLanguages=m,e.getLanguage=N,e.inherit=i,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("objectivec",function(e){var t={cN:"built_in",b:"(AV|CA|CF|CG|CI|MK|MP|NS|UI)\\w+"},i={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},o=/[a-zA-Z@][a-zA-Z0-9_]*/,n="@interface @class @protocol @implementation";return{aliases:["m","mm","objc","obj-c"],k:i,l:o,i:"</",c:[t,e.CLCM,e.CBCM,e.CNM,e.QSM,{cN:"string",v:[{b:'@"',e:'"',i:"\\n",c:[e.BE]},{b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"}]},{cN:"preprocessor",b:"#",e:"$",c:[{cN:"title",v:[{b:'"',e:'"'},{b:"<",e:">"}]}]},{cN:"class",b:"("+n.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:n,l:o,c:[e.UTM]},{cN:"variable",b:"\\."+e.UIR,r:0}]}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>]/,c:[{cN:"operator",bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate savepoint release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke",e:/;/,eW:!0,k:{keyword:"abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length character_length charindex charset check checksum checksum_agg choose close coalesce coercibility collate collation collationproperty column columns columns_updated commit compress concat concat_ws concurrent connect connection connection_id consistent constraint constraints continue contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime data database databases datalength date_add date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec engine engines eomonth errors escape escaped event eventdata events except exception exec execute exists exp explain export_set extended external extract fast fetch field fields find_in_set first first_value floor flush for force foreign format found found_rows from from_base64 from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner innodb input insert install instr intersect into is is_free_lock is_ipv4 is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names national natural nchar next no no_write_to_binlog not now nullif nvarchar oct octet_length of old_password on only open optimize option optionally or ord order outer outfile output pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges procedure procedure_analyze processlist profile profiles public publishingservername purge quarter query quick quote quotename radians rand read references regexp relative relaylog release release_lock rename repair repeat replace replicate reset restore restrict return returns reverse revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll sec_to_time second section select serializable server session session_user set sha sha1 sha2 share show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sql_variant_property sqlstate sqrt square start starting status std stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short validate_password_strength value values var var_pop var_samp variables variance varp version view warnings week weekday weekofyear weight_string when whenever where with work write xml xor year yearweek zon",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int integer interval number numeric real serial smallint varchar varying int8 serial8 text"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"pi",r:10,v:[{b:/^\s*('|")use strict('|")/},{b:/^\s*('|")use asm('|")/}]},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",b:"\\b(0[xXbBoO][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/</,e:/>\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{bK:"import",e:"[;$]",k:"import from as",c:[e.ASM,e.QSM]},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]}]}});hljs.registerLanguage("scss",function(e){{var t="[a-zA-Z-][a-zA-Z0-9_-]*",i={cN:"variable",b:"(\\$"+t+")\\b"},r={cN:"function",b:t+"\\(",rB:!0,eE:!0,e:"\\("},o={cN:"hexcolor",b:"#[0-9A-Fa-f]+"};({cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{cN:"value",eW:!0,eE:!0,c:[r,o,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"important",b:"!important"}]}})}return{cI:!0,i:"[=/|']",c:[e.CLCM,e.CBCM,r,{cN:"id",b:"\\#[A-Za-z0-9_-]+",r:0},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"tag",b:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",r:0},{cN:"pseudo",b:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{cN:"pseudo",b:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},i,{cN:"attribute",b:"\\b(z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",i:"[^\\s]"},{cN:"value",b:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{cN:"value",b:":",e:";",c:[r,i,o,e.CSSNM,e.QSM,e.ASM,{cN:"important",b:"!important"}]},{cN:"at_rule",b:"@",e:"[{;]",k:"mixin include extend for if else each while charset import debug media page content font-face namespace warn",c:[r,i,e.QSM,e.ASM,o,e.CSSNM,{cN:"preprocessor",b:"\\s[A-Za-z0-9_.-]+",r:0}]}]}});hljs.registerLanguage("mel",function(e){return{k:"int float string vector matrix if else switch case default while do for in break continue global proc return about abs addAttr addAttributeEditorNodeHelp addDynamic addNewShelfTab addPP addPanelCategory addPrefixToName advanceToNextDrivenKey affectedNet affects aimConstraint air alias aliasAttr align alignCtx alignCurve alignSurface allViewFit ambientLight angle angleBetween animCone animCurveEditor animDisplay animView annotate appendStringArray applicationName applyAttrPreset applyTake arcLenDimContext arcLengthDimension arclen arrayMapper art3dPaintCtx artAttrCtx artAttrPaintVertexCtx artAttrSkinPaintCtx artAttrTool artBuildPaintMenu artFluidAttrCtx artPuttyCtx artSelectCtx artSetPaintCtx artUserPaintCtx assignCommand assignInputDevice assignViewportFactories attachCurve attachDeviceAttr attachSurface attrColorSliderGrp attrCompatibility attrControlGrp attrEnumOptionMenu attrEnumOptionMenuGrp attrFieldGrp attrFieldSliderGrp attrNavigationControlGrp attrPresetEditWin attributeExists attributeInfo attributeMenu attributeQuery autoKeyframe autoPlace bakeClip bakeFluidShading bakePartialHistory bakeResults bakeSimulation basename basenameEx batchRender bessel bevel bevelPlus binMembership bindSkin blend2 blendShape blendShapeEditor blendShapePanel blendTwoAttr blindDataType boneLattice boundary boxDollyCtx boxZoomCtx bufferCurve buildBookmarkMenu buildKeyframeMenu button buttonManip CBG cacheFile cacheFileCombine cacheFileMerge cacheFileTrack camera cameraView canCreateManip canvas capitalizeString catch catchQuiet ceil changeSubdivComponentDisplayLevel changeSubdivRegion channelBox character characterMap characterOutlineEditor characterize chdir checkBox checkBoxGrp checkDefaultRenderGlobals choice circle circularFillet clamp clear clearCache clip clipEditor clipEditorCurrentTimeCtx clipSchedule clipSchedulerOutliner clipTrimBefore closeCurve closeSurface cluster cmdFileOutput cmdScrollFieldExecuter cmdScrollFieldReporter cmdShell coarsenSubdivSelectionList collision color colorAtPoint colorEditor colorIndex colorIndexSliderGrp colorSliderButtonGrp colorSliderGrp columnLayout commandEcho commandLine commandPort compactHairSystem componentEditor compositingInterop computePolysetVolume condition cone confirmDialog connectAttr connectControl connectDynamic connectJoint connectionInfo constrain constrainValue constructionHistory container containsMultibyte contextInfo control convertFromOldLayers convertIffToPsd convertLightmap convertSolidTx convertTessellation convertUnit copyArray copyFlexor copyKey copySkinWeights cos cpButton cpCache cpClothSet cpCollision cpConstraint cpConvClothToMesh cpForces cpGetSolverAttr cpPanel cpProperty cpRigidCollisionFilter cpSeam cpSetEdit cpSetSolverAttr cpSolver cpSolverTypes cpTool cpUpdateClothUVs createDisplayLayer createDrawCtx createEditor createLayeredPsdFile createMotionField createNewShelf createNode createRenderLayer createSubdivRegion cross crossProduct ctxAbort ctxCompletion ctxEditMode ctxTraverse currentCtx currentTime currentTimeCtx currentUnit curve curveAddPtCtx curveCVCtx curveEPCtx curveEditorCtx curveIntersect curveMoveEPCtx curveOnSurface curveSketchCtx cutKey cycleCheck cylinder dagPose date defaultLightListCheckBox defaultNavigation defineDataServer defineVirtualDevice deformer deg_to_rad delete deleteAttr deleteShadingGroupsAndMaterials deleteShelfTab deleteUI deleteUnusedBrushes delrandstr detachCurve detachDeviceAttr detachSurface deviceEditor devicePanel dgInfo dgdirty dgeval dgtimer dimWhen directKeyCtx directionalLight dirmap dirname disable disconnectAttr disconnectJoint diskCache displacementToPoly displayAffected displayColor displayCull displayLevelOfDetail displayPref displayRGBColor displaySmoothness displayStats displayString displaySurface distanceDimContext distanceDimension doBlur dolly dollyCtx dopeSheetEditor dot dotProduct doubleProfileBirailSurface drag dragAttrContext draggerContext dropoffLocator duplicate duplicateCurve duplicateSurface dynCache dynControl dynExport dynExpression dynGlobals dynPaintEditor dynParticleCtx dynPref dynRelEdPanel dynRelEditor dynamicLoad editAttrLimits editDisplayLayerGlobals editDisplayLayerMembers editRenderLayerAdjustment editRenderLayerGlobals editRenderLayerMembers editor editorTemplate effector emit emitter enableDevice encodeString endString endsWith env equivalent equivalentTol erf error eval evalDeferred evalEcho event exactWorldBoundingBox exclusiveLightCheckBox exec executeForEachObject exists exp expression expressionEditorListen extendCurve extendSurface extrude fcheck fclose feof fflush fgetline fgetword file fileBrowserDialog fileDialog fileExtension fileInfo filetest filletCurve filter filterCurve filterExpand filterStudioImport findAllIntersections findAnimCurves findKeyframe findMenuItem findRelatedSkinCluster finder firstParentOf fitBspline flexor floatEq floatField floatFieldGrp floatScrollBar floatSlider floatSlider2 floatSliderButtonGrp floatSliderGrp floor flow fluidCacheInfo fluidEmitter fluidVoxelInfo flushUndo fmod fontDialog fopen formLayout format fprint frameLayout fread freeFormFillet frewind fromNativePath fwrite gamma gauss geometryConstraint getApplicationVersionAsFloat getAttr getClassification getDefaultBrush getFileList getFluidAttr getInputDeviceRange getMayaPanelTypes getModifiers getPanel getParticleAttr getPluginResource getenv getpid glRender glRenderEditor globalStitch gmatch goal gotoBindPose grabColor gradientControl gradientControlNoAttr graphDollyCtx graphSelectContext graphTrackCtx gravity grid gridLayout group groupObjectsByName HfAddAttractorToAS HfAssignAS HfBuildEqualMap HfBuildFurFiles HfBuildFurImages HfCancelAFR HfConnectASToHF HfCreateAttractor HfDeleteAS HfEditAS HfPerformCreateAS HfRemoveAttractorFromAS HfSelectAttached HfSelectAttractors HfUnAssignAS hardenPointCurve hardware hardwareRenderPanel headsUpDisplay headsUpMessage help helpLine hermite hide hilite hitTest hotBox hotkey hotkeyCheck hsv_to_rgb hudButton hudSlider hudSliderButton hwReflectionMap hwRender hwRenderLoad hyperGraph hyperPanel hyperShade hypot iconTextButton iconTextCheckBox iconTextRadioButton iconTextRadioCollection iconTextScrollList iconTextStaticLabel ikHandle ikHandleCtx ikHandleDisplayScale ikSolver ikSplineHandleCtx ikSystem ikSystemInfo ikfkDisplayMethod illustratorCurves image imfPlugins inheritTransform insertJoint insertJointCtx insertKeyCtx insertKnotCurve insertKnotSurface instance instanceable instancer intField intFieldGrp intScrollBar intSlider intSliderGrp interToUI internalVar intersect iprEngine isAnimCurve isConnected isDirty isParentOf isSameObject isTrue isValidObjectName isValidString isValidUiName isolateSelect itemFilter itemFilterAttr itemFilterRender itemFilterType joint jointCluster jointCtx jointDisplayScale jointLattice keyTangent keyframe keyframeOutliner keyframeRegionCurrentTimeCtx keyframeRegionDirectKeyCtx keyframeRegionDollyCtx keyframeRegionInsertKeyCtx keyframeRegionMoveKeyCtx keyframeRegionScaleKeyCtx keyframeRegionSelectKeyCtx keyframeRegionSetKeyCtx keyframeRegionTrackCtx keyframeStats lassoContext lattice latticeDeformKeyCtx launch launchImageEditor layerButton layeredShaderPort layeredTexturePort layout layoutDialog lightList lightListEditor lightListPanel lightlink lineIntersection linearPrecision linstep listAnimatable listAttr listCameras listConnections listDeviceAttachments listHistory listInputDeviceAxes listInputDeviceButtons listInputDevices listMenuAnnotation listNodeTypes listPanelCategories listRelatives listSets listTransforms listUnselected listerEditor loadFluid loadNewShelf loadPlugin loadPluginLanguageResources loadPrefObjects localizedPanelLabel lockNode loft log longNameOf lookThru ls lsThroughFilter lsType lsUI Mayatomr mag makeIdentity makeLive makePaintable makeRoll makeSingleSurface makeTubeOn makebot manipMoveContext manipMoveLimitsCtx manipOptions manipRotateContext manipRotateLimitsCtx manipScaleContext manipScaleLimitsCtx marker match max memory menu menuBarLayout menuEditor menuItem menuItemToShelf menuSet menuSetPref messageLine min minimizeApp mirrorJoint modelCurrentTimeCtx modelEditor modelPanel mouse movIn movOut move moveIKtoFK moveKeyCtx moveVertexAlongDirection multiProfileBirailSurface mute nParticle nameCommand nameField namespace namespaceInfo newPanelItems newton nodeCast nodeIconButton nodeOutliner nodePreset nodeType noise nonLinear normalConstraint normalize nurbsBoolean nurbsCopyUVSet nurbsCube nurbsEditUV nurbsPlane nurbsSelect nurbsSquare nurbsToPoly nurbsToPolygonsPref nurbsToSubdiv nurbsToSubdivPref nurbsUVSet nurbsViewDirectionVector objExists objectCenter objectLayer objectType objectTypeUI obsoleteProc oceanNurbsPreviewPlane offsetCurve offsetCurveOnSurface offsetSurface openGLExtension openMayaPref optionMenu optionMenuGrp optionVar orbit orbitCtx orientConstraint outlinerEditor outlinerPanel overrideModifier paintEffectsDisplay pairBlend palettePort paneLayout panel panelConfiguration panelHistory paramDimContext paramDimension paramLocator parent parentConstraint particle particleExists particleInstancer particleRenderInfo partition pasteKey pathAnimation pause pclose percent performanceOptions pfxstrokes pickWalk picture pixelMove planarSrf plane play playbackOptions playblast plugAttr plugNode pluginInfo pluginResourceUtil pointConstraint pointCurveConstraint pointLight pointMatrixMult pointOnCurve pointOnSurface pointPosition poleVectorConstraint polyAppend polyAppendFacetCtx polyAppendVertex polyAutoProjection polyAverageNormal polyAverageVertex polyBevel polyBlendColor polyBlindData polyBoolOp polyBridgeEdge polyCacheMonitor polyCheck polyChipOff polyClipboard polyCloseBorder polyCollapseEdge polyCollapseFacet polyColorBlindData polyColorDel polyColorPerVertex polyColorSet polyCompare polyCone polyCopyUV polyCrease polyCreaseCtx polyCreateFacet polyCreateFacetCtx polyCube polyCut polyCutCtx polyCylinder polyCylindricalProjection polyDelEdge polyDelFacet polyDelVertex polyDuplicateAndConnect polyDuplicateEdge polyEditUV polyEditUVShell polyEvaluate polyExtrudeEdge polyExtrudeFacet polyExtrudeVertex polyFlipEdge polyFlipUV polyForceUV polyGeoSampler polyHelix polyInfo polyInstallAction polyLayoutUV polyListComponentConversion polyMapCut polyMapDel polyMapSew polyMapSewMove polyMergeEdge polyMergeEdgeCtx polyMergeFacet polyMergeFacetCtx polyMergeUV polyMergeVertex polyMirrorFace polyMoveEdge polyMoveFacet polyMoveFacetUV polyMoveUV polyMoveVertex polyNormal polyNormalPerVertex polyNormalizeUV polyOptUvs polyOptions polyOutput polyPipe polyPlanarProjection polyPlane polyPlatonicSolid polyPoke polyPrimitive polyPrism polyProjection polyPyramid polyQuad polyQueryBlindData polyReduce polySelect polySelectConstraint polySelectConstraintMonitor polySelectCtx polySelectEditCtx polySeparate polySetToFaceNormal polySewEdge polyShortestPathCtx polySmooth polySoftEdge polySphere polySphericalProjection polySplit polySplitCtx polySplitEdge polySplitRing polySplitVertex polyStraightenUVBorder polySubdivideEdge polySubdivideFacet polyToSubdiv polyTorus polyTransfer polyTriangulate polyUVSet polyUnite polyWedgeFace popen popupMenu pose pow preloadRefEd print progressBar progressWindow projFileViewer projectCurve projectTangent projectionContext projectionManip promptDialog propModCtx propMove psdChannelOutliner psdEditTextureFile psdExport psdTextureFile putenv pwd python querySubdiv quit rad_to_deg radial radioButton radioButtonGrp radioCollection radioMenuItemCollection rampColorPort rand randomizeFollicles randstate rangeControl readTake rebuildCurve rebuildSurface recordAttr recordDevice redo reference referenceEdit referenceQuery refineSubdivSelectionList refresh refreshAE registerPluginResource rehash reloadImage removeJoint removeMultiInstance removePanelCategory rename renameAttr renameSelectionList renameUI render renderGlobalsNode renderInfo renderLayerButton renderLayerParent renderLayerPostProcess renderLayerUnparent renderManip renderPartition renderQualityNode renderSettings renderThumbnailUpdate renderWindowEditor renderWindowSelectContext renderer reorder reorderDeformers requires reroot resampleFluid resetAE resetPfxToPolyCamera resetTool resolutionNode retarget reverseCurve reverseSurface revolve rgb_to_hsv rigidBody rigidSolver roll rollCtx rootOf rot rotate rotationInterpolation roundConstantRadius rowColumnLayout rowLayout runTimeCommand runup sampleImage saveAllShelves saveAttrPreset saveFluid saveImage saveInitialState saveMenu savePrefObjects savePrefs saveShelf saveToolSettings scale scaleBrushBrightness scaleComponents scaleConstraint scaleKey scaleKeyCtx sceneEditor sceneUIReplacement scmh scriptCtx scriptEditorInfo scriptJob scriptNode scriptTable scriptToShelf scriptedPanel scriptedPanelType scrollField scrollLayout sculpt searchPathArray seed selLoadSettings select selectContext selectCurveCV selectKey selectKeyCtx selectKeyframeRegionCtx selectMode selectPref selectPriority selectType selectedNodes selectionConnection separator setAttr setAttrEnumResource setAttrMapping setAttrNiceNameResource setConstraintRestPosition setDefaultShadingGroup setDrivenKeyframe setDynamic setEditCtx setEditor setFluidAttr setFocus setInfinity setInputDeviceMapping setKeyCtx setKeyPath setKeyframe setKeyframeBlendshapeTargetWts setMenuMode setNodeNiceNameResource setNodeTypeFlag setParent setParticleAttr setPfxToPolyCamera setPluginResource setProject setStampDensity setStartupMessage setState setToolTo setUITemplate setXformManip sets shadingConnection shadingGeometryRelCtx shadingLightRelCtx shadingNetworkCompare shadingNode shapeCompare shelfButton shelfLayout shelfTabLayout shellField shortNameOf showHelp showHidden showManipCtx showSelectionInTitle showShadingGroupAttrEditor showWindow sign simplify sin singleProfileBirailSurface size sizeBytes skinCluster skinPercent smoothCurve smoothTangentSurface smoothstep snap2to2 snapKey snapMode snapTogetherCtx snapshot soft softMod softModCtx sort sound soundControl source spaceLocator sphere sphrand spotLight spotLightPreviewPort spreadSheetEditor spring sqrt squareSurface srtContext stackTrace startString startsWith stitchAndExplodeShell stitchSurface stitchSurfacePoints strcmp stringArrayCatenate stringArrayContains stringArrayCount stringArrayInsertAtIndex stringArrayIntersector stringArrayRemove stringArrayRemoveAtIndex stringArrayRemoveDuplicates stringArrayRemoveExact stringArrayToString stringToStringArray strip stripPrefixFromName stroke subdAutoProjection subdCleanTopology subdCollapse subdDuplicateAndConnect subdEditUV subdListComponentConversion subdMapCut subdMapSewMove subdMatchTopology subdMirror subdToBlind subdToPoly subdTransferUVsToCache subdiv subdivCrease subdivDisplaySmoothness substitute substituteAllString substituteGeometry substring surface surfaceSampler surfaceShaderList swatchDisplayPort switchTable symbolButton symbolCheckBox sysFile system tabLayout tan tangentConstraint texLatticeDeformContext texManipContext texMoveContext texMoveUVShellContext texRotateContext texScaleContext texSelectContext texSelectShortestPathCtx texSmudgeUVContext texWinToolCtx text textCurves textField textFieldButtonGrp textFieldGrp textManip textScrollList textToShelf textureDisplacePlane textureHairColor texturePlacementContext textureWindow threadCount threePointArcCtx timeControl timePort timerX toNativePath toggle toggleAxis toggleWindowVisibility tokenize tokenizeList tolerance tolower toolButton toolCollection toolDropped toolHasOptions toolPropertyWindow torus toupper trace track trackCtx transferAttributes transformCompare transformLimits translator trim trunc truncateFluidCache truncateHairCache tumble tumbleCtx turbulence twoPointArcCtx uiRes uiTemplate unassignInputDevice undo undoInfo ungroup uniform unit unloadPlugin untangleUV untitledFileName untrim upAxis updateAE userCtx uvLink uvSnapshot validateShelfName vectorize view2dToolCtx viewCamera viewClipPlane viewFit viewHeadOn viewLookAt viewManip viewPlace viewSet visor volumeAxis vortex waitCursor warning webBrowser webBrowserPrefs whatIs window windowPref wire wireContext workspace wrinkle wrinkleContext writeTake xbmLangPathList xform",i:"</",c:[e.CNM,e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE]},{cN:"variable",v:[{b:"\\$\\d"},{b:"[\\$\\%\\@](\\^\\w\\b|#\\w+|[^\\s\\w{]|{\\w+}|\\w+)"},{b:"\\*(\\^\\w\\b|#\\w+|[^\\s\\w{]|{\\w+}|\\w+)",r:0}]},e.CLCM,e.CBCM]}});hljs.registerLanguage("d",function(e){var r={keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},t="(0|[1-9][\\d_]*)",a="(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)",i="0[bB][01_]+",n="([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)",c="0[xX]"+n,_="([eE][+-]?"+a+")",d="("+a+"(\\.\\d*|"+_+")|\\d+\\."+a+a+"|\\."+t+_+"?)",o="(0[xX]("+n+"\\."+n+"|\\.?"+n+")[pP][+-]?"+a+")",s="("+t+"|"+i+"|"+c+")",l="("+o+"|"+d+")",u="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",b={cN:"number",b:"\\b"+s+"(L|u|U|Lu|LU|uL|UL)?",r:0},f={cN:"number",b:"\\b("+l+"([fF]|L|i|[fF]i|Li)?|"+s+"(i|[fF]i|Li))",r:0},g={cN:"string",b:"'("+u+"|.)",e:"'",i:"."},h={b:u,r:0},p={cN:"string",b:'"',c:[h],e:'"[cwd]?'},w={cN:"string",b:'[rq]"',e:'"[cwd]?',r:5},N={cN:"string",b:"`",e:"`[cwd]?"},A={cN:"string",b:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',r:10},F={cN:"string",b:'q"\\{',e:'\\}"'},m={cN:"shebang",b:"^#!",e:"$",r:5},y={cN:"preprocessor",b:"#(line)",e:"$",r:5},L={cN:"keyword",b:"@[a-zA-Z_][a-zA-Z_\\d]*"},v=e.C("\\/\\+","\\+\\/",{c:["self"],r:10});return{l:e.UIR,k:r,c:[e.CLCM,e.CBCM,v,A,p,w,N,F,f,b,g,m,y,L]}});hljs.registerLanguage("ruleslanguage",function(T){return{k:{keyword:"BILL_PERIOD BILL_START BILL_STOP RS_EFFECTIVE_START RS_EFFECTIVE_STOP RS_JURIS_CODE RS_OPCO_CODE INTDADDATTRIBUTE|5 INTDADDVMSG|5 INTDBLOCKOP|5 INTDBLOCKOPNA|5 INTDCLOSE|5 INTDCOUNT|5 INTDCOUNTSTATUSCODE|5 INTDCREATEMASK|5 INTDCREATEDAYMASK|5 INTDCREATEFACTORMASK|5 INTDCREATEHANDLE|5 INTDCREATEOVERRIDEDAYMASK|5 INTDCREATEOVERRIDEMASK|5 INTDCREATESTATUSCODEMASK|5 INTDCREATETOUPERIOD|5 INTDDELETE|5 INTDDIPTEST|5 INTDEXPORT|5 INTDGETERRORCODE|5 INTDGETERRORMESSAGE|5 INTDISEQUAL|5 INTDJOIN|5 INTDLOAD|5 INTDLOADACTUALCUT|5 INTDLOADDATES|5 INTDLOADHIST|5 INTDLOADLIST|5 INTDLOADLISTDATES|5 INTDLOADLISTENERGY|5 INTDLOADLISTHIST|5 INTDLOADRELATEDCHANNEL|5 INTDLOADSP|5 INTDLOADSTAGING|5 INTDLOADUOM|5 INTDLOADUOMDATES|5 INTDLOADUOMHIST|5 INTDLOADVERSION|5 INTDOPEN|5 INTDREADFIRST|5 INTDREADNEXT|5 INTDRECCOUNT|5 INTDRELEASE|5 INTDREPLACE|5 INTDROLLAVG|5 INTDROLLPEAK|5 INTDSCALAROP|5 INTDSCALE|5 INTDSETATTRIBUTE|5 INTDSETDSTPARTICIPANT|5 INTDSETSTRING|5 INTDSETVALUE|5 INTDSETVALUESTATUS|5 INTDSHIFTSTARTTIME|5 INTDSMOOTH|5 INTDSORT|5 INTDSPIKETEST|5 INTDSUBSET|5 INTDTOU|5 INTDTOURELEASE|5 INTDTOUVALUE|5 INTDUPDATESTATS|5 INTDVALUE|5 STDEV INTDDELETEEX|5 INTDLOADEXACTUAL|5 INTDLOADEXCUT|5 INTDLOADEXDATES|5 INTDLOADEX|5 INTDLOADEXRELATEDCHANNEL|5 INTDSAVEEX|5 MVLOAD|5 MVLOADACCT|5 MVLOADACCTDATES|5 MVLOADACCTHIST|5 MVLOADDATES|5 MVLOADHIST|5 MVLOADLIST|5 MVLOADLISTDATES|5 MVLOADLISTHIST|5 IF FOR NEXT DONE SELECT END CALL ABORT CLEAR CHANNEL FACTOR LIST NUMBER OVERRIDE SET WEEK DISTRIBUTIONNODE ELSE WHEN THEN OTHERWISE IENUM CSV INCLUDE LEAVE RIDER SAVE DELETE NOVALUE SECTION WARN SAVE_UPDATE DETERMINANT LABEL REPORT REVENUE EACH IN FROM TOTAL CHARGE BLOCK AND OR CSV_FILE RATE_CODE AUXILIARY_DEMAND UIDACCOUNT RS BILL_PERIOD_SELECT HOURS_PER_MONTH INTD_ERROR_STOP SEASON_SCHEDULE_NAME ACCOUNTFACTOR ARRAYUPPERBOUND CALLSTOREDPROC GETADOCONNECTION GETCONNECT GETDATASOURCE GETQUALIFIER GETUSERID HASVALUE LISTCOUNT LISTOP LISTUPDATE LISTVALUE PRORATEFACTOR RSPRORATE SETBINPATH SETDBMONITOR WQ_OPEN BILLINGHOURS DATE DATEFROMFLOAT DATETIMEFROMSTRING DATETIMETOSTRING DATETOFLOAT DAY DAYDIFF DAYNAME DBDATETIME HOUR MINUTE MONTH MONTHDIFF MONTHHOURS MONTHNAME ROUNDDATE SAMEWEEKDAYLASTYEAR SECOND WEEKDAY WEEKDIFF YEAR YEARDAY YEARSTR COMPSUM HISTCOUNT HISTMAX HISTMIN HISTMINNZ HISTVALUE MAXNRANGE MAXRANGE MINRANGE COMPIKVA COMPKVA COMPKVARFROMKQKW COMPLF IDATTR FLAG LF2KW LF2KWH MAXKW POWERFACTOR READING2USAGE AVGSEASON MAXSEASON MONTHLYMERGE SEASONVALUE SUMSEASON ACCTREADDATES ACCTTABLELOAD CONFIGADD CONFIGGET CREATEOBJECT CREATEREPORT EMAILCLIENT EXPBLKMDMUSAGE EXPMDMUSAGE EXPORT_USAGE FACTORINEFFECT GETUSERSPECIFIEDSTOP INEFFECT ISHOLIDAY RUNRATE SAVE_PROFILE SETREPORTTITLE USEREXIT WATFORRUNRATE TO TABLE ACOS ASIN ATAN ATAN2 BITAND CEIL COS COSECANT COSH COTANGENT DIVQUOT DIVREM EXP FABS FLOOR FMOD FREPM FREXPN LOG LOG10 MAX MAXN MIN MINNZ MODF POW ROUND ROUND2VALUE ROUNDINT SECANT SIN SINH SQROOT TAN TANH FLOAT2STRING FLOAT2STRINGNC INSTR LEFT LEN LTRIM MID RIGHT RTRIM STRING STRINGNC TOLOWER TOUPPER TRIM NUMDAYS READ_DATE STAGING",built_in:"IDENTIFIER OPTIONS XML_ELEMENT XML_OP XML_ELEMENT_OF DOMDOCCREATE DOMDOCLOADFILE DOMDOCLOADXML DOMDOCSAVEFILE DOMDOCGETROOT DOMDOCADDPI DOMNODEGETNAME DOMNODEGETTYPE DOMNODEGETVALUE DOMNODEGETCHILDCT DOMNODEGETFIRSTCHILD DOMNODEGETSIBLING DOMNODECREATECHILDELEMENT DOMNODESETATTRIBUTE DOMNODEGETCHILDELEMENTCT DOMNODEGETFIRSTCHILDELEMENT DOMNODEGETSIBLINGELEMENT DOMNODEGETATTRIBUTECT DOMNODEGETATTRIBUTEI DOMNODEGETATTRIBUTEBYNAME DOMNODEGETBYNAME"},c:[T.CLCM,T.CBCM,T.ASM,T.QSM,T.CNM,{cN:"array",b:"#[a-zA-Z .]+"}]}});hljs.registerLanguage("actionscript",function(e){var a="[a-zA-Z_$][a-zA-Z0-9_$]*",c="([*]|[a-zA-Z_$][a-zA-Z0-9_$]*)",t={cN:"rest_arg",b:"[.]{3}",e:a,r:10};return{aliases:["as"],k:{keyword:"as break case catch class const continue default delete do dynamic each else extends final finally for function get if implements import in include instanceof interface internal is namespace native new override package private protected public return set static super switch this throw try typeof use var void while with",literal:"true false null undefined"},c:[e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{cN:"package",bK:"package",e:"{",c:[e.TM]},{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.TM]},{cN:"preprocessor",bK:"import include",e:";"},{cN:"function",bK:"function",e:"[{;]",eE:!0,i:"\\S",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",c:[e.ASM,e.QSM,e.CLCM,e.CBCM,t]},{cN:"type",b:":",e:c,r:10}]}]}});hljs.registerLanguage("coffeescript",function(e){var c={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module global window document"},n="[A-Za-z$_][0-9A-Za-z$_]*",t={cN:"subst",b:/#\{/,e:/}/,k:c},r=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,t]},{b:/"/,e:/"/,c:[e.BE,t]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[t,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+n},{b:"`",e:"`",eB:!0,eE:!0,sL:"javascript"}];t.c=r;var i=e.inherit(e.TM,{b:n}),s="(\\(.*\\))?\\s*\\B[-=]>",o={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:c,c:["self"].concat(r)}]};return{aliases:["coffee","cson","iced"],k:c,i:/\/\*/,c:r.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+n+"\\s*=\\s*"+s,e:"[-=]>",rB:!0,c:[i,o]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:s,e:"[-=]>",rB:!0,c:[o]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{cN:"attribute",b:n+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("tex",function(c){var e={cN:"command",b:"\\\\[a-zA-Zа-яА-я]+[\\*]?"},m={cN:"command",b:"\\\\[^a-zA-Zа-яА-я0-9]"},r={cN:"special",b:"[{}\\[\\]\\&#~]",r:0};return{c:[{b:"\\\\[a-zA-Zа-яА-я]+[\\*]? *= *-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",rB:!0,c:[e,m,{cN:"number",b:" *=",e:"-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",eB:!0}],r:10},e,m,r,{cN:"formula",b:"\\$\\$",e:"\\$\\$",c:[e,m,r],r:0},{cN:"formula",b:"\\$",e:"\\$",c:[e,m,r],r:0},c.C("%","$",{r:0})]}});hljs.registerLanguage("go",function(e){var t={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer",constant:"true false iota nil",typename:"bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{aliases:["golang"],k:t,i:"</",c:[e.CLCM,e.CBCM,e.QSM,{cN:"string",b:"'",e:"[^\\\\]'"},{cN:"string",b:"`",e:"`"},{cN:"number",b:e.CNR+"[dflsi]?",r:0},e.CNM]}});hljs.registerLanguage("vbscript-html",function(s){return{sL:"xml",subLanguageMode:"continuous",c:[{b:"<%",e:"%>",sL:"vbscript"}]}});hljs.registerLanguage("haskell",function(e){var c=[e.C("--","$"),e.C("{-","-}",{c:["self"]})],a={cN:"pragma",b:"{-#",e:"#-}"},i={cN:"preprocessor",b:"^#",e:"$"},n={cN:"type",b:"\\b[A-Z][\\w']*",r:0},t={cN:"container",b:"\\(",e:"\\)",i:'"',c:[a,i,{cN:"type",b:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TM,{b:"[_a-z][\\w']*"})].concat(c)},l={cN:"container",b:"{",e:"}",c:t.c};return{aliases:["hs"],k:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",c:[{cN:"module",b:"\\bmodule\\b",e:"where",k:"module where",c:[t].concat(c),i:"\\W\\.|;"},{cN:"import",b:"\\bimport\\b",e:"$",k:"import|0 qualified as hiding",c:[t].concat(c),i:"\\W\\.|;"},{cN:"class",b:"^(\\s*)?(class|instance)\\b",e:"where",k:"class family instance where",c:[n,t].concat(c)},{cN:"typedef",b:"\\b(data|(new)?type)\\b",e:"$",k:"data family type newtype deriving",c:[a,n,t,l].concat(c)},{cN:"default",bK:"default",e:"$",c:[n,t].concat(c)},{cN:"infix",bK:"infix infixl infixr",e:"$",c:[e.CNM].concat(c)},{cN:"foreign",b:"\\bforeign\\b",e:"$",k:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",c:[n,e.QSM].concat(c)},{cN:"shebang",b:"#!\\/usr\\/bin\\/env runhaskell",e:"$"},a,i,e.QSM,e.CNM,n,e.inherit(e.TM,{b:"^[_a-z][\\w']*"}),{b:"->|<-"}].concat(c)}});hljs.registerLanguage("scilab",function(e){var n=[e.CNM,{cN:"string",b:"'|\"",e:"'|\"",c:[e.BE,{b:"''"}]}];return{aliases:["sci"],k:{keyword:"abort break case clear catch continue do elseif else endfunction end for functionglobal if pause return resume select try then while%f %F %t %T %pi %eps %inf %nan %e %i %z %s",built_in:"abs and acos asin atan ceil cd chdir clearglobal cosh cos cumprod deff disp errorexec execstr exists exp eye gettext floor fprintf fread fsolve imag isdef isemptyisinfisnan isvector lasterror length load linspace list listfiles log10 log2 logmax min msprintf mclose mopen ones or pathconvert poly printf prod pwd rand realround sinh sin size gsort sprintf sqrt strcat strcmps tring sum system tanh tantype typename warning zeros matrix"},i:'("|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bK:"function endfunction",e:"$",k:"function endfunction|10",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)"}]},{cN:"transposed_variable",b:"[a-zA-Z_][a-zA-Z_0-9]*('+[\\.']*|[\\.']+)",e:"",r:0},{cN:"matrix",b:"\\[",e:"\\]'*[\\.']*",r:0,c:n},e.C("//","$")].concat(n)}});hljs.registerLanguage("profile",function(e){return{c:[e.CNM,{cN:"built_in",b:"{",e:"}$",eB:!0,eE:!0,c:[e.ASM,e.QSM],r:0},{cN:"filename",b:"[a-zA-Z_][\\da-zA-Z_]+\\.[\\da-zA-Z_]{1,3}",e:":",eE:!0},{cN:"header",b:"(ncalls|tottime|cumtime)",e:"$",k:"ncalls tottime|10 cumtime|10 filename",r:10},{cN:"summary",b:"function calls",e:"$",c:[e.CNM],r:10},e.ASM,e.QSM,{cN:"function",b:"\\(",e:"\\)$",c:[e.UTM],r:0}]}});hljs.registerLanguage("thrift",function(e){var t="bool byte i16 i32 i64 double string binary";return{k:{keyword:"namespace const typedef struct enum service exception void oneway set list map required optional",built_in:t,literal:"true false"},c:[e.QSM,e.NM,e.CLCM,e.CBCM,{cN:"class",bK:"struct enum service exception",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{b:"\\b(set|list|map)\\s*<",e:">",k:t,c:["self"]}]}});hljs.registerLanguage("matlab",function(e){var a=[e.CNM,{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]}],s={r:0,c:[{cN:"operator",b:/'['\.]*/}]};return{k:{keyword:"break case catch classdef continue else elseif end enumerated events for function global if methods otherwise parfor persistent properties return spmd switch try while",built_in:"sin sind sinh asin asind asinh cos cosd cosh acos acosd acosh tan tand tanh atan atand atan2 atanh sec secd sech asec asecd asech csc cscd csch acsc acscd acsch cot cotd coth acot acotd acoth hypot exp expm1 log log1p log10 log2 pow2 realpow reallog realsqrt sqrt nthroot nextpow2 abs angle complex conj imag real unwrap isreal cplxpair fix floor ceil round mod rem sign airy besselj bessely besselh besseli besselk beta betainc betaln ellipj ellipke erf erfc erfcx erfinv expint gamma gammainc gammaln psi legendre cross dot factor isprime primes gcd lcm rat rats perms nchoosek factorial cart2sph cart2pol pol2cart sph2cart hsv2rgb rgb2hsv zeros ones eye repmat rand randn linspace logspace freqspace meshgrid accumarray size length ndims numel disp isempty isequal isequalwithequalnans cat reshape diag blkdiag tril triu fliplr flipud flipdim rot90 find sub2ind ind2sub bsxfun ndgrid permute ipermute shiftdim circshift squeeze isscalar isvector ans eps realmax realmin pi i inf nan isnan isinf isfinite j why compan gallery hadamard hankel hilb invhilb magic pascal rosser toeplitz vander wilkinson"},i:'(//|"|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bK:"function",e:"$",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)"},{cN:"params",b:"\\[",e:"\\]"}]},{b:/[a-zA-Z_][a-zA-Z_0-9]*'['\.]*/,rB:!0,r:0,c:[{b:/[a-zA-Z_][a-zA-Z_0-9]*/,r:0},s.c[0]]},{cN:"matrix",b:"\\[",e:"\\]",c:a,r:0,starts:s},{cN:"cell",b:"\\{",e:/}/,c:a,r:0,starts:s},{b:/\)/,r:0,starts:s},e.C("^\\s*\\%\\{\\s*$","^\\s*\\%\\}\\s*$"),e.C("\\%","$")].concat(a)}});hljs.registerLanguage("vbscript",function(e){return{aliases:["vbs"],cI:!0,k:{keyword:"call class const dim do loop erase execute executeglobal exit for each next function if then else on error option explicit new private property let get public randomize redim rem select case set stop sub while wend with end to elseif is or xor and not class_initialize class_terminate default preserve in me byval byref step resume goto",built_in:"lcase month vartype instrrev ubound setlocale getobject rgb getref string weekdayname rnd dateadd monthname now day minute isarray cbool round formatcurrency conversions csng timevalue second year space abs clng timeserial fixs len asc isempty maths dateserial atn timer isobject filter weekday datevalue ccur isdate instr datediff formatdatetime replace isnull right sgn array snumeric log cdbl hex chr lbound msgbox ucase getlocale cos cdate cbyte rtrim join hour oct typename trim strcomp int createobject loadpicture tan formatnumber mid scriptenginebuildversion scriptengine split scriptengineminorversion cint sin datepart ltrim sqr scriptenginemajorversion time derived eval date formatpercent exp inputbox left ascw chrw regexp server response request cstr err",literal:"true false null nothing empty"},i:"//",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C(/'/,/$/,{r:0}),e.CNM]}});hljs.registerLanguage("capnproto",function(t){return{aliases:["capnp"],k:{keyword:"struct enum interface union group import using const annotation extends in of on as with from fixed",built_in:"Void Bool Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float32 Float64 Text Data AnyPointer AnyStruct Capability List",literal:"true false"},c:[t.QSM,t.NM,t.HCM,{cN:"shebang",b:/@0x[\w\d]{16};/,i:/\n/},{cN:"number",b:/@\d+\b/},{cN:"class",bK:"struct enum",e:/\{/,i:/\n/,c:[t.inherit(t.TM,{starts:{eW:!0,eE:!0}})]},{cN:"class",bK:"interface",e:/\{/,i:/\n/,c:[t.inherit(t.TM,{starts:{eW:!0,eE:!0}})]}]}});hljs.registerLanguage("xl",function(e){var t="ObjectLoader Animate MovieCredits Slides Filters Shading Materials LensFlare Mapping VLCAudioVideo StereoDecoder PointCloud NetworkAccess RemoteControl RegExp ChromaKey Snowfall NodeJS Speech Charts",o={keyword:"if then else do while until for loop import with is as where when by data constant",literal:"true false nil",type:"integer real text name boolean symbol infix prefix postfix block tree",built_in:"in mod rem and or xor not abs sign floor ceil sqrt sin cos tan asin acos atan exp expm1 log log2 log10 log1p pi at",module:t,id:"text_length text_range text_find text_replace contains page slide basic_slide title_slide title subtitle fade_in fade_out fade_at clear_color color line_color line_width texture_wrap texture_transform texture scale_?x scale_?y scale_?z? translate_?x translate_?y translate_?z? rotate_?x rotate_?y rotate_?z? rectangle circle ellipse sphere path line_to move_to quad_to curve_to theme background contents locally time mouse_?x mouse_?y mouse_buttons"},a={cN:"constant",b:"[A-Z][A-Z_0-9]+",r:0},r={cN:"variable",b:"([A-Z][a-z_0-9]+)+",r:0},i={cN:"id",b:"[a-z][a-z_0-9]+",r:0},l={cN:"string",b:'"',e:'"',i:"\\n"},n={cN:"string",b:"'",e:"'",i:"\\n"},s={cN:"string",b:"<<",e:">>"},c={cN:"number",b:"[0-9]+#[0-9A-Z_]+(\\.[0-9-A-Z_]+)?#?([Ee][+-]?[0-9]+)?",r:10},_={cN:"import",bK:"import",e:"$",k:{keyword:"import",module:t},r:0,c:[l]},d={cN:"function",b:"[a-z].*->"};return{aliases:["tao"],l:/[a-zA-Z][a-zA-Z0-9_?]*/,k:o,c:[e.CLCM,e.CBCM,l,n,s,d,_,a,r,i,c,e.NM]}});hljs.registerLanguage("scala",function(e){var t={cN:"annotation",b:"@[A-Za-z]+"},a={cN:"string",b:'u?r?"""',e:'"""',r:10},r={cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},c={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},i={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,r:0},l={cN:"class",bK:"class object trait type",e:/[:={\[(\n;]/,c:[{cN:"keyword",bK:"extends with",r:10},i]},n={cN:"function",bK:"def val",e:/[:={\[(\n;]/,c:[i]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,a,e.QSM,r,c,n,l,e.CNM,t]}});hljs.registerLanguage("elixir",function(e){var n="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?",r="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",b="and false then defined module in return redo retry end for true self when next until do begin unless nil break not case cond alias while ensure or include use alias fn quote",c={cN:"subst",b:"#\\{",e:"}",l:n,k:b},a={cN:"string",c:[e.BE,c],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]},i={cN:"function",bK:"def defp defmacro",e:/\B\b/,c:[e.inherit(e.TM,{b:n,endsParent:!0})]},s=e.inherit(i,{cN:"class",bK:"defmodule defrecord",e:/\bdo\b|$|;/}),l=[a,e.HCM,s,i,{cN:"constant",b:"(\\b[A-Z_]\\w*(.)?)+",r:0},{cN:"symbol",b:":",c:[a,{b:r}],r:0},{cN:"symbol",b:n+":",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"->"},{b:"("+e.RSR+")\\s*",c:[e.HCM,{cN:"regexp",i:"\\n",c:[e.BE,c],v:[{b:"/",e:"/[a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];return c.c=l,{l:n,k:b,c:l}});hljs.registerLanguage("sml",function(e){return{aliases:["ml"],k:{keyword:"abstype and andalso as case datatype do else end eqtype exception fn fun functor handle if in include infix infixr let local nonfix of op open orelse raise rec sharing sig signature struct structure then type val with withtype where while",built_in:"array bool char exn int list option order real ref string substring vector unit word",literal:"true false NONE SOME LESS EQUAL GREATER nil"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)"},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"tag",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*"},e.inherit(e.ASM,{cN:"char",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}});hljs.registerLanguage("apache",function(e){var r={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"tag",b:"</?",e:">"},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",r]},r,e.QSM]}}],i:/\S/}});hljs.registerLanguage("dockerfile",function(n){return{aliases:["docker"],cI:!0,k:{built_ins:"from maintainer cmd expose add copy entrypoint volume user workdir onbuild run env"},c:[n.HCM,{k:{built_in:"run cmd entrypoint volume add copy workdir onbuild"},b:/^ *(onbuild +)?(run|cmd|entrypoint|volume|add|copy|workdir) +/,starts:{e:/[^\\]\n/,sL:"bash",subLanguageMode:"continuous"}},{k:{built_in:"from maintainer expose env user onbuild"},b:/^ *(onbuild +)?(from|maintainer|expose|env|user|onbuild) +/,e:/[^\\]\n/,c:[n.ASM,n.QSM,n.NM,n.HCM]}]}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:"^\\[.+\\]:",rB:!0,c:[{cN:"link_reference",b:"\\[",e:"\\]:",eB:!0,eE:!0,starts:{cN:"link_url",e:"$"}}]}]}});hljs.registerLanguage("haml",function(s){return{cI:!0,c:[{cN:"doctype",b:"^!!!( (5|1\\.1|Strict|Frameset|Basic|Mobile|RDFa|XML\\b.*))?$",r:10},s.C("^\\s*(!=#|=#|-#|/).*$",!1,{r:0}),{b:"^\\s*(-|=|!=)(?!#)",starts:{e:"\\n",sL:"ruby"}},{cN:"tag",b:"^\\s*%",c:[{cN:"title",b:"\\w+"},{cN:"value",b:"[#\\.]\\w+"},{b:"{\\s*",e:"\\s*}",eE:!0,c:[{b:":\\w+\\s*=>",e:",\\s+",rB:!0,eW:!0,c:[{cN:"symbol",b:":\\w+"},{cN:"string",b:'"',e:'"'},{cN:"string",b:"'",e:"'"},{b:"\\w+",r:0}]}]},{b:"\\(\\s*",e:"\\s*\\)",eE:!0,c:[{b:"\\w+\\s*=",e:"\\s+",rB:!0,eW:!0,c:[{cN:"attribute",b:"\\w+",r:0},{cN:"string",b:'"',e:'"'},{cN:"string",b:"'",e:"'"},{b:"\\w+",r:0}]}]}]},{cN:"bullet",b:"^\\s*[=~]\\s*",r:0},{b:"#{",starts:{e:"}",sL:"ruby"}}]}});hljs.registerLanguage("fortran",function(e){var t={cN:"params",b:"\\(",e:"\\)"},n={constant:".False. .True.",type:"integer real character complex logical dimension allocatable|10 parameter external implicit|10 none double precision assign intent optional pointer target in out common equivalence data",keyword:"kind do while private call intrinsic where elsewhere type endtype endmodule endselect endinterface end enddo endif if forall endforall only contains default return stop then public subroutine|10 function program .and. .or. .not. .le. .eq. .ge. .gt. .lt. goto save else use module select case access blank direct exist file fmt form formatted iostat name named nextrec number opened rec recl sequential status unformatted unit continue format pause cycle exit c_null_char c_alert c_backspace c_form_feed flush wait decimal round iomsg synchronous nopass non_overridable pass protected volatile abstract extends import non_intrinsic value deferred generic final enumerator class associate bind enum c_int c_short c_long c_long_long c_signed_char c_size_t c_int8_t c_int16_t c_int32_t c_int64_t c_int_least8_t c_int_least16_t c_int_least32_t c_int_least64_t c_int_fast8_t c_int_fast16_t c_int_fast32_t c_int_fast64_t c_intmax_t C_intptr_t c_float c_double c_long_double c_float_complex c_double_complex c_long_double_complex c_bool c_char c_null_ptr c_null_funptr c_new_line c_carriage_return c_horizontal_tab c_vertical_tab iso_c_binding c_loc c_funloc c_associated c_f_pointer c_ptr c_funptr iso_fortran_env character_storage_size error_unit file_storage_size input_unit iostat_end iostat_eor numeric_storage_size output_unit c_f_procpointer ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode newunit contiguous pad position action delim readwrite eor advance nml interface procedure namelist include sequence elemental pure",built_in:"alog alog10 amax0 amax1 amin0 amin1 amod cabs ccos cexp clog csin csqrt dabs dacos dasin datan datan2 dcos dcosh ddim dexp dint dlog dlog10 dmax1 dmin1 dmod dnint dsign dsin dsinh dsqrt dtan dtanh float iabs idim idint idnint ifix isign max0 max1 min0 min1 sngl algama cdabs cdcos cdexp cdlog cdsin cdsqrt cqabs cqcos cqexp cqlog cqsin cqsqrt dcmplx dconjg derf derfc dfloat dgamma dimag dlgama iqint qabs qacos qasin qatan qatan2 qcmplx qconjg qcos qcosh qdim qerf qerfc qexp qgamma qimag qlgama qlog qlog10 qmax1 qmin1 qmod qnint qsign qsin qsinh qsqrt qtan qtanh abs acos aimag aint anint asin atan atan2 char cmplx conjg cos cosh exp ichar index int log log10 max min nint sign sin sinh sqrt tan tanh print write dim lge lgt lle llt mod nullify allocate deallocate adjustl adjustr all allocated any associated bit_size btest ceiling count cshift date_and_time digits dot_product eoshift epsilon exponent floor fraction huge iand ibclr ibits ibset ieor ior ishft ishftc lbound len_trim matmul maxexponent maxloc maxval merge minexponent minloc minval modulo mvbits nearest pack present product radix random_number random_seed range repeat reshape rrspacing scale scan selected_int_kind selected_real_kind set_exponent shape size spacing spread sum system_clock tiny transpose trim ubound unpack verify achar iachar transfer dble entry dprod cpu_time command_argument_count get_command get_command_argument get_environment_variable is_iostat_end ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode is_iostat_eor move_alloc new_line selected_char_kind same_type_as extends_type_ofacosh asinh atanh bessel_j0 bessel_j1 bessel_jn bessel_y0 bessel_y1 bessel_yn erf erfc erfc_scaled gamma log_gamma hypot norm2 atomic_define atomic_ref execute_command_line leadz trailz storage_size merge_bits bge bgt ble blt dshiftl dshiftr findloc iall iany iparity image_index lcobound ucobound maskl maskr num_images parity popcnt poppar shifta shiftl shiftr this_image"};return{cI:!0,aliases:["f90","f95"],k:n,c:[e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{cN:"string",r:0}),{cN:"function",bK:"subroutine function program",i:"[${=\\n]",c:[e.UTM,t]},e.C("!","$",{r:0}),{cN:"number",b:"(?=\\b|\\+|\\-|\\.)(?=\\.\\d|\\d)(?:\\d+)?(?:\\.?\\d*)(?:[de][+-]?\\d+)?\\b\\.?",r:0}]}});hljs.registerLanguage("smali",function(r){var t=["add","and","cmp","cmpg","cmpl","const","div","double","float","goto","if","int","long","move","mul","neg","new","nop","not","or","rem","return","shl","shr","sput","sub","throw","ushr","xor"],n=["aget","aput","array","check","execute","fill","filled","goto/16","goto/32","iget","instance","invoke","iput","monitor","packed","sget","sparse"],s=["transient","constructor","abstract","final","synthetic","public","private","protected","static","bridge","system"];return{aliases:["smali"],c:[{cN:"string",b:'"',e:'"',r:0},r.C("#","$",{r:0}),{cN:"keyword",b:"\\s*\\.end\\s[a-zA-Z0-9]*",r:1},{cN:"keyword",b:"^[ ]*\\.[a-zA-Z]*",r:0},{cN:"keyword",b:"\\s:[a-zA-Z_0-9]*",r:0},{cN:"keyword",b:"\\s("+s.join("|")+")",r:1},{cN:"keyword",b:"\\[",r:0},{cN:"instruction",b:"\\s("+t.join("|")+")\\s",r:1},{cN:"instruction",b:"\\s("+t.join("|")+")((\\-|/)[a-zA-Z0-9]+)+\\s",r:10},{cN:"instruction",b:"\\s("+n.join("|")+")((\\-|/)[a-zA-Z0-9]+)*\\s",r:10},{cN:"class",b:"L[^(;:\n]*;",r:0},{cN:"function",b:'( |->)[^(\n ;"]*\\(',r:0},{cN:"function",b:"\\)",r:0},{cN:"variable",b:"[vp][0-9]+",r:0}]}});hljs.registerLanguage("julia",function(r){var e={keyword:"in abstract baremodule begin bitstype break catch ccall const continue do else elseif end export finally for function global if immutable import importall let local macro module quote return try type typealias using while",literal:"true false ANY ARGS CPU_CORES C_NULL DL_LOAD_PATH DevNull ENDIAN_BOM ENV I|0 Inf Inf16 Inf32 InsertionSort JULIA_HOME LOAD_PATH MS_ASYNC MS_INVALIDATE MS_SYNC MergeSort NaN NaN16 NaN32 OS_NAME QuickSort RTLD_DEEPBIND RTLD_FIRST RTLD_GLOBAL RTLD_LAZY RTLD_LOCAL RTLD_NODELETE RTLD_NOLOAD RTLD_NOW RoundDown RoundFromZero RoundNearest RoundToZero RoundUp STDERR STDIN STDOUT VERSION WORD_SIZE catalan cglobal e eu eulergamma golden im nothing pi γ π φ",built_in:"ASCIIString AbstractArray AbstractRNG AbstractSparseArray Any ArgumentError Array Associative Base64Pipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError Box CFILE Cchar Cdouble Cfloat Char CharString Cint Clong Clonglong ClusterManager Cmd Coff_t Colon Complex Complex128 Complex32 Complex64 Condition Cptrdiff_t Cshort Csize_t Cssize_t Cuchar Cuint Culong Culonglong Cushort Cwchar_t DArray DataType DenseArray Diagonal Dict DimensionMismatch DirectIndexString Display DivideError DomainError EOFError EachLine Enumerate ErrorException Exception Expr Factorization FileMonitor FileOffset Filter Float16 Float32 Float64 FloatRange FloatingPoint Function GetfieldNode GotoNode Hermitian IO IOBuffer IOStream IPv4 IPv6 InexactError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException IntrinsicFunction KeyError LabelNode LambdaStaticData LineNumberNode LoadError LocalProcess MIME MathConst MemoryError MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode Nothing Number ObjectIdDict OrdinalRange OverflowError ParseError PollingFileWatcher ProcessExitedException ProcessGroup Ptr QuoteNode Range Range1 Ranges Rational RawFD Real Regex RegexMatch RemoteRef RepString RevString RopeString RoundingMode Set SharedArray Signed SparseMatrixCSC StackOverflowError Stat StatStruct StepRange String SubArray SubString SymTridiagonal Symbol SymbolNode Symmetric SystemError Task TextDisplay Timer TmStruct TopNode Triangular Tridiagonal Type TypeConstructor TypeError TypeName TypeVar UTF16String UTF32String UTF8String UdpSocket Uint Uint128 Uint16 Uint32 Uint64 Uint8 UndefRefError UndefVarError UniformScaling UnionType UnitRange Unsigned Vararg VersionNumber WString WeakKeyDict WeakRef Woodbury Zip"},t="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",o={l:t,k:e},n={cN:"type-annotation",b:/::/},a={cN:"subtype",b:/<:/},i={cN:"number",b:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,r:0},l={cN:"char",b:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},c={cN:"subst",b:/\$\(/,e:/\)/,k:e},u={cN:"variable",b:"\\$"+t},d={cN:"string",c:[r.BE,c,u],v:[{b:/\w*"/,e:/"\w*/},{b:/\w*"""/,e:/"""\w*/}]},g={cN:"string",c:[r.BE,c,u],b:"`",e:"`"},s={cN:"macrocall",b:"@"+t},S={cN:"comment",v:[{b:"#=",e:"=#",r:10},{b:"#",e:"$"}]};return o.c=[i,l,n,a,d,g,s,S,r.HCM],c.c=o.c,o});hljs.registerLanguage("delphi",function(e){var r="exports register file shl array record property for mod while set ally label uses raise not stored class safecall var interface or private static exit index inherited to else stdcall override shr asm far resourcestring finalization packed virtual out and protected library do xorwrite goto near function end div overload object unit begin string on inline repeat until destructor write message program with read initialization except default nil if case cdecl in downto threadvar of try pascal const external constructor type public then implementation finally published procedure",t=[e.CLCM,e.C(/\{/,/\}/,{r:0}),e.C(/\(\*/,/\*\)/,{r:10})],i={cN:"string",b:/'/,e:/'/,c:[{b:/''/}]},c={cN:"string",b:/(#\d+)+/},o={b:e.IR+"\\s*=\\s*class\\s*\\(",rB:!0,c:[e.TM]},n={cN:"function",bK:"function constructor destructor procedure",e:/[:;]/,k:"function constructor|10 destructor|10 procedure|10",c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:r,c:[i,c]}].concat(t)};return{cI:!0,k:r,i:/"|\$[G-Zg-z]|\/\*|<\/|\|/,c:[i,c,e.NM,o,n].concat(t)}});hljs.registerLanguage("brainfuck",function(r){var n={cN:"literal",b:"[\\+\\-]",r:0};return{aliases:["bf"],c:[r.C("[^\\[\\]\\.,\\+\\-<> \r\n]","[\\[\\]\\.,\\+\\-<> \r\n]",{rE:!0,r:0}),{cN:"title",b:"[\\[\\]]",r:0},{cN:"string",b:"[\\.,]",r:0},{b:/\+\+|\-\-/,rB:!0,c:[n]},n]}});hljs.registerLanguage("ini",function(e){return{cI:!0,i:/\S/,c:[e.C(";","$"),{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:!0,k:"on off true false yes no",c:[e.QSM,e.NM],r:0}]}]}});hljs.registerLanguage("json",function(e){var t={literal:"true false null"},i=[e.QSM,e.CNM],l={cN:"value",e:",",eW:!0,eE:!0,c:i,k:t},c={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:l}],i:"\\S"},n={b:"\\[",e:"\\]",c:[e.inherit(l,{cN:null})],i:"\\S"};return i.splice(i.length,0,c,n),{c:i,k:t,i:"\\S"}});hljs.registerLanguage("powershell",function(e){var t={b:"`[\\s\\S]",r:0},r={cN:"variable",v:[{b:/\$[\w\d][\w\d_:]*/}]},o={cN:"string",b:/"/,e:/"/,c:[t,r,{cN:"variable",b:/\$[A-z]/,e:/[^A-z]/}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["ps"],l:/-?[A-z\.\-]+/,cI:!0,k:{keyword:"if else foreach return function do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch",literal:"$null $true $false",built_in:"Add-Content Add-History Add-Member Add-PSSnapin Clear-Content Clear-Item Clear-Item Property Clear-Variable Compare-Object ConvertFrom-SecureString Convert-Path ConvertTo-Html ConvertTo-SecureString Copy-Item Copy-ItemProperty Export-Alias Export-Clixml Export-Console Export-Csv ForEach-Object Format-Custom Format-List Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-Content Get-Credential Get-Culture Get-Date Get-EventLog Get-ExecutionPolicy Get-Help Get-History Get-Host Get-Item Get-ItemProperty Get-Location Get-Member Get-PfxCertificate Get-Process Get-PSDrive Get-PSProvider Get-PSSnapin Get-Service Get-TraceSource Get-UICulture Get-Unique Get-Variable Get-WmiObject Group-Object Import-Alias Import-Clixml Import-Csv Invoke-Expression Invoke-History Invoke-Item Join-Path Measure-Command Measure-Object Move-Item Move-ItemProperty New-Alias New-Item New-ItemProperty New-Object New-PSDrive New-Service New-TimeSpan New-Variable Out-Default Out-File Out-Host Out-Null Out-Printer Out-String Pop-Location Push-Location Read-Host Remove-Item Remove-ItemProperty Remove-PSDrive Remove-PSSnapin Remove-Variable Rename-Item Rename-ItemProperty Resolve-Path Restart-Service Resume-Service Select-Object Select-String Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-Location Set-PSDebug Set-Service Set-TraceSource Set-Variable Sort-Object Split-Path Start-Service Start-Sleep Start-Transcript Stop-Process Stop-Service Stop-Transcript Suspend-Service Tee-Object Test-Path Trace-Command Update-FormatData Update-TypeData Where-Object Write-Debug Write-Error Write-Host Write-Output Write-Progress Write-Verbose Write-Warning",operator:"-ne -eq -lt -gt -ge -le -not -like -notlike -match -notmatch -contains -notcontains -in -notin -replace"},c:[e.HCM,e.NM,o,a,r]}});hljs.registerLanguage("gradle",function(e){return{cI:!0,k:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.NM,e.RM]}});hljs.registerLanguage("erb",function(e){return{sL:"xml",subLanguageMode:"continuous",c:[e.C("<%#","%>"),{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0}]}});hljs.registerLanguage("swift",function(e){var i={keyword:"class deinit enum extension func import init let protocol static struct subscript typealias var break case continue default do else fallthrough if in for return switch where while as dynamicType is new super self Self Type __COLUMN__ __FILE__ __FUNCTION__ __LINE__ associativity didSet get infix inout left mutating none nonmutating operator override postfix precedence prefix right set unowned unowned safe unsafe weak willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue assert bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal false filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced join lexicographicalCompare map max maxElement min minElement nil numericCast partition posix print println quickSort reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith strideof strideofValue swap swift toString transcode true underestimateCount unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafePointers withVaList"},t={cN:"type",b:"\\b[A-Z][\\w']*",r:0},n=e.C("/\\*","\\*/",{c:["self"]}),r={cN:"subst",b:/\\\(/,e:"\\)",k:i,c:[]},s={cN:"number",b:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",r:0},o=e.inherit(e.QSM,{c:[r,e.BE]});return r.c=[s],{k:i,c:[o,e.CLCM,n,t,s,{cN:"func",bK:"func",e:"{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/,i:/\(/}),{cN:"generics",b:/</,e:/>/,i:/>/},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:i,c:["self",s,o,e.CBCM,{b:":"}],i:/["']/}],i:/\[|%/},{cN:"class",bK:"struct protocol class extension enum",k:i,e:"\\{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/})]},{cN:"preprocessor",b:"(@assignment|@class_protocol|@exported|@final|@lazy|@noreturn|@NSCopying|@NSManaged|@objc|@optional|@required|@auto_closure|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix)"}]}});hljs.registerLanguage("lisp",function(b){var e="[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#!]*",c="\\|[^]*?\\|",r="(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s|D|E|F|L|S)(\\+|\\-)?\\d+)?",a={cN:"shebang",b:"^#!",e:"$"},i={cN:"literal",b:"\\b(t{1}|nil)\\b"},l={cN:"number",v:[{b:r,r:0},{b:"#(b|B)[0-1]+(/[0-1]+)?"},{b:"#(o|O)[0-7]+(/[0-7]+)?"},{b:"#(x|X)[0-9a-fA-F]+(/[0-9a-fA-F]+)?"},{b:"#(c|C)\\("+r+" +"+r,e:"\\)"}]},t=b.inherit(b.QSM,{i:null}),d=b.C(";","$",{r:0}),n={cN:"variable",b:"\\*",e:"\\*"},u={cN:"keyword",b:"[:&]"+e},N={b:e,r:0},o={b:c},s={b:"\\(",e:"\\)",c:["self",i,t,l,N]},v={cN:"quoted",c:[l,t,n,u,s,N],v:[{b:"['`]\\(",e:"\\)"},{b:"\\(quote ",e:"\\)",k:"quote"},{b:"'"+c}]},f={cN:"quoted",v:[{b:"'"+e},{b:"#'"+e+"(::"+e+")*"}]},g={cN:"list",b:"\\(\\s*",e:"\\)"},q={eW:!0,r:0};return g.c=[{cN:"keyword",v:[{b:e},{b:c}]},q],q.c=[v,f,g,i,l,t,d,n,u,o,N],{i:/\S/,c:[l,a,i,t,d,v,f,g,N]}});hljs.registerLanguage("rsl",function(e){return{k:{keyword:"float color point normal vector matrix while for if do return else break extern continue",built_in:"abs acos ambient area asin atan atmosphere attribute calculatenormal ceil cellnoise clamp comp concat cos degrees depth Deriv diffuse distance Du Dv environment exp faceforward filterstep floor format fresnel incident length lightsource log match max min mod noise normalize ntransform opposite option phong pnoise pow printf ptlined radians random reflect refract renderinfo round setcomp setxcomp setycomp setzcomp shadow sign sin smoothstep specular specularbrdf spline sqrt step tan texture textureinfo trace transform vtransform xcomp ycomp zcomp"},i:"</",c:[e.CLCM,e.CBCM,e.QSM,e.ASM,e.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"shader",bK:"surface displacement light volume imager",e:"\\("},{cN:"shading",bK:"illuminate illuminance gather",e:"\\("}]}});hljs.registerLanguage("scheme",function(e){var t="[^\\(\\)\\[\\]\\{\\}\",'`;#|\\\\\\s]+",r="(\\-|\\+)?\\d+([./]\\d+)?",i=r+"[+\\-]"+r+"i",a={built_in:"case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules ' * + , ,@ - ... / ; < <= = => > >= ` abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"},n={cN:"shebang",b:"^#!",e:"$"},c={cN:"literal",b:"(#t|#f|#\\\\"+t+"|#\\\\.)"},l={cN:"number",v:[{b:r,r:0},{b:i,r:0},{b:"#b[0-1]+(/[0-1]+)?"},{b:"#o[0-7]+(/[0-7]+)?"},{b:"#x[0-9a-f]+(/[0-9a-f]+)?"}]},s=e.QSM,o=[e.C(";","$",{r:0}),e.C("#\\|","\\|#")],u={b:t,r:0},p={cN:"variable",b:"'"+t},d={eW:!0,r:0},g={cN:"list",v:[{b:"\\(",e:"\\)"},{b:"\\[",e:"\\]"}],c:[{cN:"keyword",b:t,l:t,k:a},d]};return d.c=[c,l,s,u,p,g].concat(o),{i:/\S/,c:[n,l,s,p,g].concat(o)}});hljs.registerLanguage("stata",function(e){return{aliases:["do","ado"],cI:!0,k:"if else in foreach for forv forva forval forvalu forvalue forvalues by bys bysort xi quietly qui capture about ac ac_7 acprplot acprplot_7 adjust ado adopath adoupdate alpha ameans an ano anov anova anova_estat anova_terms anovadef aorder ap app appe appen append arch arch_dr arch_estat arch_p archlm areg areg_p args arima arima_dr arima_estat arima_p as asmprobit asmprobit_estat asmprobit_lf asmprobit_mfx__dlg asmprobit_p ass asse asser assert avplot avplot_7 avplots avplots_7 bcskew0 bgodfrey binreg bip0_lf biplot bipp_lf bipr_lf bipr_p biprobit bitest bitesti bitowt blogit bmemsize boot bootsamp bootstrap bootstrap_8 boxco_l boxco_p boxcox boxcox_6 boxcox_p bprobit br break brier bro brow brows browse brr brrstat bs bs_7 bsampl_w bsample bsample_7 bsqreg bstat bstat_7 bstat_8 bstrap bstrap_7 ca ca_estat ca_p cabiplot camat canon canon_8 canon_8_p canon_estat canon_p cap caprojection capt captu captur capture cat cc cchart cchart_7 cci cd censobs_table centile cf char chdir checkdlgfiles checkestimationsample checkhlpfiles checksum chelp ci cii cl class classutil clear cli clis clist clo clog clog_lf clog_p clogi clogi_sw clogit clogit_lf clogit_p clogitp clogl_sw cloglog clonevar clslistarray cluster cluster_measures cluster_stop cluster_tree cluster_tree_8 clustermat cmdlog cnr cnre cnreg cnreg_p cnreg_sw cnsreg codebook collaps4 collapse colormult_nb colormult_nw compare compress conf confi confir confirm conren cons const constr constra constrai constrain constraint continue contract copy copyright copysource cor corc corr corr2data corr_anti corr_kmo corr_smc corre correl correla correlat correlate corrgram cou coun count cox cox_p cox_sw coxbase coxhaz coxvar cprplot cprplot_7 crc cret cretu cretur creturn cross cs cscript cscript_log csi ct ct_is ctset ctst_5 ctst_st cttost cumsp cumsp_7 cumul cusum cusum_7 cutil d datasig datasign datasigna datasignat datasignatu datasignatur datasignature datetof db dbeta de dec deco decod decode deff des desc descr descri describ describe destring dfbeta dfgls dfuller di di_g dir dirstats dis discard disp disp_res disp_s displ displa display distinct do doe doed doedi doedit dotplot dotplot_7 dprobit drawnorm drop ds ds_util dstdize duplicates durbina dwstat dydx e ed edi edit egen eivreg emdef en enc enco encod encode eq erase ereg ereg_lf ereg_p ereg_sw ereghet ereghet_glf ereghet_glf_sh ereghet_gp ereghet_ilf ereghet_ilf_sh ereghet_ip eret eretu eretur ereturn err erro error est est_cfexist est_cfname est_clickable est_expand est_hold est_table est_unhold est_unholdok estat estat_default estat_summ estat_vce_only esti estimates etodow etof etomdy ex exi exit expand expandcl fac fact facto factor factor_estat factor_p factor_pca_rotated factor_rotate factormat fcast fcast_compute fcast_graph fdades fdadesc fdadescr fdadescri fdadescrib fdadescribe fdasav fdasave fdause fh_st file open file read file close file filefilter fillin find_hlp_file findfile findit findit_7 fit fl fli flis flist for5_0 form forma format fpredict frac_154 frac_adj frac_chk frac_cox frac_ddp frac_dis frac_dv frac_in frac_mun frac_pp frac_pq frac_pv frac_wgt frac_xo fracgen fracplot fracplot_7 fracpoly fracpred fron_ex fron_hn fron_p fron_tn fron_tn2 frontier ftodate ftoe ftomdy ftowdate g gamhet_glf gamhet_gp gamhet_ilf gamhet_ip gamma gamma_d2 gamma_p gamma_sw gammahet gdi_hexagon gdi_spokes ge gen gene gener genera generat generate genrank genstd genvmean gettoken gl gladder gladder_7 glim_l01 glim_l02 glim_l03 glim_l04 glim_l05 glim_l06 glim_l07 glim_l08 glim_l09 glim_l10 glim_l11 glim_l12 glim_lf glim_mu glim_nw1 glim_nw2 glim_nw3 glim_p glim_v1 glim_v2 glim_v3 glim_v4 glim_v5 glim_v6 glim_v7 glm glm_6 glm_p glm_sw glmpred glo glob globa global glogit glogit_8 glogit_p gmeans gnbre_lf gnbreg gnbreg_5 gnbreg_p gomp_lf gompe_sw gomper_p gompertz gompertzhet gomphet_glf gomphet_glf_sh gomphet_gp gomphet_ilf gomphet_ilf_sh gomphet_ip gphdot gphpen gphprint gprefs gprobi_p gprobit gprobit_8 gr gr7 gr_copy gr_current gr_db gr_describe gr_dir gr_draw gr_draw_replay gr_drop gr_edit gr_editviewopts gr_example gr_example2 gr_export gr_print gr_qscheme gr_query gr_read gr_rename gr_replay gr_save gr_set gr_setscheme gr_table gr_undo gr_use graph graph7 grebar greigen greigen_7 greigen_8 grmeanby grmeanby_7 gs_fileinfo gs_filetype gs_graphinfo gs_stat gsort gwood h hadimvo hareg hausman haver he heck_d2 heckma_p heckman heckp_lf heckpr_p heckprob hel help hereg hetpr_lf hetpr_p hetprob hettest hexdump hilite hist hist_7 histogram hlogit hlu hmeans hotel hotelling hprobit hreg hsearch icd9 icd9_ff icd9p iis impute imtest inbase include inf infi infil infile infix inp inpu input ins insheet insp inspe inspec inspect integ inten intreg intreg_7 intreg_p intrg2_ll intrg_ll intrg_ll2 ipolate iqreg ir irf irf_create irfm iri is_svy is_svysum isid istdize ivprob_1_lf ivprob_lf ivprobit ivprobit_p ivreg ivreg_footnote ivtob_1_lf ivtob_lf ivtobit ivtobit_p jackknife jacknife jknife jknife_6 jknife_8 jkstat joinby kalarma1 kap kap_3 kapmeier kappa kapwgt kdensity kdensity_7 keep ksm ksmirnov ktau kwallis l la lab labe label labelbook ladder levels levelsof leverage lfit lfit_p li lincom line linktest lis list lloghet_glf lloghet_glf_sh lloghet_gp lloghet_ilf lloghet_ilf_sh lloghet_ip llogi_sw llogis_p llogist llogistic llogistichet lnorm_lf lnorm_sw lnorma_p lnormal lnormalhet lnormhet_glf lnormhet_glf_sh lnormhet_gp lnormhet_ilf lnormhet_ilf_sh lnormhet_ip lnskew0 loadingplot loc loca local log logi logis_lf logistic logistic_p logit logit_estat logit_p loglogs logrank loneway lookfor lookup lowess lowess_7 lpredict lrecomp lroc lroc_7 lrtest ls lsens lsens_7 lsens_x lstat ltable ltable_7 ltriang lv lvr2plot lvr2plot_7 m ma mac macr macro makecns man manova manova_estat manova_p manovatest mantel mark markin markout marksample mat mat_capp mat_order mat_put_rr mat_rapp mata mata_clear mata_describe mata_drop mata_matdescribe mata_matsave mata_matuse mata_memory mata_mlib mata_mosave mata_rename mata_which matalabel matcproc matlist matname matr matri matrix matrix_input__dlg matstrik mcc mcci md0_ md1_ md1debug_ md2_ md2debug_ mds mds_estat mds_p mdsconfig mdslong mdsmat mdsshepard mdytoe mdytof me_derd mean means median memory memsize meqparse mer merg merge mfp mfx mhelp mhodds minbound mixed_ll mixed_ll_reparm mkassert mkdir mkmat mkspline ml ml_5 ml_adjs ml_bhhhs ml_c_d ml_check ml_clear ml_cnt ml_debug ml_defd ml_e0 ml_e0_bfgs ml_e0_cycle ml_e0_dfp ml_e0i ml_e1 ml_e1_bfgs ml_e1_bhhh ml_e1_cycle ml_e1_dfp ml_e2 ml_e2_cycle ml_ebfg0 ml_ebfr0 ml_ebfr1 ml_ebh0q ml_ebhh0 ml_ebhr0 ml_ebr0i ml_ecr0i ml_edfp0 ml_edfr0 ml_edfr1 ml_edr0i ml_eds ml_eer0i ml_egr0i ml_elf ml_elf_bfgs ml_elf_bhhh ml_elf_cycle ml_elf_dfp ml_elfi ml_elfs ml_enr0i ml_enrr0 ml_erdu0 ml_erdu0_bfgs ml_erdu0_bhhh ml_erdu0_bhhhq ml_erdu0_cycle ml_erdu0_dfp ml_erdu0_nrbfgs ml_exde ml_footnote ml_geqnr ml_grad0 ml_graph ml_hbhhh ml_hd0 ml_hold ml_init ml_inv ml_log ml_max ml_mlout ml_mlout_8 ml_model ml_nb0 ml_opt ml_p ml_plot ml_query ml_rdgrd ml_repor ml_s_e ml_score ml_searc ml_technique ml_unhold mleval mlf_ mlmatbysum mlmatsum mlog mlogi mlogit mlogit_footnote mlogit_p mlopts mlsum mlvecsum mnl0_ mor more mov move mprobit mprobit_lf mprobit_p mrdu0_ mrdu1_ mvdecode mvencode mvreg mvreg_estat n nbreg nbreg_al nbreg_lf nbreg_p nbreg_sw nestreg net newey newey_7 newey_p news nl nl_7 nl_9 nl_9_p nl_p nl_p_7 nlcom nlcom_p nlexp2 nlexp2_7 nlexp2a nlexp2a_7 nlexp3 nlexp3_7 nlgom3 nlgom3_7 nlgom4 nlgom4_7 nlinit nllog3 nllog3_7 nllog4 nllog4_7 nlog_rd nlogit nlogit_p nlogitgen nlogittree nlpred no nobreak noi nois noisi noisil noisily note notes notes_dlg nptrend numlabel numlist odbc old_ver olo olog ologi ologi_sw ologit ologit_p ologitp on one onew onewa oneway op_colnm op_comp op_diff op_inv op_str opr opro oprob oprob_sw oprobi oprobi_p oprobit oprobitp opts_exclusive order orthog orthpoly ou out outf outfi outfil outfile outs outsh outshe outshee outsheet ovtest pac pac_7 palette parse parse_dissim pause pca pca_8 pca_display pca_estat pca_p pca_rotate pcamat pchart pchart_7 pchi pchi_7 pcorr pctile pentium pergram pergram_7 permute permute_8 personal peto_st pkcollapse pkcross pkequiv pkexamine pkexamine_7 pkshape pksumm pksumm_7 pl plo plot plugin pnorm pnorm_7 poisgof poiss_lf poiss_sw poisso_p poisson poisson_estat post postclose postfile postutil pperron pr prais prais_e prais_e2 prais_p predict predictnl preserve print pro prob probi probit probit_estat probit_p proc_time procoverlay procrustes procrustes_estat procrustes_p profiler prog progr progra program prop proportion prtest prtesti pwcorr pwd q\\s qby qbys qchi qchi_7 qladder qladder_7 qnorm qnorm_7 qqplot qqplot_7 qreg qreg_c qreg_p qreg_sw qu quadchk quantile quantile_7 que quer query range ranksum ratio rchart rchart_7 rcof recast reclink recode reg reg3 reg3_p regdw regr regre regre_p2 regres regres_p regress regress_estat regriv_p remap ren rena renam rename renpfix repeat replace report reshape restore ret retu retur return rm rmdir robvar roccomp roccomp_7 roccomp_8 rocf_lf rocfit rocfit_8 rocgold rocplot rocplot_7 roctab roctab_7 rolling rologit rologit_p rot rota rotat rotate rotatemat rreg rreg_p ru run runtest rvfplot rvfplot_7 rvpplot rvpplot_7 sa safesum sample sampsi sav save savedresults saveold sc sca scal scala scalar scatter scm_mine sco scob_lf scob_p scobi_sw scobit scor score scoreplot scoreplot_help scree screeplot screeplot_help sdtest sdtesti se search separate seperate serrbar serrbar_7 serset set set_defaults sfrancia sh she shel shell shewhart shewhart_7 signestimationsample signrank signtest simul simul_7 simulate simulate_8 sktest sleep slogit slogit_d2 slogit_p smooth snapspan so sor sort spearman spikeplot spikeplot_7 spikeplt spline_x split sqreg sqreg_p sret sretu sretur sreturn ssc st st_ct st_hc st_hcd st_hcd_sh st_is st_issys st_note st_promo st_set st_show st_smpl st_subid stack statsby statsby_8 stbase stci stci_7 stcox stcox_estat stcox_fr stcox_fr_ll stcox_p stcox_sw stcoxkm stcoxkm_7 stcstat stcurv stcurve stcurve_7 stdes stem stepwise stereg stfill stgen stir stjoin stmc stmh stphplot stphplot_7 stphtest stphtest_7 stptime strate strate_7 streg streg_sw streset sts sts_7 stset stsplit stsum sttocc sttoct stvary stweib su suest suest_8 sum summ summa summar summari summariz summarize sunflower sureg survcurv survsum svar svar_p svmat svy svy_disp svy_dreg svy_est svy_est_7 svy_estat svy_get svy_gnbreg_p svy_head svy_header svy_heckman_p svy_heckprob_p svy_intreg_p svy_ivreg_p svy_logistic_p svy_logit_p svy_mlogit_p svy_nbreg_p svy_ologit_p svy_oprobit_p svy_poisson_p svy_probit_p svy_regress_p svy_sub svy_sub_7 svy_x svy_x_7 svy_x_p svydes svydes_8 svygen svygnbreg svyheckman svyheckprob svyintreg svyintreg_7 svyintrg svyivreg svylc svylog_p svylogit svymarkout svymarkout_8 svymean svymlog svymlogit svynbreg svyolog svyologit svyoprob svyoprobit svyopts svypois svypois_7 svypoisson svyprobit svyprobt svyprop svyprop_7 svyratio svyreg svyreg_p svyregress svyset svyset_7 svyset_8 svytab svytab_7 svytest svytotal sw sw_8 swcnreg swcox swereg swilk swlogis swlogit swologit swoprbt swpois swprobit swqreg swtobit swweib symmetry symmi symplot symplot_7 syntax sysdescribe sysdir sysuse szroeter ta tab tab1 tab2 tab_or tabd tabdi tabdis tabdisp tabi table tabodds tabodds_7 tabstat tabu tabul tabula tabulat tabulate te tempfile tempname tempvar tes test testnl testparm teststd tetrachoric time_it timer tis tob tobi tobit tobit_p tobit_sw token tokeni tokeniz tokenize tostring total translate translator transmap treat_ll treatr_p treatreg trim trnb_cons trnb_mean trpoiss_d2 trunc_ll truncr_p truncreg tsappend tset tsfill tsline tsline_ex tsreport tsrevar tsrline tsset tssmooth tsunab ttest ttesti tut_chk tut_wait tutorial tw tware_st two twoway twoway__fpfit_serset twoway__function_gen twoway__histogram_gen twoway__ipoint_serset twoway__ipoints_serset twoway__kdensity_gen twoway__lfit_serset twoway__normgen_gen twoway__pci_serset twoway__qfit_serset twoway__scatteri_serset twoway__sunflower_gen twoway_ksm_serset ty typ type typeof u unab unabbrev unabcmd update us use uselabel var var_mkcompanion var_p varbasic varfcast vargranger varirf varirf_add varirf_cgraph varirf_create varirf_ctable varirf_describe varirf_dir varirf_drop varirf_erase varirf_graph varirf_ograph varirf_rename varirf_set varirf_table varlist varlmar varnorm varsoc varstable varstable_w varstable_w2 varwle vce vec vec_fevd vec_mkphi vec_p vec_p_w vecirf_create veclmar veclmar_w vecnorm vecnorm_w vecrank vecstable verinst vers versi versio version view viewsource vif vwls wdatetof webdescribe webseek webuse weib1_lf weib2_lf weib_lf weib_lf0 weibhet_glf weibhet_glf_sh weibhet_glfa weibhet_glfa_sh weibhet_gp weibhet_ilf weibhet_ilf_sh weibhet_ilfa weibhet_ilfa_sh weibhet_ip weibu_sw weibul_p weibull weibull_c weibull_s weibullhet wh whelp whi which whil while wilc_st wilcoxon win wind windo window winexec wntestb wntestb_7 wntestq xchart xchart_7 xcorr xcorr_7 xi xi_6 xmlsav xmlsave xmluse xpose xsh xshe xshel xshell xt_iis xt_tis xtab_p xtabond xtbin_p xtclog xtcloglog xtcloglog_8 xtcloglog_d2 xtcloglog_pa_p xtcloglog_re_p xtcnt_p xtcorr xtdata xtdes xtfront_p xtfrontier xtgee xtgee_elink xtgee_estat xtgee_makeivar xtgee_p xtgee_plink xtgls xtgls_p xthaus xthausman xtht_p xthtaylor xtile xtint_p xtintreg xtintreg_8 xtintreg_d2 xtintreg_p xtivp_1 xtivp_2 xtivreg xtline xtline_ex xtlogit xtlogit_8 xtlogit_d2 xtlogit_fe_p xtlogit_pa_p xtlogit_re_p xtmixed xtmixed_estat xtmixed_p xtnb_fe xtnb_lf xtnbreg xtnbreg_pa_p xtnbreg_refe_p xtpcse xtpcse_p xtpois xtpoisson xtpoisson_d2 xtpoisson_pa_p xtpoisson_refe_p xtpred xtprobit xtprobit_8 xtprobit_d2 xtprobit_re_p xtps_fe xtps_lf xtps_ren xtps_ren_8 xtrar_p xtrc xtrc_p xtrchh xtrefe_p xtreg xtreg_be xtreg_fe xtreg_ml xtreg_pa_p xtreg_re xtregar xtrere_p xtset xtsf_ll xtsf_llti xtsum xttab xttest0 xttobit xttobit_8 xttobit_p xttrans yx yxview__barlike_draw yxview_area_draw yxview_bar_draw yxview_dot_draw yxview_dropline_draw yxview_function_draw yxview_iarrow_draw yxview_ilabels_draw yxview_normal_draw yxview_pcarrow_draw yxview_pcbarrow_draw yxview_pccapsym_draw yxview_pcscatter_draw yxview_pcspike_draw yxview_rarea_draw yxview_rbar_draw yxview_rbarm_draw yxview_rcap_draw yxview_rcapsym_draw yxview_rconnected_draw yxview_rline_draw yxview_rscatter_draw yxview_rspike_draw yxview_spike_draw yxview_sunflower_draw zap_s zinb zinb_llf zinb_plf zip zip_llf zip_p zip_plf zt_ct_5 zt_hc_5 zt_hcd_5 zt_is_5 zt_iss_5 zt_sho_5 zt_smp_5 ztbase_5 ztcox_5 ztdes_5 ztereg_5 ztfill_5 ztgen_5 ztir_5 ztjoin_5 ztnb ztnb_p ztp ztp_p zts_5 ztset_5 ztspli_5 ztsum_5 zttoct_5 ztvary_5 ztweib_5",c:[{cN:"label",v:[{b:"\\$\\{?[a-zA-Z0-9_]+\\}?"},{b:"`[a-zA-Z0-9_]+'"}]},{cN:"string",v:[{b:'`"[^\r\n]*?"\''},{b:'"[^\r\n"]*"'}]},{cN:"literal",v:[{b:"\\b(abs|acos|asin|atan|atan2|atanh|ceil|cloglog|comb|cos|digamma|exp|floor|invcloglog|invlogit|ln|lnfact|lnfactorial|lngamma|log|log10|max|min|mod|reldif|round|sign|sin|sqrt|sum|tan|tanh|trigamma|trunc|betaden|Binomial|binorm|binormal|chi2|chi2tail|dgammapda|dgammapdada|dgammapdadx|dgammapdx|dgammapdxdx|F|Fden|Ftail|gammaden|gammap|ibeta|invbinomial|invchi2|invchi2tail|invF|invFtail|invgammap|invibeta|invnchi2|invnFtail|invnibeta|invnorm|invnormal|invttail|nbetaden|nchi2|nFden|nFtail|nibeta|norm|normal|normalden|normd|npnchi2|tden|ttail|uniform|abbrev|char|index|indexnot|length|lower|ltrim|match|plural|proper|real|regexm|regexr|regexs|reverse|rtrim|string|strlen|strlower|strltrim|strmatch|strofreal|strpos|strproper|strreverse|strrtrim|strtrim|strupper|subinstr|subinword|substr|trim|upper|word|wordcount|_caller|autocode|byteorder|chop|clip|cond|e|epsdouble|epsfloat|group|inlist|inrange|irecode|matrix|maxbyte|maxdouble|maxfloat|maxint|maxlong|mi|minbyte|mindouble|minfloat|minint|minlong|missing|r|recode|replay|return|s|scalar|d|date|day|dow|doy|halfyear|mdy|month|quarter|week|year|d|daily|dofd|dofh|dofm|dofq|dofw|dofy|h|halfyearly|hofd|m|mofd|monthly|q|qofd|quarterly|tin|twithin|w|weekly|wofd|y|yearly|yh|ym|yofd|yq|yw|cholesky|colnumb|colsof|corr|det|diag|diag0cnt|el|get|hadamard|I|inv|invsym|issym|issymmetric|J|matmissing|matuniform|mreldif|nullmat|rownumb|rowsof|sweep|syminv|trace|vec|vecdiag)(?=\\(|$)"}]},e.C("^[ ]*\\*.*$",!1),e.CLCM,e.CBCM]}});hljs.registerLanguage("asciidoc",function(e){return{aliases:["adoc"],c:[e.C("^/{4,}\\n","\\n/{4,}$",{r:10}),e.C("^//","$",{r:0}),{cN:"title",b:"^\\.\\w.*$"},{b:"^[=\\*]{4,}\\n",e:"\\n^[=\\*]{4,}$",r:10},{cN:"header",b:"^(={1,5}) .+?( \\1)?$",r:10},{cN:"header",b:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$",r:10},{cN:"attribute",b:"^:.+?:",e:"\\s",eE:!0,r:10},{cN:"attribute",b:"^\\[.+?\\]$",r:0},{cN:"blockquote",b:"^_{4,}\\n",e:"\\n_{4,}$",r:10},{cN:"code",b:"^[\\-\\.]{4,}\\n",e:"\\n[\\-\\.]{4,}$",r:10},{b:"^\\+{4,}\\n",e:"\\n\\+{4,}$",c:[{b:"<",e:">",sL:"xml",r:0}],r:10},{cN:"bullet",b:"^(\\*+|\\-+|\\.+|[^\\n]+?::)\\s+"},{cN:"label",b:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",r:10},{cN:"strong",b:"\\B\\*(?![\\*\\s])",e:"(\\n{2}|\\*)",c:[{b:"\\\\*\\w",r:0}]},{cN:"emphasis",b:"\\B'(?!['\\s])",e:"(\\n{2}|')",c:[{b:"\\\\'\\w",r:0}],r:0},{cN:"emphasis",b:"_(?![_\\s])",e:"(\\n{2}|_)",r:0},{cN:"smartquote",v:[{b:"``.+?''"},{b:"`.+?'"}]},{cN:"code",b:"(`.+?`|\\+.+?\\+)",r:0},{cN:"code",b:"^[ \\t]",e:"$",r:0},{cN:"horizontal_rule",b:"^'{3,}[ \\t]*$",r:10},{b:"(link:)?(http|https|ftp|file|irc|image:?):\\S+\\[.*?\\]",rB:!0,c:[{b:"(link|image:?):",r:0},{cN:"link_url",b:"\\w",e:"[^\\[]+",r:0},{cN:"link_label",b:"\\[",e:"\\]",eB:!0,eE:!0,r:0}],r:10}]}});hljs.registerLanguage("php",function(e){var c={cN:"variable",b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},i={cN:"preprocessor",b:/<\?(php)?|\?>/},a={cN:"string",c:[e.BE,i],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},n={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.CLCM,e.HCM,e.C("/\\*","\\*/",{c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},i]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[e.BE]},i,c,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",c,e.CBCM,a,n]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},a,n]}});hljs.registerLanguage("java",function(e){var a=e.UIR+"(<"+e.UIR+">)?",t="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",c="(\\b(0b[01_]+)|\\b0[xX][a-fA-F0-9_]+|(\\b[\\d_]+(\\.[\\d_]*)?|\\.[\\d_]+)([eE][-+]?\\d+)?)[lLfF]?",r={cN:"number",b:c,r:0};return{aliases:["jsp"],k:t,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return",r:0},{cN:"function",b:"("+a+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},r,{cN:"annotation",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("glsl",function(e){return{k:{keyword:"atomic_uint attribute bool break bvec2 bvec3 bvec4 case centroid coherent const continue default discard dmat2 dmat2x2 dmat2x3 dmat2x4 dmat3 dmat3x2 dmat3x3 dmat3x4 dmat4 dmat4x2 dmat4x3 dmat4x4 do double dvec2 dvec3 dvec4 else flat float for highp if iimage1D iimage1DArray iimage2D iimage2DArray iimage2DMS iimage2DMSArray iimage2DRect iimage3D iimageBuffer iimageCube iimageCubeArray image1D image1DArray image2D image2DArray image2DMS image2DMSArray image2DRect image3D imageBuffer imageCube imageCubeArray in inout int invariant isampler1D isampler1DArray isampler2D isampler2DArray isampler2DMS isampler2DMSArray isampler2DRect isampler3D isamplerBuffer isamplerCube isamplerCubeArray ivec2 ivec3 ivec4 layout lowp mat2 mat2x2 mat2x3 mat2x4 mat3 mat3x2 mat3x3 mat3x4 mat4 mat4x2 mat4x3 mat4x4 mediump noperspective out patch precision readonly restrict return sample sampler1D sampler1DArray sampler1DArrayShadow sampler1DShadow sampler2D sampler2DArray sampler2DArrayShadow sampler2DMS sampler2DMSArray sampler2DRect sampler2DRectShadow sampler2DShadow sampler3D samplerBuffer samplerCube samplerCubeArray samplerCubeArrayShadow samplerCubeShadow smooth struct subroutine switch uimage1D uimage1DArray uimage2D uimage2DArray uimage2DMS uimage2DMSArray uimage2DRect uimage3D uimageBuffer uimageCube uimageCubeArray uint uniform usampler1D usampler1DArray usampler2D usampler2DArray usampler2DMS usampler2DMSArray usampler2DRect usampler3D usamplerBuffer usamplerCube usamplerCubeArray uvec2 uvec3 uvec4 varying vec2 vec3 vec4 void volatile while writeonly",built_in:"gl_BackColor gl_BackLightModelProduct gl_BackLightProduct gl_BackMaterial gl_BackSecondaryColor gl_ClipDistance gl_ClipPlane gl_ClipVertex gl_Color gl_DepthRange gl_EyePlaneQ gl_EyePlaneR gl_EyePlaneS gl_EyePlaneT gl_Fog gl_FogCoord gl_FogFragCoord gl_FragColor gl_FragCoord gl_FragData gl_FragDepth gl_FrontColor gl_FrontFacing gl_FrontLightModelProduct gl_FrontLightProduct gl_FrontMaterial gl_FrontSecondaryColor gl_InstanceID gl_InvocationID gl_Layer gl_LightModel gl_LightSource gl_MaxAtomicCounterBindings gl_MaxAtomicCounterBufferSize gl_MaxClipDistances gl_MaxClipPlanes gl_MaxCombinedAtomicCounterBuffers gl_MaxCombinedAtomicCounters gl_MaxCombinedImageUniforms gl_MaxCombinedImageUnitsAndFragmentOutputs gl_MaxCombinedTextureImageUnits gl_MaxDrawBuffers gl_MaxFragmentAtomicCounterBuffers gl_MaxFragmentAtomicCounters gl_MaxFragmentImageUniforms gl_MaxFragmentInputComponents gl_MaxFragmentUniformComponents gl_MaxFragmentUniformVectors gl_MaxGeometryAtomicCounterBuffers gl_MaxGeometryAtomicCounters gl_MaxGeometryImageUniforms gl_MaxGeometryInputComponents gl_MaxGeometryOutputComponents gl_MaxGeometryOutputVertices gl_MaxGeometryTextureImageUnits gl_MaxGeometryTotalOutputComponents gl_MaxGeometryUniformComponents gl_MaxGeometryVaryingComponents gl_MaxImageSamples gl_MaxImageUnits gl_MaxLights gl_MaxPatchVertices gl_MaxProgramTexelOffset gl_MaxTessControlAtomicCounterBuffers gl_MaxTessControlAtomicCounters gl_MaxTessControlImageUniforms gl_MaxTessControlInputComponents gl_MaxTessControlOutputComponents gl_MaxTessControlTextureImageUnits gl_MaxTessControlTotalOutputComponents gl_MaxTessControlUniformComponents gl_MaxTessEvaluationAtomicCounterBuffers gl_MaxTessEvaluationAtomicCounters gl_MaxTessEvaluationImageUniforms gl_MaxTessEvaluationInputComponents gl_MaxTessEvaluationOutputComponents gl_MaxTessEvaluationTextureImageUnits gl_MaxTessEvaluationUniformComponents gl_MaxTessGenLevel gl_MaxTessPatchComponents gl_MaxTextureCoords gl_MaxTextureImageUnits gl_MaxTextureUnits gl_MaxVaryingComponents gl_MaxVaryingFloats gl_MaxVaryingVectors gl_MaxVertexAtomicCounterBuffers gl_MaxVertexAtomicCounters gl_MaxVertexAttribs gl_MaxVertexImageUniforms gl_MaxVertexOutputComponents gl_MaxVertexTextureImageUnits gl_MaxVertexUniformComponents gl_MaxVertexUniformVectors gl_MaxViewports gl_MinProgramTexelOffsetgl_ModelViewMatrix gl_ModelViewMatrixInverse gl_ModelViewMatrixInverseTranspose gl_ModelViewMatrixTranspose gl_ModelViewProjectionMatrix gl_ModelViewProjectionMatrixInverse gl_ModelViewProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixTranspose gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_Normal gl_NormalMatrix gl_NormalScale gl_ObjectPlaneQ gl_ObjectPlaneR gl_ObjectPlaneS gl_ObjectPlaneT gl_PatchVerticesIn gl_PerVertex gl_Point gl_PointCoord gl_PointSize gl_Position gl_PrimitiveID gl_PrimitiveIDIn gl_ProjectionMatrix gl_ProjectionMatrixInverse gl_ProjectionMatrixInverseTranspose gl_ProjectionMatrixTranspose gl_SampleID gl_SampleMask gl_SampleMaskIn gl_SamplePosition gl_SecondaryColor gl_TessCoord gl_TessLevelInner gl_TessLevelOuter gl_TexCoord gl_TextureEnvColor gl_TextureMatrixInverseTranspose gl_TextureMatrixTranspose gl_Vertex gl_VertexID gl_ViewportIndex gl_in gl_out EmitStreamVertex EmitVertex EndPrimitive EndStreamPrimitive abs acos acosh all any asin asinh atan atanh atomicCounter atomicCounterDecrement atomicCounterIncrement barrier bitCount bitfieldExtract bitfieldInsert bitfieldReverse ceil clamp cos cosh cross dFdx dFdy degrees determinant distance dot equal exp exp2 faceforward findLSB findMSB floatBitsToInt floatBitsToUint floor fma fract frexp ftransform fwidth greaterThan greaterThanEqual imageAtomicAdd imageAtomicAnd imageAtomicCompSwap imageAtomicExchange imageAtomicMax imageAtomicMin imageAtomicOr imageAtomicXor imageLoad imageStore imulExtended intBitsToFloat interpolateAtCentroid interpolateAtOffset interpolateAtSample inverse inversesqrt isinf isnan ldexp length lessThan lessThanEqual log log2 matrixCompMult max memoryBarrier min mix mod modf noise1 noise2 noise3 noise4 normalize not notEqual outerProduct packDouble2x32 packHalf2x16 packSnorm2x16 packSnorm4x8 packUnorm2x16 packUnorm4x8 pow radians reflect refract round roundEven shadow1D shadow1DLod shadow1DProj shadow1DProjLod shadow2D shadow2DLod shadow2DProj shadow2DProjLod sign sin sinh smoothstep sqrt step tan tanh texelFetch texelFetchOffset texture texture1D texture1DLod texture1DProj texture1DProjLod texture2D texture2DLod texture2DProj texture2DProjLod texture3D texture3DLod texture3DProj texture3DProjLod textureCube textureCubeLod textureGather textureGatherOffset textureGatherOffsets textureGrad textureGradOffset textureLod textureLodOffset textureOffset textureProj textureProjGrad textureProjGradOffset textureProjLod textureProjLodOffset textureProjOffset textureQueryLod textureSize transpose trunc uaddCarry uintBitsToFloat umulExtended unpackDouble2x32 unpackHalf2x16 unpackSnorm2x16 unpackSnorm4x8 unpackUnorm2x16 unpackUnorm4x8 usubBorrow gl_TextureMatrix gl_TextureMatrixInverse",literal:"true false"},i:'"',c:[e.CLCM,e.CBCM,e.CNM,{cN:"preprocessor",b:"#",e:"$"}]}});hljs.registerLanguage("lua",function(e){var t="\\[=*\\[",a="\\]=*\\]",r={b:t,e:a,c:["self"]},n=[e.C("--(?!"+t+")","$"),e.C("--"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{keyword:"and break do else elseif end false for if in local nil not or repeat return then true until while",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},c:n.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:a,c:[r],r:5}])}});hljs.registerLanguage("protobuf",function(e){return{k:{keyword:"package import option optional required repeated group",built_in:"double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes",literal:"true false"},c:[e.QSM,e.NM,e.CLCM,{cN:"class",bK:"message enum service",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{cN:"function",bK:"rpc",e:/;/,eE:!0,k:"rpc returns"},{cN:"constant",b:/^\s*[A-Z_]+/,e:/\s*=/,eE:!0}]}});hljs.registerLanguage("gcode",function(e){var N="[A-Z_][A-Z0-9_.]*",i="\\%",c={literal:"",built_in:"",keyword:"IF DO WHILE ENDWHILE CALL ENDIF SUB ENDSUB GOTO REPEAT ENDREPEAT EQ LT GT NE GE LE OR XOR"},r={cN:"preprocessor",b:"([O])([0-9]+)"},l=[e.CLCM,e.CBCM,e.C(/\(/,/\)/),e.inherit(e.CNM,{b:"([-+]?([0-9]*\\.?[0-9]+\\.?))|"+e.CNR}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"keyword",b:"([G])([0-9]+\\.?[0-9]?)"},{cN:"title",b:"([M])([0-9]+\\.?[0-9]?)"},{cN:"title",b:"(VC|VS|#)",e:"(\\d+)"},{cN:"title",b:"(VZOFX|VZOFY|VZOFZ)"},{cN:"built_in",b:"(ATAN|ABS|ACOS|ASIN|SIN|COS|EXP|FIX|FUP|ROUND|LN|TAN)(\\[)",e:"([-+]?([0-9]*\\.?[0-9]+\\.?))(\\])"},{cN:"label",v:[{b:"N",e:"\\d+",i:"\\W"}]}];return{aliases:["nc"],cI:!0,l:N,k:c,c:[{cN:"preprocessor",b:i},r].concat(l)}});hljs.registerLanguage("vim",function(e){return{l:/[!#@\w]+/,k:{keyword:"N|0 P|0 X|0 a|0 ab abc abo al am an|0 ar arga argd arge argdo argg argl argu as au aug aun b|0 bN ba bad bd be bel bf bl bm bn bo bp br brea breaka breakd breakl bro bufdo buffers bun bw c|0 cN cNf ca cabc caddb cad caddf cal cat cb cc ccl cd ce cex cf cfir cgetb cgete cg changes chd che checkt cl cla clo cm cmapc cme cn cnew cnf cno cnorea cnoreme co col colo com comc comp con conf cope cp cpf cq cr cs cst cu cuna cunme cw d|0 delm deb debugg delc delf dif diffg diffo diffp diffpu diffs diffthis dig di dl dell dj dli do doautoa dp dr ds dsp e|0 ea ec echoe echoh echom echon el elsei em en endfo endf endt endw ene ex exe exi exu f|0 files filet fin fina fini fir fix fo foldc foldd folddoc foldo for fu g|0 go gr grepa gu gv ha h|0 helpf helpg helpt hi hid his i|0 ia iabc if ij il im imapc ime ino inorea inoreme int is isp iu iuna iunme j|0 ju k|0 keepa kee keepj lN lNf l|0 lad laddb laddf la lan lat lb lc lch lcl lcs le lefta let lex lf lfir lgetb lgete lg lgr lgrepa lh ll lla lli lmak lm lmapc lne lnew lnf ln loadk lo loc lockv lol lope lp lpf lr ls lt lu lua luad luaf lv lvimgrepa lw m|0 ma mak map mapc marks mat me menut mes mk mks mksp mkv mkvie mod mz mzf nbc nb nbs n|0 new nm nmapc nme nn nnoreme noa no noh norea noreme norm nu nun nunme ol o|0 om omapc ome on ono onoreme opt ou ounme ow p|0 profd prof pro promptr pc ped pe perld po popu pp pre prev ps pt ptN ptf ptj ptl ptn ptp ptr pts pu pw py3 python3 py3d py3f py pyd pyf q|0 quita qa r|0 rec red redi redr redraws reg res ret retu rew ri rightb rub rubyd rubyf rund ru rv s|0 sN san sa sal sav sb sbN sba sbf sbl sbm sbn sbp sbr scrip scripte scs se setf setg setl sf sfir sh sim sig sil sl sla sm smap smapc sme sn sni sno snor snoreme sor so spelld spe spelli spellr spellu spellw sp spr sre st sta startg startr star stopi stj sts sun sunm sunme sus sv sw sy synti sync t|0 tN tabN tabc tabdo tabe tabf tabfir tabl tabm tabnew tabn tabo tabp tabr tabs tab ta tags tc tcld tclf te tf th tj tl tm tn to tp tr try ts tu u|0 undoj undol una unh unl unlo unm unme uns up v|0 ve verb vert vim vimgrepa vi viu vie vm vmapc vme vne vn vnoreme vs vu vunme windo w|0 wN wa wh wi winc winp wn wp wq wqa ws wu wv x|0 xa xmapc xm xme xn xnoreme xu xunme y|0 z|0 ~ Next Print append abbreviate abclear aboveleft all amenu anoremenu args argadd argdelete argedit argglobal arglocal argument ascii autocmd augroup aunmenu buffer bNext ball badd bdelete behave belowright bfirst blast bmodified bnext botright bprevious brewind break breakadd breakdel breaklist browse bunload bwipeout change cNext cNfile cabbrev cabclear caddbuffer caddexpr caddfile call catch cbuffer cclose center cexpr cfile cfirst cgetbuffer cgetexpr cgetfile chdir checkpath checktime clist clast close cmap cmapclear cmenu cnext cnewer cnfile cnoremap cnoreabbrev cnoremenu copy colder colorscheme command comclear compiler continue confirm copen cprevious cpfile cquit crewind cscope cstag cunmap cunabbrev cunmenu cwindow delete delmarks debug debuggreedy delcommand delfunction diffupdate diffget diffoff diffpatch diffput diffsplit digraphs display deletel djump dlist doautocmd doautoall deletep drop dsearch dsplit edit earlier echo echoerr echohl echomsg else elseif emenu endif endfor endfunction endtry endwhile enew execute exit exusage file filetype find finally finish first fixdel fold foldclose folddoopen folddoclosed foldopen function global goto grep grepadd gui gvim hardcopy help helpfind helpgrep helptags highlight hide history insert iabbrev iabclear ijump ilist imap imapclear imenu inoremap inoreabbrev inoremenu intro isearch isplit iunmap iunabbrev iunmenu join jumps keepalt keepmarks keepjumps lNext lNfile list laddexpr laddbuffer laddfile last language later lbuffer lcd lchdir lclose lcscope left leftabove lexpr lfile lfirst lgetbuffer lgetexpr lgetfile lgrep lgrepadd lhelpgrep llast llist lmake lmap lmapclear lnext lnewer lnfile lnoremap loadkeymap loadview lockmarks lockvar lolder lopen lprevious lpfile lrewind ltag lunmap luado luafile lvimgrep lvimgrepadd lwindow move mark make mapclear match menu menutranslate messages mkexrc mksession mkspell mkvimrc mkview mode mzscheme mzfile nbclose nbkey nbsart next nmap nmapclear nmenu nnoremap nnoremenu noautocmd noremap nohlsearch noreabbrev noremenu normal number nunmap nunmenu oldfiles open omap omapclear omenu only onoremap onoremenu options ounmap ounmenu ownsyntax print profdel profile promptfind promptrepl pclose pedit perl perldo pop popup ppop preserve previous psearch ptag ptNext ptfirst ptjump ptlast ptnext ptprevious ptrewind ptselect put pwd py3do py3file python pydo pyfile quit quitall qall read recover redo redir redraw redrawstatus registers resize retab return rewind right rightbelow ruby rubydo rubyfile rundo runtime rviminfo substitute sNext sandbox sargument sall saveas sbuffer sbNext sball sbfirst sblast sbmodified sbnext sbprevious sbrewind scriptnames scriptencoding scscope set setfiletype setglobal setlocal sfind sfirst shell simalt sign silent sleep slast smagic smapclear smenu snext sniff snomagic snoremap snoremenu sort source spelldump spellgood spellinfo spellrepall spellundo spellwrong split sprevious srewind stop stag startgreplace startreplace startinsert stopinsert stjump stselect sunhide sunmap sunmenu suspend sview swapname syntax syntime syncbind tNext tabNext tabclose tabedit tabfind tabfirst tablast tabmove tabnext tabonly tabprevious tabrewind tag tcl tcldo tclfile tearoff tfirst throw tjump tlast tmenu tnext topleft tprevious trewind tselect tunmenu undo undojoin undolist unabbreviate unhide unlet unlockvar unmap unmenu unsilent update vglobal version verbose vertical vimgrep vimgrepadd visual viusage view vmap vmapclear vmenu vnew vnoremap vnoremenu vsplit vunmap vunmenu write wNext wall while winsize wincmd winpos wnext wprevious wqall wsverb wundo wviminfo xit xall xmapclear xmap xmenu xnoremap xnoremenu xunmap xunmenu yank",built_in:"abs acos add and append argc argidx argv asin atan atan2 browse browsedir bufexists buflisted bufloaded bufname bufnr bufwinnr byte2line byteidx call ceil changenr char2nr cindent clearmatches col complete complete_add complete_check confirm copy cos cosh count cscope_connection cursor deepcopy delete did_filetype diff_filler diff_hlID empty escape eval eventhandler executable exists exp expand extend feedkeys filereadable filewritable filter finddir findfile float2nr floor fmod fnameescape fnamemodify foldclosed foldclosedend foldlevel foldtext foldtextresult foreground function garbagecollect get getbufline getbufvar getchar getcharmod getcmdline getcmdpos getcmdtype getcwd getfontname getfperm getfsize getftime getftype getline getloclist getmatches getpid getpos getqflist getreg getregtype gettabvar gettabwinvar getwinposx getwinposy getwinvar glob globpath has has_key haslocaldir hasmapto histadd histdel histget histnr hlexists hlID hostname iconv indent index input inputdialog inputlist inputrestore inputsave inputsecret insert invert isdirectory islocked items join keys len libcall libcallnr line line2byte lispindent localtime log log10 luaeval map maparg mapcheck match matchadd matcharg matchdelete matchend matchlist matchstr max min mkdir mode mzeval nextnonblank nr2char or pathshorten pow prevnonblank printf pumvisible py3eval pyeval range readfile reltime reltimestr remote_expr remote_foreground remote_peek remote_read remote_send remove rename repeat resolve reverse round screenattr screenchar screencol screenrow search searchdecl searchpair searchpairpos searchpos server2client serverlist setbufvar setcmdpos setline setloclist setmatches setpos setqflist setreg settabvar settabwinvar setwinvar sha256 shellescape shiftwidth simplify sin sinh sort soundfold spellbadword spellsuggest split sqrt str2float str2nr strchars strdisplaywidth strftime stridx string strlen strpart strridx strtrans strwidth submatch substitute synconcealed synID synIDattr synIDtrans synstack system tabpagebuflist tabpagenr tabpagewinnr tagfiles taglist tan tanh tempname tolower toupper tr trunc type undofile undotree values virtcol visualmode wildmenumode winbufnr wincol winheight winline winnr winrestcmd winrestview winsaveview winwidth writefile xor"},i:/[{:]/,c:[e.NM,e.ASM,{cN:"string",b:/"((\\")|[^"\n])*("|\n)/},{cN:"variable",b:/[bwtglsav]:[\w\d_]*/},{cN:"function",bK:"function function!",e:"$",r:0,c:[e.TM,{cN:"params",b:"\\(",e:"\\)"}]}]}});hljs.registerLanguage("processing",function(e){return{k:{keyword:"BufferedReader PVector PFont PImage PGraphics HashMap boolean byte char color double float int long String Array FloatDict FloatList IntDict IntList JSONArray JSONObject Object StringDict StringList Table TableRow XML false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",constant:"P2D P3D HALF_PI PI QUARTER_PI TAU TWO_PI",variable:"displayHeight displayWidth mouseY mouseX mousePressed pmouseX pmouseY key keyCode pixels focused frameCount frameRate height width",title:"setup draw",built_in:"size createGraphics beginDraw createShape loadShape PShape arc ellipse line point quad rect triangle bezier bezierDetail bezierPoint bezierTangent curve curveDetail curvePoint curveTangent curveTightness shape shapeMode beginContour beginShape bezierVertex curveVertex endContour endShape quadraticVertex vertex ellipseMode noSmooth rectMode smooth strokeCap strokeJoin strokeWeight mouseClicked mouseDragged mouseMoved mousePressed mouseReleased mouseWheel keyPressed keyPressedkeyReleased keyTyped print println save saveFrame day hour millis minute month second year background clear colorMode fill noFill noStroke stroke alpha blue brightness color green hue lerpColor red saturation modelX modelY modelZ screenX screenY screenZ ambient emissive shininess specular add createImage beginCamera camera endCamera frustum ortho perspective printCamera printProjection cursor frameRate noCursor exit loop noLoop popStyle pushStyle redraw binary boolean byte char float hex int str unbinary unhex join match matchAll nf nfc nfp nfs split splitTokens trim append arrayCopy concat expand reverse shorten sort splice subset box sphere sphereDetail createInput createReader loadBytes loadJSONArray loadJSONObject loadStrings loadTable loadXML open parseXML saveTable selectFolder selectInput beginRaw beginRecord createOutput createWriter endRaw endRecord PrintWritersaveBytes saveJSONArray saveJSONObject saveStream saveStrings saveXML selectOutput popMatrix printMatrix pushMatrix resetMatrix rotate rotateX rotateY rotateZ scale shearX shearY translate ambientLight directionalLight lightFalloff lights lightSpecular noLights normal pointLight spotLight image imageMode loadImage noTint requestImage tint texture textureMode textureWrap blend copy filter get loadPixels set updatePixels blendMode loadShader PShaderresetShader shader createFont loadFont text textFont textAlign textLeading textMode textSize textWidth textAscent textDescent abs ceil constrain dist exp floor lerp log mag map max min norm pow round sq sqrt acos asin atan atan2 cos degrees radians sin tan noise noiseDetail noiseSeed random randomGaussian randomSeed"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM]}});hljs.registerLanguage("mizar",function(e){return{k:"environ vocabularies notations constructors definitions registrations theorems schemes requirements begin end definition registration cluster existence pred func defpred deffunc theorem proof let take assume then thus hence ex for st holds consider reconsider such that and in provided of as from be being by means equals implies iff redefine define now not or attr is mode suppose per cases set thesis contradiction scheme reserve struct correctness compatibility coherence symmetry assymetry reflexivity irreflexivity connectedness uniqueness commutativity idempotence involutiveness projectivity",c:[e.C("::","$")]}});hljs.registerLanguage("vbnet",function(e){return{aliases:["vb"],cI:!0,k:{keyword:"addhandler addressof alias and andalso aggregate ansi as assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into is isfalse isnot istrue join key let lib like loop me mid mod module mustinherit mustoverride mybase myclass namespace narrowing new next not notinheritable notoverridable of off on operator option optional or order orelse overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim rem removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly xor",built_in:"boolean byte cbool cbyte cchar cdate cdec cdbl char cint clng cobj csbyte cshort csng cstr ctype date decimal directcast double gettype getxmlnamespace iif integer long object sbyte short single string trycast typeof uinteger ulong ushort",literal:"true false nothing"},i:"//|{|}|endif|gosub|variant|wend",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C("'","$",{rB:!0,c:[{cN:"xmlDocTag",b:"'''|<!--|-->",c:[e.PWM]},{cN:"xmlDocTag",b:"</?",e:">",c:[e.PWM]}]}),e.CNM,{cN:"preprocessor",b:"#",e:"$",k:"if else elseif end region externalsource"}]}});hljs.registerLanguage("q",function(e){var s={keyword:"do while select delete by update from",constant:"0b 1b",built_in:"neg not null string reciprocal floor ceiling signum mod xbar xlog and or each scan over prior mmu lsq inv md5 ltime gtime count first var dev med cov cor all any rand sums prds mins maxs fills deltas ratios avgs differ prev next rank reverse iasc idesc asc desc msum mcount mavg mdev xrank mmin mmax xprev rotate distinct group where flip type key til get value attr cut set upsert raze union inter except cross sv vs sublist enlist read0 read1 hopen hclose hdel hsym hcount peach system ltrim rtrim trim lower upper ssr view tables views cols xcols keys xkey xcol xasc xdesc fkeys meta lj aj aj0 ij pj asof uj ww wj wj1 fby xgroup ungroup ej save load rsave rload show csv parse eval min max avg wavg wsum sin cos tan sum",typename:"`float `double int `timestamp `timespan `datetime `time `boolean `symbol `char `byte `short `long `real `month `date `minute `second `guid"};return{aliases:["k","kdb"],k:s,l:/\b(`?)[A-Za-z0-9_]+\b/,c:[e.CLCM,e.QSM,e.CNM]}});hljs.registerLanguage("livescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger case default function var with then unless until loop of by when and or is isnt not it that otherwise from to til fallthrough super case default function var void const let enum export import native __hasProp __extends __slice __bind __indexOf",literal:"true false null undefined yes no on off it that void",built_in:"npm require console print module global window document"},s="[A-Za-z$_](?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*",i=e.inherit(e.TM,{b:s}),n={cN:"subst",b:/#\{/,e:/}/,k:t},r={cN:"subst",b:/#[A-Za-z$_]/,e:/(?:\-[0-9A-Za-z$_]|[0-9A-Za-z$_])*/,k:t},c=[e.BNM,{cN:"number",b:"(\\b0[xX][a-fA-F0-9_]+)|(\\b\\d(\\d|_\\d)*(\\.(\\d(\\d|_\\d)*)?)?(_*[eE]([-+]\\d(_\\d|\\d)*)?)?[_a-z]*)",r:0,starts:{e:"(\\s*/)?",r:0}},{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,n,r]},{b:/"/,e:/"/,c:[e.BE,n,r]},{b:/\\/,e:/(\s|$)/,eE:!0}]},{cN:"pi",v:[{b:"//",e:"//[gim]*",c:[n,e.HCM]},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+s},{b:"``",e:"``",eB:!0,eE:!0,sL:"javascript"}];n.c=c;var a={cN:"params",b:"\\(",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(c)}]};return{aliases:["ls"],k:t,i:/\/\*/,c:c.concat([e.C("\\/\\*","\\*\\/"),e.HCM,{cN:"function",c:[i,a],rB:!0,v:[{b:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B\\->\\*?",e:"\\->\\*?"},{b:"("+s+"\\s*(?:=|:=)\\s*)?!?(\\(.*\\))?\\s*\\B[-~]{1,2}>\\*?",e:"[-~]{1,2}>\\*?"},{b:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B!?[-~]{1,2}>\\*?",e:"!?[-~]{1,2}>\\*?"}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{cN:"attribute",b:s+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("haxe",function(e){var r="([*]|[a-zA-Z_$][a-zA-Z0-9_$]*)";return{aliases:["hx"],k:{keyword:"break callback case cast catch class continue default do dynamic else enum extends extern for function here if implements import in inline interface never new override package private public return static super switch this throw trace try typedef untyped using var while",literal:"true false null"},c:[e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.TM]},{cN:"preprocessor",b:"#",e:"$",k:"if else elseif end error"},{cN:"function",bK:"function",e:"[{;]",eE:!0,i:"\\S",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",c:[e.ASM,e.QSM,e.CLCM,e.CBCM]},{cN:"type",b:":",e:r,r:10}]}]}});hljs.registerLanguage("monkey",function(e){var n={cN:"number",r:0,v:[{b:"[$][a-fA-F0-9]+"},e.NM]};return{cI:!0,k:{keyword:"public private property continue exit extern new try catch eachin not abstract final select case default const local global field end if then else elseif endif while wend repeat until forever for to step next return module inline throw",built_in:"DebugLog DebugStop Error Print ACos ACosr ASin ASinr ATan ATan2 ATan2r ATanr Abs Abs Ceil Clamp Clamp Cos Cosr Exp Floor Log Max Max Min Min Pow Sgn Sgn Sin Sinr Sqrt Tan Tanr Seed PI HALFPI TWOPI",literal:"true false null and or shl shr mod"},c:[e.C("#rem","#end"),e.C("'","$",{r:0}),{cN:"function",bK:"function method",e:"[(=:]|$",i:/\n/,c:[e.UTM]},{cN:"class",bK:"class interface",e:"$",c:[{bK:"extends implements"},e.UTM]},{cN:"variable",b:"\\b(self|super)\\b"},{cN:"preprocessor",bK:"import",e:"$"},{cN:"preprocessor",b:"\\s*#",e:"$",k:"if else elseif endif end then"},{cN:"pi",b:"^\\s*strict\\b"},{bK:"alias",e:"=",c:[e.UTM]},e.QSM,n]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,e.NM,s,a,t]}});hljs.registerLanguage("erlang",function(e){var r="[a-z'][a-zA-Z0-9_']*",c="("+r+":"+r+"|"+r+")",a={keyword:"after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun if let not of orelse|10 query receive rem try when xor",literal:"false true"},n=e.C("%","$"),i={cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},b={b:"fun\\s+"+r+"/\\d+"},d={b:c+"\\(",e:"\\)",rB:!0,r:0,c:[{cN:"function_name",b:c,r:0},{b:"\\(",e:"\\)",eW:!0,rE:!0,r:0}]},o={cN:"tuple",b:"{",e:"}",r:0},t={cN:"variable",b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0},l={cN:"variable",b:"[A-Z][a-zA-Z0-9_]*",r:0},f={b:"#"+e.UIR,r:0,rB:!0,c:[{cN:"record_name",b:"#"+e.UIR,r:0},{b:"{",e:"}",r:0}]},s={bK:"fun receive if try case",e:"end",k:a};s.c=[n,b,e.inherit(e.ASM,{cN:""}),s,d,e.QSM,i,o,t,l,f];var u=[n,b,s,d,e.QSM,i,o,t,l,f];d.c[1].c=u,o.c=u,f.c[1].c=u;var v={cN:"params",b:"\\(",e:"\\)",c:u};return{aliases:["erl"],k:a,i:"(</|\\*=|\\+=|-=|/\\*|\\*/|\\(\\*|\\*\\))",c:[{cN:"function",b:"^"+r+"\\s*\\(",e:"->",rB:!0,i:"\\(|#|//|/\\*|\\\\|:|;",c:[v,e.inherit(e.TM,{b:r})],starts:{e:";|\\.",k:a,c:u}},n,{cN:"pp",b:"^-",e:"\\.",r:0,eE:!0,rB:!0,l:"-"+e.IR,k:"-module -record -undef -export -ifdef -ifndef -author -copyright -doc -vsn -import -include -include_lib -compile -define -else -endif -file -behaviour -behavior -spec",c:[v]},i,e.QSM,f,t,l,o,{b:/\.$/}]}});hljs.registerLanguage("kotlin",function(e){var a="val var get set class trait object public open private protected final enum if else do while for when break continue throw try catch finally import package is as in return fun override default companion reified inline volatile transient native";return{k:{typename:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null",keyword:a},c:[e.CLCM,{cN:"javadoc",b:"/\\*\\*",e:"\\*//*",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CBCM,{cN:"type",b:/</,e:/>/,rB:!0,eE:!1,r:0},{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:a,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b:/</,e:/>/,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,k:a,r:0,i:/\([^\(,\s:]+,/,c:[{cN:"typename",b:/:\s*/,e:/\s*[=\)]/,eB:!0,rE:!0,r:0}]},e.CLCM,e.CBCM]},{cN:"class",bK:"class trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[e.UTM,{cN:"type",b:/</,e:/>/,eB:!0,eE:!0,r:0},{cN:"typename",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0}]},{cN:"variable",bK:"var val",e:/\s*[=:$]/,eE:!0},e.QSM,{cN:"shebang",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.CNM]}});hljs.registerLanguage("stylus",function(t){var e={cN:"variable",b:"\\$"+t.IR},o={cN:"hexcolor",b:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})",r:10},i=["charset","css","debug","extend","font-face","for","import","include","media","mixin","page","warn","while"],r=["after","before","first-letter","first-line","active","first-child","focus","hover","lang","link","visited"],n=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],a="[\\.\\s\\n\\[\\:,]",l=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-variant-ligatures","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"],d=["\\{","\\}","\\?","(\\bReturn\\b)","(\\bEnd\\b)","(\\bend\\b)",";","#\\s","\\*\\s","===\\s","\\|","%"];return{aliases:["styl"],cI:!1,i:"("+d.join("|")+")",k:"if else for in",c:[t.QSM,t.ASM,t.CLCM,t.CBCM,o,{b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"+a,rB:!0,c:[{cN:"class",b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"+a,rB:!0,c:[{cN:"id",b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\b("+n.join("|")+")"+a,rB:!0,c:[{cN:"tag",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"}]},{cN:"pseudo",b:"&?:?:\\b("+r.join("|")+")"+a},{cN:"at_rule",b:"@("+i.join("|")+")\\b"},e,t.CSSNM,t.NM,{cN:"function",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*\\(.*\\)",i:"[\\n]",rB:!0,c:[{cN:"title",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"},{cN:"params",b:/\(/,e:/\)/,c:[o,e,t.ASM,t.CSSNM,t.NM,t.QSM]}]},{cN:"attribute",b:"\\b("+l.reverse().join("|")+")\\b"}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",a={cN:"function",b:c+"\\(",rB:!0,eE:!0,e:"\\("},r={cN:"rule",b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{cN:"value",eW:!0,eE:!0,c:[a,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]};return{cI:!0,i:/[=\/|']/,c:[e.CBCM,r,{cN:"id",b:/\#[A-Za-z0-9_-]+/},{cN:"class",b:/\.[A-Za-z0-9_-]+/,r:0},{cN:"attr_selector",b:/\[/,e:/\]/,i:"$"},{cN:"pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"']+/},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[a,e.ASM,e.QSM,e.CSSNM]}]},{cN:"tag",b:c,r:0},{cN:"rules",b:"{",e:"}",i:/\S/,r:0,c:[e.CBCM,r]}]}});hljs.registerLanguage("puppet",function(e){var s="augeas computer cron exec file filebucket host interface k5login macauthorization mailalias maillist mcx mount nagios_command nagios_contact nagios_contactgroup nagios_host nagios_hostdependency nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service firewall nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo nagios_servicegroup nagios_timeperiod notify package resources router schedule scheduled_task selboolean selmodule service ssh_authorized_key sshkey stage tidy user vlan yumrepo zfs zone zpool",r="alias audit before loglevel noop require subscribe tag owner ensure group mode name|0 changes context force incl lens load_path onlyif provider returns root show_diff type_check en_address ip_address realname command environment hour monute month monthday special target weekday creates cwd ogoutput refresh refreshonly tries try_sleep umask backup checksum content ctime force ignore links mtime purge recurse recurselimit replace selinux_ignore_defaults selrange selrole seltype seluser source souirce_permissions sourceselect validate_cmd validate_replacement allowdupe attribute_membership auth_membership forcelocal gid ia_load_module members system host_aliases ip allowed_trunk_vlans description device_url duplex encapsulation etherchannel native_vlan speed principals allow_root auth_class auth_type authenticate_user k_of_n mechanisms rule session_owner shared options device fstype enable hasrestart directory present absent link atboot blockdevice device dump pass remounts poller_tag use message withpath adminfile allow_virtual allowcdrom category configfiles flavor install_options instance package_settings platform responsefile status uninstall_options vendor unless_system_user unless_uid binary control flags hasstatus manifest pattern restart running start stop allowdupe auths expiry gid groups home iterations key_membership keys managehome membership password password_max_age password_min_age profile_membership profiles project purge_ssh_keys role_membership roles salt shell uid baseurl cost descr enabled enablegroups exclude failovermethod gpgcheck gpgkey http_caching include includepkgs keepalive metadata_expire metalink mirrorlist priority protect proxy proxy_password proxy_username repo_gpgcheck s3_enabled skip_if_unavailable sslcacert sslclientcert sslclientkey sslverify mounted",a={keyword:"and case class default define else elsif false if in import enherits node or true undef unless main settings $string "+s,literal:r,built_in:"architecture augeasversion blockdevices boardmanufacturer boardproductname boardserialnumber cfkey dhcp_servers domain ec2_ ec2_userdata facterversion filesystems ldom fqdn gid hardwareisa hardwaremodel hostname id|0 interfaces ipaddress ipaddress_ ipaddress6 ipaddress6_ iphostnumber is_virtual kernel kernelmajversion kernelrelease kernelversion kernelrelease kernelversion lsbdistcodename lsbdistdescription lsbdistid lsbdistrelease lsbmajdistrelease lsbminordistrelease lsbrelease macaddress macaddress_ macosx_buildversion macosx_productname macosx_productversion macosx_productverson_major macosx_productversion_minor manufacturer memoryfree memorysize netmask metmask_ network_ operatingsystem operatingsystemmajrelease operatingsystemrelease osfamily partitions path physicalprocessorcount processor processorcount productname ps puppetversion rubysitedir rubyversion selinux selinux_config_mode selinux_config_policy selinux_current_mode selinux_current_mode selinux_enforced selinux_policyversion serialnumber sp_ sshdsakey sshecdsakey sshrsakey swapencrypted swapfree swapsize timezone type uniqueid uptime uptime_days uptime_hours uptime_seconds uuid virtual vlans xendomains zfs_version zonenae zones zpool_version"},i=e.C("#","$"),o={cN:"string",c:[e.BE],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]},n=[o,i,{cN:"keyword",bK:"class",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"(::)?[A-Za-z_]\\w*(::\\w+)*"}),i,o]},{cN:"keyword",b:"([a-zA-Z_(::)]+ *\\{)",c:[o,i],r:0},{cN:"keyword",b:"(\\}|\\{)",r:0},{cN:"function",b:"[a-zA-Z_]+\\s*=>"},{cN:"constant",b:"(::)?(\\b[A-Z][a-z_]*(::)?)+",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0}];return{aliases:["pp"],k:a,c:n}});hljs.registerLanguage("nimrod",function(t){return{aliases:["nim"],k:{keyword:"addr and as asm bind block break|0 case|0 cast const|0 continue|0 converter discard distinct|10 div do elif else|0 end|0 enum|0 except export finally for from generic if|0 import|0 in include|0 interface is isnot|10 iterator|10 let|0 macro method|10 mixin mod nil not notin|10 object|0 of or out proc|10 ptr raise ref|10 return shl shr static template|10 try|0 tuple type|0 using|0 var|0 when while|0 with without xor yield",literal:"shared guarded stdin stdout stderr result|10 true false"},c:[{cN:"decorator",b:/{\./,e:/\.}/,r:10},{cN:"string",b:/[a-zA-Z]\w*"/,e:/"/,c:[{b:/""/}]},{cN:"string",b:/([a-zA-Z]\w*)?"""/,e:/"""/},t.QSM,{cN:"type",b:/\b[A-Z]\w+\b/,r:0},{cN:"type",b:/\b(int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float|float32|float64|bool|char|string|cstring|pointer|expr|stmt|void|auto|any|range|array|openarray|varargs|seq|set|clong|culong|cchar|cschar|cshort|cint|csize|clonglong|cfloat|cdouble|clongdouble|cuchar|cushort|cuint|culonglong|cstringarray|semistatic)\b/},{cN:"number",b:/\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/,r:0},{cN:"number",b:/\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/,r:0},{cN:"number",b:/\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/,r:0},{cN:"number",b:/\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/,r:0},t.HCM]}});hljs.registerLanguage("smalltalk",function(a){var r="[a-z][a-zA-Z0-9_]*",s={cN:"char",b:"\\$.{1}"},c={cN:"symbol",b:"#"+a.UIR};return{aliases:["st"],k:"self super nil true false thisContext",c:[a.C('"','"'),a.ASM,{cN:"class",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},{cN:"method",b:r+":",r:0},a.CNM,c,s,{cN:"localvars",b:"\\|[ ]*"+r+"([ ]+"+r+")*[ ]*\\|",rB:!0,e:/\|/,i:/\S/,c:[{b:"(\\|[ ]*)?"+r}]},{cN:"array",b:"\\#\\(",e:"\\)",c:[a.ASM,s,a.CNM,c]}]}});hljs.registerLanguage("x86asm",function(s){return{cI:!0,l:"\\.?"+s.IR,k:{keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",literal:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l",pseudo:"db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times",preprocessor:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public ",built_in:"bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},c:[s.C(";","$",{r:0}),{cN:"number",b:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",r:0},{cN:"number",b:"\\$[0-9][0-9A-Fa-f]*",r:0},{cN:"number",b:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[HhXx]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{cN:"number",b:"\\b(?:0[HhXx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"},s.QSM,{cN:"string",b:"'",e:"[^\\\\]'",r:0},{cN:"string",b:"`",e:"[^\\\\]`",r:0},{cN:"string",b:"\\.[A-Za-z0-9]+",r:0},{cN:"label",b:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)",r:0},{cN:"label",b:"^\\s*%%[A-Za-z0-9_$#@~.?]*:",r:0},{cN:"argument",b:"%[0-9]+",r:0},{cN:"built_in",b:"%!S+",r:0}]}});hljs.registerLanguage("roboconf",function(e){var n="[a-zA-Z-_][^\n{\r\n]+\\{";return{aliases:["graph","instances"],cI:!0,k:"import",c:[{cN:"facet",b:"^facet "+n,e:"}",k:"facet installer exports children extends",c:[e.HCM]},{cN:"instance-of",b:"^instance of "+n,e:"}",k:"name count channels instance-data instance-state instance of",c:[{cN:"keyword",b:"[a-zA-Z-_]+( | )*:"},e.HCM]},{cN:"component",b:"^"+n,e:"}",l:"\\(?[a-zA-Z]+\\)?",k:"installer exports children extends imports facets alias (optional)",c:[{cN:"string",b:"\\.[a-zA-Z-_]+",e:"\\s|,|;",eE:!0},e.HCM]},e.HCM]}});hljs.registerLanguage("ruby",function(e){var c="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",b={cN:"yardoctag",b:"@[A-Za-z]+"},a={cN:"value",b:"#<",e:">"},n=[e.C("#","$",{c:[b]}),e.C("^\\=begin","^\\=end",{c:[b],r:10}),e.C("^__END__","\\n$")],s={cN:"subst",b:"#\\{",e:"}",k:r},t={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},i={cN:"params",b:"\\(",e:"\\)",k:r},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]}].concat(n)},{cN:"function",bK:"def",e:" |$|;",r:0,c:[e.inherit(e.TM,{b:c}),i].concat(n)},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[t,{b:c}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,{cN:"regexp",c:[e.BE,s],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(n),r:0}].concat(n);s.c=d,i.c=d;var o="[>?]>",l="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",N=[{b:/^\s*=>/,cN:"status",starts:{e:"$",c:d}},{cN:"prompt",b:"^("+o+"|"+l+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,c:n.concat(N).concat(d)}});hljs.registerLanguage("typescript",function(e){return{aliases:["ts"],k:{keyword:"in if for while finally var new function|0 do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private get set super interface extendsstatic constructor implements enum export import declare type protected",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:0},e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/</,e:/>;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/,r:0},{cN:"constructor",bK:"constructor",e:/\{/,eE:!0,r:10},{cN:"module",bK:"module",e:/\{/,eE:!0},{cN:"interface",bK:"interface",e:/\{/,eE:!0},{b:/\$[(.]/},{b:"\\."+e.IR,r:0}]}});hljs.registerLanguage("handlebars",function(e){var a="each in with if else unless bindattr action collection debugger log outlet template unbound view yield";return{aliases:["hbs","html.hbs","html.handlebars"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[{cN:"expression",b:"{{",e:"}}",c:[{cN:"begin-block",b:"#[a-zA-Z- .]+",k:a},{cN:"string",b:'"',e:'"'},{cN:"end-block",b:"\\/[a-zA-Z- .]+",k:a},{cN:"variable",b:"[a-zA-Z-.]+",k:a}]}]}});hljs.registerLanguage("mercury",function(e){var i={keyword:"module use_module import_module include_module end_module initialise mutable initialize finalize finalise interface implementation pred mode func type inst solver any_pred any_func is semidet det nondet multi erroneous failure cc_nondet cc_multi typeclass instance where pragma promise external trace atomic or_else require_complete_switch require_det require_semidet require_multi require_nondet require_cc_multi require_cc_nondet require_erroneous require_failure",pragma:"inline no_inline type_spec source_file fact_table obsolete memo loop_check minimal_model terminates does_not_terminate check_termination promise_equivalent_clauses",preprocessor:"foreign_proc foreign_decl foreign_code foreign_type foreign_import_module foreign_export_enum foreign_export foreign_enum may_call_mercury will_not_call_mercury thread_safe not_thread_safe maybe_thread_safe promise_pure promise_semipure tabled_for_io local untrailed trailed attach_to_io_state can_pass_as_mercury_type stable will_not_throw_exception may_modify_trail will_not_modify_trail may_duplicate may_not_duplicate affects_liveness does_not_affect_liveness doesnt_affect_liveness no_sharing unknown_sharing sharing",built_in:"some all not if then else true fail false try catch catch_any semidet_true semidet_false semidet_fail impure_true impure semipure"},r={cN:"label",b:"XXX",e:"$",eW:!0,r:0},t=e.inherit(e.CLCM,{b:"%"}),_=e.inherit(e.CBCM,{r:0});t.c.push(r),_.c.push(r);var n={cN:"number",b:"0'.\\|0[box][0-9a-fA-F]*"},a=e.inherit(e.ASM,{r:0}),o=e.inherit(e.QSM,{r:0}),l={cN:"constant",b:"\\\\[abfnrtv]\\|\\\\x[0-9a-fA-F]*\\\\\\|%[-+# *.0-9]*[dioxXucsfeEgGp]",r:0};o.c.push(l);var s={cN:"built_in",v:[{b:"<=>"},{b:"<=",r:0},{b:"=>",r:0},{b:"/\\\\"},{b:"\\\\/"}]},c={cN:"built_in",v:[{b:":-\\|-->"},{b:"=",r:0}]};return{aliases:["m","moo"],k:i,c:[s,c,t,_,n,e.NM,a,o,{b:/:-/}]}});hljs.registerLanguage("fix",function(u){return{c:[{b:/[^\u2401\u0001]+/,e:/[\u2401\u0001]/,eE:!0,rB:!0,rE:!1,c:[{b:/([^\u2401\u0001=]+)/,e:/=([^\u2401\u0001=]+)/,rE:!0,rB:!1,cN:"attribute"},{b:/=/,e:/([\u2401\u0001])/,eE:!0,eB:!0,cN:"string"}]}],cI:!0}});hljs.registerLanguage("clojure",function(e){var t={built_in:"def cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>&#'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={cN:"collection",b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"attribute",b:"[:]"+n},f={cN:"list",b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"keyword",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}});hljs.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},s={b:"->{",e:"}"},n={cN:"variable",v:[{b:/\$\d/},{b:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{b:/[\$%@][^\s\w{]/,r:0}]},i=e.C("^(__END__|__DATA__)","\\n$",{r:5}),o=[e.BE,r,n],a=[n,e.HCM,i,e.C("^\\=\\w","\\=cut",{eW:!0}),s,{cN:"string",c:o,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,i,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];return r.c=a,s.c=a,{aliases:["pl"],k:t,c:a}});hljs.registerLanguage("twig",function(e){var t={cN:"params",b:"\\(",e:"\\)"},a="attribute block constant cycle date dump include max min parent random range source template_from_string",r={cN:"function",bK:a,r:0,c:[t]},c={cN:"filter",b:/\|[A-Za-z_]+:?/,k:"abs batch capitalize convert_encoding date date_modify default escape first format join json_encode keys last length lower merge nl2br number_format raw replace reverse round slice sort split striptags title trim upper url_encode",c:[r]},n="autoescape block do embed extends filter flush for if import include macro sandbox set spaceless use verbatim";return n=n+" "+n.split(" ").map(function(e){return"end"+e}).join(" "),{aliases:["craftcms"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[e.C(/\{#/,/#}/),{cN:"template_tag",b:/\{%/,e:/%}/,k:n,c:[c,r]},{cN:"variable",b:/\{\{/,e:/}}/,c:[c,r]}]}});hljs.registerLanguage("livecodeserver",function(e){var r={cN:"variable",b:"\\b[gtps][A-Z]+[A-Za-z0-9_\\-]*\\b|\\$_[A-Z]+",r:0},t=[e.CBCM,e.HCM,e.C("--","$"),e.C("[^:]//","$")],a=e.inherit(e.TM,{v:[{b:"\\b_*rig[A-Z]+[A-Za-z0-9_\\-]*"},{b:"\\b_[a-z0-9\\-]+"}]}),o=e.inherit(e.TM,{b:"\\b([A-Za-z0-9_\\-]+)\\b"});return{cI:!1,k:{keyword:"$_COOKIE $_FILES $_GET $_GET_BINARY $_GET_RAW $_POST $_POST_BINARY $_POST_RAW $_SESSION $_SERVER codepoint codepoints segment segments codeunit codeunits sentence sentences trueWord trueWords paragraph after byte bytes english the until http forever descending using line real8 with seventh for stdout finally element word words fourth before black ninth sixth characters chars stderr uInt1 uInt1s uInt2 uInt2s stdin string lines relative rel any fifth items from middle mid at else of catch then third it file milliseconds seconds second secs sec int1 int1s int4 int4s internet int2 int2s normal text item last long detailed effective uInt4 uInt4s repeat end repeat URL in try into switch to words https token binfile each tenth as ticks tick system real4 by dateItems without char character ascending eighth whole dateTime numeric short first ftp integer abbreviated abbr abbrev private case while if",constant:"SIX TEN FORMFEED NINE ZERO NONE SPACE FOUR FALSE COLON CRLF PI COMMA ENDOFFILE EOF EIGHT FIVE QUOTE EMPTY ONE TRUE RETURN CR LINEFEED RIGHT BACKSLASH NULL SEVEN TAB THREE TWO six ten formfeed nine zero none space four false colon crlf pi comma endoffile eof eight five quote empty one true return cr linefeed right backslash null seven tab three two RIVERSION RISTATE FILE_READ_MODE FILE_WRITE_MODE FILE_WRITE_MODE DIR_WRITE_MODE FILE_READ_UMASK FILE_WRITE_UMASK DIR_READ_UMASK DIR_WRITE_UMASK",operator:"div mod wrap and or bitAnd bitNot bitOr bitXor among not in a an within contains ends with begins the keys of keys",built_in:"put abs acos aliasReference annuity arrayDecode arrayEncode asin atan atan2 average avg avgDev base64Decode base64Encode baseConvert binaryDecode binaryEncode byteOffset byteToNum cachedURL cachedURLs charToNum cipherNames codepointOffset codepointProperty codepointToNum codeunitOffset commandNames compound compress constantNames cos date dateFormat decompress directories diskSpace DNSServers exp exp1 exp2 exp10 extents files flushEvents folders format functionNames geometricMean global globals hasMemory harmonicMean hostAddress hostAddressToName hostName hostNameToAddress isNumber ISOToMac itemOffset keys len length libURLErrorData libUrlFormData libURLftpCommand libURLLastHTTPHeaders libURLLastRHHeaders libUrlMultipartFormAddPart libUrlMultipartFormData libURLVersion lineOffset ln ln1 localNames log log2 log10 longFilePath lower macToISO matchChunk matchText matrixMultiply max md5Digest median merge millisec millisecs millisecond milliseconds min monthNames nativeCharToNum normalizeText num number numToByte numToChar numToCodepoint numToNativeChar offset open openfiles openProcesses openProcessIDs openSockets paragraphOffset paramCount param params peerAddress pendingMessages platform popStdDev populationStandardDeviation populationVariance popVariance processID random randomBytes replaceText result revCreateXMLTree revCreateXMLTreeFromFile revCurrentRecord revCurrentRecordIsFirst revCurrentRecordIsLast revDatabaseColumnCount revDatabaseColumnIsNull revDatabaseColumnLengths revDatabaseColumnNames revDatabaseColumnNamed revDatabaseColumnNumbered revDatabaseColumnTypes revDatabaseConnectResult revDatabaseCursors revDatabaseID revDatabaseTableNames revDatabaseType revDataFromQuery revdb_closeCursor revdb_columnbynumber revdb_columncount revdb_columnisnull revdb_columnlengths revdb_columnnames revdb_columntypes revdb_commit revdb_connect revdb_connections revdb_connectionerr revdb_currentrecord revdb_cursorconnection revdb_cursorerr revdb_cursors revdb_dbtype revdb_disconnect revdb_execute revdb_iseof revdb_isbof revdb_movefirst revdb_movelast revdb_movenext revdb_moveprev revdb_query revdb_querylist revdb_recordcount revdb_rollback revdb_tablenames revGetDatabaseDriverPath revNumberOfRecords revOpenDatabase revOpenDatabases revQueryDatabase revQueryDatabaseBlob revQueryResult revQueryIsAtStart revQueryIsAtEnd revUnixFromMacPath revXMLAttribute revXMLAttributes revXMLAttributeValues revXMLChildContents revXMLChildNames revXMLCreateTreeFromFileWithNamespaces revXMLCreateTreeWithNamespaces revXMLDataFromXPathQuery revXMLEvaluateXPath revXMLFirstChild revXMLMatchingNode revXMLNextSibling revXMLNodeContents revXMLNumberOfChildren revXMLParent revXMLPreviousSibling revXMLRootNode revXMLRPC_CreateRequest revXMLRPC_Documents revXMLRPC_Error revXMLRPC_GetHost revXMLRPC_GetMethod revXMLRPC_GetParam revXMLText revXMLRPC_Execute revXMLRPC_GetParamCount revXMLRPC_GetParamNode revXMLRPC_GetParamType revXMLRPC_GetPath revXMLRPC_GetPort revXMLRPC_GetProtocol revXMLRPC_GetRequest revXMLRPC_GetResponse revXMLRPC_GetSocket revXMLTree revXMLTrees revXMLValidateDTD revZipDescribeItem revZipEnumerateItems revZipOpenArchives round sampVariance sec secs seconds sentenceOffset sha1Digest shell shortFilePath sin specialFolderPath sqrt standardDeviation statRound stdDev sum sysError systemVersion tan tempName textDecode textEncode tick ticks time to tokenOffset toLower toUpper transpose truewordOffset trunc uniDecode uniEncode upper URLDecode URLEncode URLStatus uuid value variableNames variance version waitDepth weekdayNames wordOffset xsltApplyStylesheet xsltApplyStylesheetFromFile xsltLoadStylesheet xsltLoadStylesheetFromFile add breakpoint cancel clear local variable file word line folder directory URL close socket process combine constant convert create new alias folder directory decrypt delete variable word line folder directory URL dispatch divide do encrypt filter get include intersect kill libURLDownloadToFile libURLFollowHttpRedirects libURLftpUpload libURLftpUploadFile libURLresetAll libUrlSetAuthCallback libURLSetCustomHTTPHeaders libUrlSetExpect100 libURLSetFTPListCommand libURLSetFTPMode libURLSetFTPStopTime libURLSetStatusCallback load multiply socket prepare process post seek rel relative read from process rename replace require resetAll resolve revAddXMLNode revAppendXML revCloseCursor revCloseDatabase revCommitDatabase revCopyFile revCopyFolder revCopyXMLNode revDeleteFolder revDeleteXMLNode revDeleteAllXMLTrees revDeleteXMLTree revExecuteSQL revGoURL revInsertXMLNode revMoveFolder revMoveToFirstRecord revMoveToLastRecord revMoveToNextRecord revMoveToPreviousRecord revMoveToRecord revMoveXMLNode revPutIntoXMLNode revRollBackDatabase revSetDatabaseDriverPath revSetXMLAttribute revXMLRPC_AddParam revXMLRPC_DeleteAllDocuments revXMLAddDTD revXMLRPC_Free revXMLRPC_FreeAll revXMLRPC_DeleteDocument revXMLRPC_DeleteParam revXMLRPC_SetHost revXMLRPC_SetMethod revXMLRPC_SetPort revXMLRPC_SetProtocol revXMLRPC_SetSocket revZipAddItemWithData revZipAddItemWithFile revZipAddUncompressedItemWithData revZipAddUncompressedItemWithFile revZipCancel revZipCloseArchive revZipDeleteItem revZipExtractItemToFile revZipExtractItemToVariable revZipSetProgressCallback revZipRenameItem revZipReplaceItemWithData revZipReplaceItemWithFile revZipOpenArchive send set sort split start stop subtract union unload wait write"},c:[r,{cN:"keyword",b:"\\bend\\sif\\b"},{cN:"function",bK:"function",e:"$",c:[r,o,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"function",bK:"end",e:"$",c:[o,a]},{cN:"command",bK:"command on",e:"$",c:[r,o,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"command",bK:"end",e:"$",c:[o,a]},{cN:"preprocessor",b:"<\\?rev|<\\?lc|<\\?livecode",r:10},{cN:"preprocessor",b:"<\\?"},{cN:"preprocessor",b:"\\?>"},e.ASM,e.QSM,e.BNM,e.CNM,a].concat(t),i:";$|^\\[|^="}});hljs.registerLanguage("step21",function(e){var r="[A-Z_][A-Z0-9_.]*",i="END-ISO-10303-21;",l={literal:"",built_in:"",keyword:"HEADER ENDSEC DATA"},s={cN:"preprocessor",b:"ISO-10303-21;",r:10},t=[e.CLCM,e.CBCM,e.C("/\\*\\*!","\\*/"),e.CNM,e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"'",e:"'"},{cN:"label",v:[{b:"#",e:"\\d+",i:"\\W"}]}];return{aliases:["p21","step","stp"],cI:!0,l:r,k:l,c:[{cN:"preprocessor",b:i,r:10},s].concat(t)}});hljs.registerLanguage("cpp",function(t){var i={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary intmax_t uintmax_t int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t int_least8_t uint_least8_t int_least16_t uint_least16_t int_least32_t uint_least32_t int_least64_t uint_least64_t int_fast8_t uint_fast8_t int_fast16_t uint_fast16_t int_fast32_t uint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong atomic_wchar_t atomic_char16_t atomic_char32_t atomic_intmax_t atomic_uintmax_t atomic_intptr_t atomic_uintptr_t atomic_size_t atomic_ptrdiff_t atomic_int_least8_t atomic_int_least16_t atomic_int_least32_t atomic_int_least64_t atomic_uint_least8_t atomic_uint_least16_t atomic_uint_least32_t atomic_uint_least64_t atomic_int_fast8_t atomic_int_fast16_t atomic_int_fast32_t atomic_int_fast64_t atomic_uint_fast8_t atomic_uint_fast16_t atomic_uint_fast32_t atomic_uint_fast64_t",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c","cc","h","c++","h++","hpp"],k:i,i:"</",c:[t.CLCM,t.CBCM,t.QSM,{cN:"string",b:"'\\\\?.",e:"'",i:"."},{cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},t.CNM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line pragma",c:[{b:/\\\n/,r:0},{b:'include\\s*[<"]',e:'[>"]',k:"include",i:"\\n"},t.CLCM]},{b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:i,c:["self"]},{b:t.IR+"::",k:i},{bK:"new throw return else",r:0},{cN:"function",b:"("+t.IR+"\\s+)+"+t.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:i,c:[{b:t.IR+"\\s*\\(",rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:i,r:0,c:[t.CBCM]},t.CLCM,t.CBCM]}]}});hljs.registerLanguage("vala",function(e){return{k:{keyword:"char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double bool struct enum string void weak unowned owned async signal static abstract interface override while do for foreach else switch case break default return try catch public private protected internal using new this get set const stdout stdin stderr var",built_in:"DBus GLib CCode Gee Object",literal:"false true null"},c:[{cN:"class",bK:"class interface delegate namespace",e:"{",eE:!0,i:"[^,:\\n\\s\\.]",c:[e.UTM]},e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""',r:5},e.ASM,e.QSM,e.CNM,{cN:"preprocessor",b:"^#",e:"$",r:2},{cN:"constant",b:" [A-Z_]+ ",r:0}]}});hljs.registerLanguage("http",function(t){return{aliases:["https"],i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:!0}}]}});hljs.registerLanguage("avrasm",function(r){return{cI:!0,l:"\\.?"+r.IR,k:{keyword:"adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub subi swap tst wdr",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf",preprocessor:".byte .cseg .db .def .device .dseg .dw .endmacro .equ .eseg .exit .include .list .listmac .macro .nolist .org .set"},c:[r.CBCM,r.C(";","$",{r:0}),r.CNM,r.BNM,{cN:"number",b:"\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)"},r.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},{cN:"label",b:"^[A-Za-z0-9_.$]+:"},{cN:"preprocessor",b:"#",e:"$"},{cN:"localvars",b:"@[0-9]+"}]}});hljs.registerLanguage("aspectj",function(e){var t="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else extends implements break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws privileged aspectOf adviceexecution proceed cflowbelow cflow initialization preinitialization staticinitialization withincode target within execution getWithinTypeName handler thisJoinPoint thisJoinPointStaticPart thisEnclosingJoinPointStaticPart declare parents warning error soft precedence thisAspectInstance",i="get set args call";return{k:t,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"aspect",bK:"aspect",e:/[{;=]/,eE:!0,i:/[:;"\[\]]/,c:[{bK:"extends implements pertypewithin perthis pertarget percflowbelow percflow issingleton"},e.UTM,{b:/\([^\)]*/,e:/[)]+/,k:t+" "+i,eE:!1}]},{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,r:0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"pointcut after before around throwing returning",e:/[)]/,eE:!1,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",rB:!0,c:[e.UTM]}]},{b:/[:]/,rB:!0,e:/[{;]/,r:0,eE:!1,k:t,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",k:t+" "+i},e.QSM]},{bK:"new throw",r:0},{cN:"function",b:/\w+ +\w+(\.)?\w+\s*\([^\)]*\)\s*((throws)[\w\s,]+)?[\{;]/,rB:!0,e:/[{;=]/,k:t,eE:!0,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,r:0,k:t,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},e.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("rib",function(e){return{k:"ArchiveRecord AreaLightSource Atmosphere Attribute AttributeBegin AttributeEnd Basis Begin Blobby Bound Clipping ClippingPlane Color ColorSamples ConcatTransform Cone CoordinateSystem CoordSysTransform CropWindow Curves Cylinder DepthOfField Detail DetailRange Disk Displacement Display End ErrorHandler Exposure Exterior Format FrameAspectRatio FrameBegin FrameEnd GeneralPolygon GeometricApproximation Geometry Hider Hyperboloid Identity Illuminate Imager Interior LightSource MakeCubeFaceEnvironment MakeLatLongEnvironment MakeShadow MakeTexture Matte MotionBegin MotionEnd NuPatch ObjectBegin ObjectEnd ObjectInstance Opacity Option Orientation Paraboloid Patch PatchMesh Perspective PixelFilter PixelSamples PixelVariance Points PointsGeneralPolygons PointsPolygons Polygon Procedural Projection Quantize ReadArchive RelativeDetail ReverseOrientation Rotate Scale ScreenWindow ShadingInterpolation ShadingRate Shutter Sides Skew SolidBegin SolidEnd Sphere SubdivisionMesh Surface TextureCoordinates Torus Transform TransformBegin TransformEnd TransformPoints Translate TrimCurve WorldBegin WorldEnd",i:"</",c:[e.HCM,e.CNM,e.ASM,e.QSM]}});hljs.registerLanguage("python",function(e){var r={cN:"prompt",b:/^(>>>|\.\.\.) /},b={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]},l={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},c={cN:"params",b:/\(/,e:/\)/,c:["self",r,l,b]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[r,l,b,e.HCM,{v:[{cN:"function",bK:"def",r:10},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n,]/,c:[e.UTM,c]},{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}});hljs.registerLanguage("axapta",function(e){return{k:"false int abstract private char boolean static null if for true while long throw finally protected final return void enum else break new catch byte super case short default double public try this switch continue reverse firstfast firstonly forupdate nofetch sum avg minof maxof count order group by asc desc index hint like dispaly edit client server ttsbegin ttscommit str real date container anytype common div mod",c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"class",bK:"class interface",e:"{",eE:!0,i:":",c:[{bK:"extends implements"},e.UTM]}]}});hljs.registerLanguage("nix",function(e){var t={keyword:"rec with let in inherit assert if else then",constant:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},i={cN:"subst",b:/\$\{/,e:/}/,k:t},r={cN:"variable",b:/[a-zA-Z0-9-_]+(\s*=)/},n={cN:"string",b:"''",e:"''",c:[i]},s={cN:"string",b:'"',e:'"',c:[i]},a=[e.NM,e.HCM,e.CBCM,n,s,r];return i.c=a,{aliases:["nixos"],k:t,c:a}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"chunk",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("parser3",function(r){var e=r.C("{","}",{c:["self"]});return{sL:"xml",r:0,c:[r.C("^#","$"),r.C("\\^rem{","}",{r:10,c:[e]}),{cN:"preprocessor",b:"^@(?:BASE|USE|CLASS|OPTIONS)$",r:10},{cN:"title",b:"@[\\w\\-]+\\[[\\w^;\\-]*\\](?:\\[[\\w^;\\-]*\\])?(?:.*)$"},{cN:"variable",b:"\\$\\{?[\\w\\-\\.\\:]+\\}?"},{cN:"keyword",b:"\\^[\\w\\-\\.\\:]+"},{cN:"number",b:"\\^#[0-9a-fA-F]+"},r.CNM]}});hljs.registerLanguage("django",function(e){var t={cN:"filter",b:/\|[A-Za-z]+:?/,k:"truncatewords removetags linebreaksbr yesno get_digit timesince random striptags filesizeformat escape linebreaks length_is ljust rjust cut urlize fix_ampersands title floatformat capfirst pprint divisibleby add make_list unordered_list urlencode timeuntil urlizetrunc wordcount stringformat linenumbers slice date dictsort dictsortreversed default_if_none pluralize lower join center default truncatewords_html upper length phone2numeric wordwrap time addslashes slugify first escapejs force_escape iriencode last safe safeseq truncatechars localize unlocalize localtime utc timezone",c:[{cN:"argument",b:/"/,e:/"/},{cN:"argument",b:/'/,e:/'/}]};return{aliases:["jinja"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[e.C(/\{%\s*comment\s*%}/,/\{%\s*endcomment\s*%}/),e.C(/\{#/,/#}/),{cN:"template_tag",b:/\{%/,e:/%}/,k:"comment endcomment load templatetag ifchanged endifchanged if endif firstof for endfor in ifnotequal endifnotequal widthratio extends include spaceless endspaceless regroup by as ifequal endifequal ssi now with cycle url filter endfilter debug block endblock else autoescape endautoescape csrf_token empty elif endwith static trans blocktrans endblocktrans get_static_prefix get_media_prefix plural get_current_language language get_available_languages get_current_language_bidi get_language_info get_language_info_list localize endlocalize localtime endlocaltime timezone endtimezone get_current_timezone verbatim",c:[t]},{cN:"variable",b:/\{\{/,e:/}}/,c:[t]}]}});hljs.registerLanguage("rust",function(e){var t=e.inherit(e.CBCM);return t.c.push("self"),{aliases:["rs"],k:{keyword:"alignof as be box break const continue crate do else enum extern false fn for if impl in let loop match mod mut offsetof once priv proc pub pure ref return self sizeof static struct super trait true type typeof unsafe unsized use virtual while yield int i8 i16 i32 i64 uint u8 u32 u64 float f32 f64 str char bool",built_in:"assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln!"},l:e.IR+"!?",i:"</",c:[e.CLCM,t,e.inherit(e.QSM,{i:null}),{cN:"string",b:/r(#*)".*?"\1(?!#)/},{cN:"string",b:/'\\?(x\w{2}|u\w{4}|U\w{8}|.)'/},{b:/'[a-zA-Z_][a-zA-Z0-9_]*/},{cN:"number",b:/\b(0[xbo][A-Fa-f0-9_]+|\d[\d_]*(\.[0-9_]+)?([eE][+-]?[0-9_]+)?)([uif](8|16|32|64|size))?/,r:0},{cN:"function",bK:"fn",e:"(\\(|<)",eE:!0,c:[e.UTM]},{cN:"preprocessor",b:"#\\!?\\[",e:"\\]"},{bK:"type",e:"(=|<)",c:[e.UTM],i:"\\S"},{bK:"trait enum",e:"({|<)",c:[e.UTM],i:"\\S"},{b:e.IR+"::"},{b:"->"}]}});hljs.registerLanguage("vhdl",function(e){var t="\\d(_|\\d)*",r="[eE][-+]?"+t,n=t+"(\\."+t+")?("+r+")?",o="\\w+",i=t+"#"+o+"(\\."+o+")?#("+r+")?",a="\\b("+i+"|"+n+")";return{cI:!0,k:{keyword:"abs access after alias all and architecture array assert attribute begin block body buffer bus case component configuration constant context cover disconnect downto default else elsif end entity exit fairness file for force function generate generic group guarded if impure in inertial inout is label library linkage literal loop map mod nand new next nor not null of on open or others out package port postponed procedure process property protected pure range record register reject release rem report restrict restrict_guarantee return rol ror select sequence severity shared signal sla sll sra srl strong subtype then to transport type unaffected units until use variable vmode vprop vunit wait when while with xnor xor",typename:"boolean bit character severity_level integer time delay_length natural positive string bit_vector file_open_kind file_open_status std_ulogic std_ulogic_vector std_logic std_logic_vector unsigned signed boolean_vector integer_vector real_vector time_vector"},i:"{",c:[e.CBCM,e.C("--","$"),e.QSM,{cN:"number",b:a,r:0},{cN:"literal",b:"'(U|X|0|1|Z|W|L|H|-)'",c:[e.BE]},{cN:"attribute",b:"'[A-Za-z](_?[A-Za-z0-9])*",c:[e.BE]}]}});hljs.registerLanguage("ocaml",function(e){return{aliases:["ml"],k:{keyword:"and as assert asr begin class constraint do done downto else end exception external for fun function functor if in include inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method mod module mutable new object of open! open or private rec sig struct then to try type val! val virtual when while with parser value",built_in:"array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit in_channel out_channel ref",literal:"true false"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)"},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"tag",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*"},e.inherit(e.ASM,{cN:"char",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}});hljs.registerLanguage("cmake",function(e){return{aliases:["cmake.in"],cI:!0,k:{keyword:"add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_minimum_required cmake_policy configure_file create_test_sourcelist define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories load_cache load_command macro mark_as_advanced message option output_required_files project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_link_libraries try_compile try_run unset variable_watch while build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file qt5_use_modules qt5_use_package qt5_wrap_cpp on off true false and or",operator:"equal less greater strless strgreater strequal matches"},c:[{cN:"envvar",b:"\\${",e:"}"},e.HCM,e.QSM,e.NM]}});hljs.registerLanguage("1c",function(c){var e="[a-zA-Zа-яА-Я][a-zA-Z0-9_а-яА-Я]*",r="возврат дата для если и или иначе иначеесли исключение конецесли конецпопытки конецпроцедуры конецфункции конеццикла константа не перейти перем перечисление по пока попытка прервать продолжить процедура строка тогда фс функция цикл число экспорт",t="ansitooem oemtoansi ввестивидсубконто ввестидату ввестизначение ввестиперечисление ввестипериод ввестиплансчетов ввестистроку ввестичисло вопрос восстановитьзначение врег выбранныйплансчетов вызватьисключение датагод датамесяц датачисло добавитьмесяц завершитьработусистемы заголовоксистемы записьжурналарегистрации запуститьприложение зафиксироватьтранзакцию значениевстроку значениевстрокувнутр значениевфайл значениеизстроки значениеизстрокивнутр значениеизфайла имякомпьютера имяпользователя каталогвременныхфайлов каталогиб каталогпользователя каталогпрограммы кодсимв командасистемы конгода конецпериодаби конецрассчитанногопериодаби конецстандартногоинтервала конквартала конмесяца коннедели лев лог лог10 макс максимальноеколичествосубконто мин монопольныйрежим названиеинтерфейса названиенабораправ назначитьвид назначитьсчет найти найтипомеченныенаудаление найтиссылки началопериодаби началостандартногоинтервала начатьтранзакцию начгода начквартала начмесяца начнедели номерднягода номерднянедели номернеделигода нрег обработкаожидания окр описаниеошибки основнойжурналрасчетов основнойплансчетов основнойязык открытьформу открытьформумодально отменитьтранзакцию очиститьокносообщений периодстр полноеимяпользователя получитьвремята получитьдатута получитьдокументта получитьзначенияотбора получитьпозициюта получитьпустоезначение получитьта прав праводоступа предупреждение префиксавтонумерации пустаястрока пустоезначение рабочаядаттьпустоезначение рабочаядата разделительстраниц разделительстрок разм разобратьпозициюдокумента рассчитатьрегистрына рассчитатьрегистрыпо сигнал симв символтабуляции создатьобъект сокрл сокрлп сокрп сообщить состояние сохранитьзначение сред статусвозврата стрдлина стрзаменить стрколичествострок стрполучитьстроку стрчисловхождений сформироватьпозициюдокумента счетпокоду текущаядата текущеевремя типзначения типзначениястр удалитьобъекты установитьтана установитьтапо фиксшаблон формат цел шаблон",i={cN:"dquote",b:'""'},n={cN:"string",b:'"',e:'"|$',c:[i]},a={cN:"string",b:"\\|",e:'"|$',c:[i]};return{cI:!0,l:e,k:{keyword:r,built_in:t},c:[c.CLCM,c.NM,n,a,{cN:"function",b:"(процедура|функция)",e:"$",l:e,k:"процедура функция",c:[c.inherit(c.TM,{b:e}),{cN:"tail",eW:!0,c:[{cN:"params",b:"\\(",e:"\\)",l:e,k:"знач",c:[n,a]},{cN:"export",b:"экспорт",eW:!0,l:e,k:"экспорт",c:[c.CLCM]}]},c.CLCM]},{cN:"preprocessor",b:"#",e:"$"},{cN:"date",b:"'\\d{2}\\.\\d{2}\\.(\\d{2}|\\d{4})'"}]}});hljs.registerLanguage("tcl",function(e){return{aliases:["tk"],k:"after append apply array auto_execok auto_import auto_load auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror binary break catch cd chan clock close concat continue dde dict encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent filename flush for foreach format gets glob global history http if incr info interp join lappend|10 lassign|10 lindex|10 linsert|10 list llength|10 load lrange|10 lrepeat|10 lreplace|10 lreverse|10 lsearch|10 lset|10 lsort|10 mathfunc mathop memory msgcat namespace open package parray pid pkg::create pkg_mkIndex platform platform::shell proc puts pwd read refchan regexp registry regsub|10 rename return safe scan seek set socket source split string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord tcl_wordBreakAfter tcl_wordBreakBefore tcltest tclvars tell time tm trace unknown unload unset update uplevel upvar variable vwait while",c:[e.C(";[ \\t]*#","$"),e.C("^[ \\t]*#","$"),{bK:"proc",e:"[\\{]",eE:!0,c:[{cN:"symbol",b:"[ \\t\\n\\r]+(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"[ \\t\\n\\r]",eW:!0,eE:!0}]},{cN:"variable",eE:!0,v:[{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*\\(([a-zA-Z0-9_])*\\)",e:"[^a-zA-Z0-9_\\}\\$]"},{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"(\\))?[^a-zA-Z0-9_\\}\\$]"}]},{cN:"string",c:[e.BE],v:[e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},{cN:"number",v:[e.BNM,e.CNM]}]}});hljs.registerLanguage("groovy",function(e){return{k:{typename:"byte short char int long boolean float double void",literal:"true false null",keyword:"def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},c:[e.CLCM,{cN:"javadoc",b:"/\\*\\*",e:"\\*//*",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CBCM,{cN:"string",b:'"""',e:'"""'},{cN:"string",b:"'''",e:"'''"},{cN:"string",b:"\\$/",e:"/\\$",r:10},e.ASM,{cN:"regexp",b:/~?\/[^\/\n]+\//,c:[e.BE]},e.QSM,{cN:"shebang",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.BNM,{cN:"class",bK:"class interface trait enum",e:"{",i:":",c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"annotation",b:"@[A-Za-z]+"},{cN:"string",b:/[^\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\?/,e:/\:/},{cN:"label",b:"^\\s*[A-Za-z0-9_$]+:",r:0}]}});hljs.registerLanguage("erlang-repl",function(r){return{k:{special_functions:"spawn spawn_link self",reserved:"after and andalso|10 band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse|10 query receive rem try when xor"},c:[{cN:"prompt",b:"^[0-9]+> ",r:10},r.C("%","$"),{cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},r.ASM,r.QSM,{cN:"constant",b:"\\?(::)?([A-Z]\\w*(::)?)+"},{cN:"arrow",b:"->"},{cN:"ok",b:"ok"},{cN:"exclamation_mark",b:"!"},{cN:"function_or_atom",b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{cN:"variable",b:"[A-Z][a-zA-Z0-9_']*",r:0}]}});hljs.registerLanguage("nginx",function(e){var r={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},b={eW:!0,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,r],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[r]},{cN:"regexp",c:[e.BE,r],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},r]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"title",b:e.UIR,starts:b}],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("mathematica",function(e){return{aliases:["mma"],l:"(\\$|\\b)"+e.IR+"\\b",k:"AbelianGroup Abort AbortKernels AbortProtect Above Abs Absolute AbsoluteCorrelation AbsoluteCorrelationFunction AbsoluteCurrentValue AbsoluteDashing AbsoluteFileName AbsoluteOptions AbsolutePointSize AbsoluteThickness AbsoluteTime AbsoluteTiming AccountingForm Accumulate Accuracy AccuracyGoal ActionDelay ActionMenu ActionMenuBox ActionMenuBoxOptions Active ActiveItem ActiveStyle AcyclicGraphQ AddOnHelpPath AddTo AdjacencyGraph AdjacencyList AdjacencyMatrix AdjustmentBox AdjustmentBoxOptions AdjustTimeSeriesForecast AffineTransform After AiryAi AiryAiPrime AiryAiZero AiryBi AiryBiPrime AiryBiZero AlgebraicIntegerQ AlgebraicNumber AlgebraicNumberDenominator AlgebraicNumberNorm AlgebraicNumberPolynomial AlgebraicNumberTrace AlgebraicRules AlgebraicRulesData Algebraics AlgebraicUnitQ Alignment AlignmentMarker AlignmentPoint All AllowedDimensions AllowGroupClose AllowInlineCells AllowKernelInitialization AllowReverseGroupClose AllowScriptLevelChange AlphaChannel AlternatingGroup AlternativeHypothesis Alternatives AmbientLight Analytic AnchoredSearch And AndersonDarlingTest AngerJ AngleBracket AngularGauge Animate AnimationCycleOffset AnimationCycleRepetitions AnimationDirection AnimationDisplayTime AnimationRate AnimationRepetitions AnimationRunning Animator AnimatorBox AnimatorBoxOptions AnimatorElements Annotation Annuity AnnuityDue Antialiasing Antisymmetric Apart ApartSquareFree Appearance AppearanceElements AppellF1 Append AppendTo Apply ArcCos ArcCosh ArcCot ArcCoth ArcCsc ArcCsch ArcSec ArcSech ArcSin ArcSinDistribution ArcSinh ArcTan ArcTanh Arg ArgMax ArgMin ArgumentCountQ ARIMAProcess ArithmeticGeometricMean ARMAProcess ARProcess Array ArrayComponents ArrayDepth ArrayFlatten ArrayPad ArrayPlot ArrayQ ArrayReshape ArrayRules Arrays Arrow Arrow3DBox ArrowBox Arrowheads AspectRatio AspectRatioFixed Assert Assuming Assumptions AstronomicalData Asynchronous AsynchronousTaskObject AsynchronousTasks AtomQ Attributes AugmentedSymmetricPolynomial AutoAction AutoDelete AutoEvaluateEvents AutoGeneratedPackage AutoIndent AutoIndentSpacings AutoItalicWords AutoloadPath AutoMatch Automatic AutomaticImageSize AutoMultiplicationSymbol AutoNumberFormatting AutoOpenNotebooks AutoOpenPalettes AutorunSequencing AutoScaling AutoScroll AutoSpacing AutoStyleOptions AutoStyleWords Axes AxesEdge AxesLabel AxesOrigin AxesStyle Axis BabyMonsterGroupB Back Background BackgroundTasksSettings Backslash Backsubstitution Backward Band BandpassFilter BandstopFilter BarabasiAlbertGraphDistribution BarChart BarChart3D BarLegend BarlowProschanImportance BarnesG BarOrigin BarSpacing BartlettHannWindow BartlettWindow BaseForm Baseline BaselinePosition BaseStyle BatesDistribution BattleLemarieWavelet Because BeckmannDistribution Beep Before Begin BeginDialogPacket BeginFrontEndInteractionPacket BeginPackage BellB BellY Below BenfordDistribution BeniniDistribution BenktanderGibratDistribution BenktanderWeibullDistribution BernoulliB BernoulliDistribution BernoulliGraphDistribution BernoulliProcess BernsteinBasis BesselFilterModel BesselI BesselJ BesselJZero BesselK BesselY BesselYZero Beta BetaBinomialDistribution BetaDistribution BetaNegativeBinomialDistribution BetaPrimeDistribution BetaRegularized BetweennessCentrality BezierCurve BezierCurve3DBox BezierCurve3DBoxOptions BezierCurveBox BezierCurveBoxOptions BezierFunction BilateralFilter Binarize BinaryFormat BinaryImageQ BinaryRead BinaryReadList BinaryWrite BinCounts BinLists Binomial BinomialDistribution BinomialProcess BinormalDistribution BiorthogonalSplineWavelet BipartiteGraphQ BirnbaumImportance BirnbaumSaundersDistribution BitAnd BitClear BitGet BitLength BitNot BitOr BitSet BitShiftLeft BitShiftRight BitXor Black BlackmanHarrisWindow BlackmanNuttallWindow BlackmanWindow Blank BlankForm BlankNullSequence BlankSequence Blend Block BlockRandom BlomqvistBeta BlomqvistBetaTest Blue Blur BodePlot BohmanWindow Bold Bookmarks Boole BooleanConsecutiveFunction BooleanConvert BooleanCountingFunction BooleanFunction BooleanGraph BooleanMaxterms BooleanMinimize BooleanMinterms Booleans BooleanTable BooleanVariables BorderDimensions BorelTannerDistribution Bottom BottomHatTransform BoundaryStyle Bounds Box BoxBaselineShift BoxData BoxDimensions Boxed Boxes BoxForm BoxFormFormatTypes BoxFrame BoxID BoxMargins BoxMatrix BoxRatios BoxRotation BoxRotationPoint BoxStyle BoxWhiskerChart Bra BracketingBar BraKet BrayCurtisDistance BreadthFirstScan Break Brown BrownForsytheTest BrownianBridgeProcess BrowserCategory BSplineBasis BSplineCurve BSplineCurve3DBox BSplineCurveBox BSplineCurveBoxOptions BSplineFunction BSplineSurface BSplineSurface3DBox BubbleChart BubbleChart3D BubbleScale BubbleSizes BulletGauge BusinessDayQ ButterflyGraph ButterworthFilterModel Button ButtonBar ButtonBox ButtonBoxOptions ButtonCell ButtonContents ButtonData ButtonEvaluator ButtonExpandable ButtonFrame ButtonFunction ButtonMargins ButtonMinHeight ButtonNote ButtonNotebook ButtonSource ButtonStyle ButtonStyleMenuListing Byte ByteCount ByteOrdering C CachedValue CacheGraphics CalendarData CalendarType CallPacket CanberraDistance Cancel CancelButton CandlestickChart Cap CapForm CapitalDifferentialD CardinalBSplineBasis CarmichaelLambda Cases Cashflow Casoratian Catalan CatalanNumber Catch CauchyDistribution CauchyWindow CayleyGraph CDF CDFDeploy CDFInformation CDFWavelet Ceiling Cell CellAutoOverwrite CellBaseline CellBoundingBox CellBracketOptions CellChangeTimes CellContents CellContext CellDingbat CellDynamicExpression CellEditDuplicate CellElementsBoundingBox CellElementSpacings CellEpilog CellEvaluationDuplicate CellEvaluationFunction CellEventActions CellFrame CellFrameColor CellFrameLabelMargins CellFrameLabels CellFrameMargins CellGroup CellGroupData CellGrouping CellGroupingRules CellHorizontalScrolling CellID CellLabel CellLabelAutoDelete CellLabelMargins CellLabelPositioning CellMargins CellObject CellOpen CellPrint CellProlog Cells CellSize CellStyle CellTags CellularAutomaton CensoredDistribution Censoring Center CenterDot CentralMoment CentralMomentGeneratingFunction CForm ChampernowneNumber ChanVeseBinarize Character CharacterEncoding CharacterEncodingsPath CharacteristicFunction CharacteristicPolynomial CharacterRange Characters ChartBaseStyle ChartElementData ChartElementDataFunction ChartElementFunction ChartElements ChartLabels ChartLayout ChartLegends ChartStyle Chebyshev1FilterModel Chebyshev2FilterModel ChebyshevDistance ChebyshevT ChebyshevU Check CheckAbort CheckAll Checkbox CheckboxBar CheckboxBox CheckboxBoxOptions ChemicalData ChessboardDistance ChiDistribution ChineseRemainder ChiSquareDistribution ChoiceButtons ChoiceDialog CholeskyDecomposition Chop Circle CircleBox CircleDot CircleMinus CirclePlus CircleTimes CirculantGraph CityData Clear ClearAll ClearAttributes ClearSystemCache ClebschGordan ClickPane Clip ClipboardNotebook ClipFill ClippingStyle ClipPlanes ClipRange Clock ClockGauge ClockwiseContourIntegral Close Closed CloseKernels ClosenessCentrality Closing ClosingAutoSave ClosingEvent ClusteringComponents CMYKColor Coarse Coefficient CoefficientArrays CoefficientDomain CoefficientList CoefficientRules CoifletWavelet Collect Colon ColonForm ColorCombine ColorConvert ColorData ColorDataFunction ColorFunction ColorFunctionScaling Colorize ColorNegate ColorOutput ColorProfileData ColorQuantize ColorReplace ColorRules ColorSelectorSettings ColorSeparate ColorSetter ColorSetterBox ColorSetterBoxOptions ColorSlider ColorSpace Column ColumnAlignments ColumnBackgrounds ColumnForm ColumnLines ColumnsEqual ColumnSpacings ColumnWidths CommonDefaultFormatTypes Commonest CommonestFilter CommonUnits CommunityBoundaryStyle CommunityGraphPlot CommunityLabels CommunityRegionStyle CompatibleUnitQ CompilationOptions CompilationTarget Compile Compiled CompiledFunction Complement CompleteGraph CompleteGraphQ CompleteKaryTree CompletionsListPacket Complex Complexes ComplexExpand ComplexInfinity ComplexityFunction ComponentMeasurements ComponentwiseContextMenu Compose ComposeList ComposeSeries Composition CompoundExpression CompoundPoissonDistribution CompoundPoissonProcess CompoundRenewalProcess Compress CompressedData Condition ConditionalExpression Conditioned Cone ConeBox ConfidenceLevel ConfidenceRange ConfidenceTransform ConfigurationPath Congruent Conjugate ConjugateTranspose Conjunction Connect ConnectedComponents ConnectedGraphQ ConnesWindow ConoverTest ConsoleMessage ConsoleMessagePacket ConsolePrint Constant ConstantArray Constants ConstrainedMax ConstrainedMin ContentPadding ContentsBoundingBox ContentSelectable ContentSize Context ContextMenu Contexts ContextToFilename ContextToFileName Continuation Continue ContinuedFraction ContinuedFractionK ContinuousAction ContinuousMarkovProcess ContinuousTimeModelQ ContinuousWaveletData ContinuousWaveletTransform ContourDetect ContourGraphics ContourIntegral ContourLabels ContourLines ContourPlot ContourPlot3D Contours ContourShading ContourSmoothing ContourStyle ContraharmonicMean Control ControlActive ControlAlignment ControllabilityGramian ControllabilityMatrix ControllableDecomposition ControllableModelQ ControllerDuration ControllerInformation ControllerInformationData ControllerLinking ControllerManipulate ControllerMethod ControllerPath ControllerState ControlPlacement ControlsRendering ControlType Convergents ConversionOptions ConversionRules ConvertToBitmapPacket ConvertToPostScript ConvertToPostScriptPacket Convolve ConwayGroupCo1 ConwayGroupCo2 ConwayGroupCo3 CoordinateChartData CoordinatesToolOptions CoordinateTransform CoordinateTransformData CoprimeQ Coproduct CopulaDistribution Copyable CopyDirectory CopyFile CopyTag CopyToClipboard CornerFilter CornerNeighbors Correlation CorrelationDistance CorrelationFunction CorrelationTest Cos Cosh CoshIntegral CosineDistance CosineWindow CosIntegral Cot Coth Count CounterAssignments CounterBox CounterBoxOptions CounterClockwiseContourIntegral CounterEvaluator CounterFunction CounterIncrements CounterStyle CounterStyleMenuListing CountRoots CountryData Covariance CovarianceEstimatorFunction CovarianceFunction CoxianDistribution CoxIngersollRossProcess CoxModel CoxModelFit CramerVonMisesTest CreateArchive CreateDialog CreateDirectory CreateDocument CreateIntermediateDirectories CreatePalette CreatePalettePacket CreateScheduledTask CreateTemporary CreateWindow CriticalityFailureImportance CriticalitySuccessImportance CriticalSection Cross CrossingDetect CrossMatrix Csc Csch CubeRoot Cubics Cuboid CuboidBox Cumulant CumulantGeneratingFunction Cup CupCap Curl CurlyDoubleQuote CurlyQuote CurrentImage CurrentlySpeakingPacket CurrentValue CurvatureFlowFilter CurveClosed Cyan CycleGraph CycleIndexPolynomial Cycles CyclicGroup Cyclotomic Cylinder CylinderBox CylindricalDecomposition D DagumDistribution DamerauLevenshteinDistance DampingFactor Darker Dashed Dashing DataCompression DataDistribution DataRange DataReversed Date DateDelimiters DateDifference DateFunction DateList DateListLogPlot DateListPlot DatePattern DatePlus DateRange DateString DateTicksFormat DaubechiesWavelet DavisDistribution DawsonF DayCount DayCountConvention DayMatchQ DayName DayPlus DayRange DayRound DeBruijnGraph Debug DebugTag Decimal DeclareKnownSymbols DeclarePackage Decompose Decrement DedekindEta Default DefaultAxesStyle DefaultBaseStyle DefaultBoxStyle DefaultButton DefaultColor DefaultControlPlacement DefaultDuplicateCellStyle DefaultDuration DefaultElement DefaultFaceGridsStyle DefaultFieldHintStyle DefaultFont DefaultFontProperties DefaultFormatType DefaultFormatTypeForStyle DefaultFrameStyle DefaultFrameTicksStyle DefaultGridLinesStyle DefaultInlineFormatType DefaultInputFormatType DefaultLabelStyle DefaultMenuStyle DefaultNaturalLanguage DefaultNewCellStyle DefaultNewInlineCellStyle DefaultNotebook DefaultOptions DefaultOutputFormatType DefaultStyle DefaultStyleDefinitions DefaultTextFormatType DefaultTextInlineFormatType DefaultTicksStyle DefaultTooltipStyle DefaultValues Defer DefineExternal DefineInputStreamMethod DefineOutputStreamMethod Definition Degree DegreeCentrality DegreeGraphDistribution DegreeLexicographic DegreeReverseLexicographic Deinitialization Del Deletable Delete DeleteBorderComponents DeleteCases DeleteContents DeleteDirectory DeleteDuplicates DeleteFile DeleteSmallComponents DeleteWithContents DeletionWarning Delimiter DelimiterFlashTime DelimiterMatching Delimiters Denominator DensityGraphics DensityHistogram DensityPlot DependentVariables Deploy Deployed Depth DepthFirstScan Derivative DerivativeFilter DescriptorStateSpace DesignMatrix Det DGaussianWavelet DiacriticalPositioning Diagonal DiagonalMatrix Dialog DialogIndent DialogInput DialogLevel DialogNotebook DialogProlog DialogReturn DialogSymbols Diamond DiamondMatrix DiceDissimilarity DictionaryLookup DifferenceDelta DifferenceOrder DifferenceRoot DifferenceRootReduce Differences DifferentialD DifferentialRoot DifferentialRootReduce DifferentiatorFilter DigitBlock DigitBlockMinimum DigitCharacter DigitCount DigitQ DihedralGroup Dilation Dimensions DiracComb DiracDelta DirectedEdge DirectedEdges DirectedGraph DirectedGraphQ DirectedInfinity Direction Directive Directory DirectoryName DirectoryQ DirectoryStack DirichletCharacter DirichletConvolve DirichletDistribution DirichletL DirichletTransform DirichletWindow DisableConsolePrintPacket DiscreteChirpZTransform DiscreteConvolve DiscreteDelta DiscreteHadamardTransform DiscreteIndicator DiscreteLQEstimatorGains DiscreteLQRegulatorGains DiscreteLyapunovSolve DiscreteMarkovProcess DiscretePlot DiscretePlot3D DiscreteRatio DiscreteRiccatiSolve DiscreteShift DiscreteTimeModelQ DiscreteUniformDistribution DiscreteVariables DiscreteWaveletData DiscreteWaveletPacketTransform DiscreteWaveletTransform Discriminant Disjunction Disk DiskBox DiskMatrix Dispatch DispersionEstimatorFunction Display DisplayAllSteps DisplayEndPacket DisplayFlushImagePacket DisplayForm DisplayFunction DisplayPacket DisplayRules DisplaySetSizePacket DisplayString DisplayTemporary DisplayWith DisplayWithRef DisplayWithVariable DistanceFunction DistanceTransform Distribute Distributed DistributedContexts DistributeDefinitions DistributionChart DistributionDomain DistributionFitTest DistributionParameterAssumptions DistributionParameterQ Dithering Div Divergence Divide DivideBy Dividers Divisible Divisors DivisorSigma DivisorSum DMSList DMSString Do DockedCells DocumentNotebook DominantColors DOSTextFormat Dot DotDashed DotEqual Dotted DoubleBracketingBar DoubleContourIntegral DoubleDownArrow DoubleLeftArrow DoubleLeftRightArrow DoubleLeftTee DoubleLongLeftArrow DoubleLongLeftRightArrow DoubleLongRightArrow DoubleRightArrow DoubleRightTee DoubleUpArrow DoubleUpDownArrow DoubleVerticalBar DoublyInfinite Down DownArrow DownArrowBar DownArrowUpArrow DownLeftRightVector DownLeftTeeVector DownLeftVector DownLeftVectorBar DownRightTeeVector DownRightVector DownRightVectorBar Downsample DownTee DownTeeArrow DownValues DragAndDrop DrawEdges DrawFrontFaces DrawHighlighted Drop DSolve Dt DualLinearProgramming DualSystemsModel DumpGet DumpSave DuplicateFreeQ Dynamic DynamicBox DynamicBoxOptions DynamicEvaluationTimeout DynamicLocation DynamicModule DynamicModuleBox DynamicModuleBoxOptions DynamicModuleParent DynamicModuleValues DynamicName DynamicNamespace DynamicReference DynamicSetting DynamicUpdating DynamicWrapper DynamicWrapperBox DynamicWrapperBoxOptions E EccentricityCentrality EdgeAdd EdgeBetweennessCentrality EdgeCapacity EdgeCapForm EdgeColor EdgeConnectivity EdgeCost EdgeCount EdgeCoverQ EdgeDashing EdgeDelete EdgeDetect EdgeForm EdgeIndex EdgeJoinForm EdgeLabeling EdgeLabels EdgeLabelStyle EdgeList EdgeOpacity EdgeQ EdgeRenderingFunction EdgeRules EdgeShapeFunction EdgeStyle EdgeThickness EdgeWeight Editable EditButtonSettings EditCellTagsSettings EditDistance EffectiveInterest Eigensystem Eigenvalues EigenvectorCentrality Eigenvectors Element ElementData Eliminate EliminationOrder EllipticE EllipticExp EllipticExpPrime EllipticF EllipticFilterModel EllipticK EllipticLog EllipticNomeQ EllipticPi EllipticReducedHalfPeriods EllipticTheta EllipticThetaPrime EmitSound EmphasizeSyntaxErrors EmpiricalDistribution Empty EmptyGraphQ EnableConsolePrintPacket Enabled Encode End EndAdd EndDialogPacket EndFrontEndInteractionPacket EndOfFile EndOfLine EndOfString EndPackage EngineeringForm Enter EnterExpressionPacket EnterTextPacket Entropy EntropyFilter Environment Epilog Equal EqualColumns EqualRows EqualTilde EquatedTo Equilibrium EquirippleFilterKernel Equivalent Erf Erfc Erfi ErlangB ErlangC ErlangDistribution Erosion ErrorBox ErrorBoxOptions ErrorNorm ErrorPacket ErrorsDialogSettings EstimatedDistribution EstimatedProcess EstimatorGains EstimatorRegulator EuclideanDistance EulerE EulerGamma EulerianGraphQ EulerPhi Evaluatable Evaluate Evaluated EvaluatePacket EvaluationCell EvaluationCompletionAction EvaluationElements EvaluationMode EvaluationMonitor EvaluationNotebook EvaluationObject EvaluationOrder Evaluator EvaluatorNames EvenQ EventData EventEvaluator EventHandler EventHandlerTag EventLabels ExactBlackmanWindow ExactNumberQ ExactRootIsolation ExampleData Except ExcludedForms ExcludePods Exclusions ExclusionsStyle Exists Exit ExitDialog Exp Expand ExpandAll ExpandDenominator ExpandFileName ExpandNumerator Expectation ExpectationE ExpectedValue ExpGammaDistribution ExpIntegralE ExpIntegralEi Exponent ExponentFunction ExponentialDistribution ExponentialFamily ExponentialGeneratingFunction ExponentialMovingAverage ExponentialPowerDistribution ExponentPosition ExponentStep Export ExportAutoReplacements ExportPacket ExportString Expression ExpressionCell ExpressionPacket ExpToTrig ExtendedGCD Extension ExtentElementFunction ExtentMarkers ExtentSize ExternalCall ExternalDataCharacterEncoding Extract ExtractArchive ExtremeValueDistribution FaceForm FaceGrids FaceGridsStyle Factor FactorComplete Factorial Factorial2 FactorialMoment FactorialMomentGeneratingFunction FactorialPower FactorInteger FactorList FactorSquareFree FactorSquareFreeList FactorTerms FactorTermsList Fail FailureDistribution False FARIMAProcess FEDisableConsolePrintPacket FeedbackSector FeedbackSectorStyle FeedbackType FEEnableConsolePrintPacket Fibonacci FieldHint FieldHintStyle FieldMasked FieldSize File FileBaseName FileByteCount FileDate FileExistsQ FileExtension FileFormat FileHash FileInformation FileName FileNameDepth FileNameDialogSettings FileNameDrop FileNameJoin FileNames FileNameSetter FileNameSplit FileNameTake FilePrint FileType FilledCurve FilledCurveBox Filling FillingStyle FillingTransform FilterRules FinancialBond FinancialData FinancialDerivative FinancialIndicator Find FindArgMax FindArgMin FindClique FindClusters FindCurvePath FindDistributionParameters FindDivisions FindEdgeCover FindEdgeCut FindEulerianCycle FindFaces FindFile FindFit FindGeneratingFunction FindGeoLocation FindGeometricTransform FindGraphCommunities FindGraphIsomorphism FindGraphPartition FindHamiltonianCycle FindIndependentEdgeSet FindIndependentVertexSet FindInstance FindIntegerNullVector FindKClan FindKClique FindKClub FindKPlex FindLibrary FindLinearRecurrence FindList FindMaximum FindMaximumFlow FindMaxValue FindMinimum FindMinimumCostFlow FindMinimumCut FindMinValue FindPermutation FindPostmanTour FindProcessParameters FindRoot FindSequenceFunction FindSettings FindShortestPath FindShortestTour FindThreshold FindVertexCover FindVertexCut Fine FinishDynamic FiniteAbelianGroupCount FiniteGroupCount FiniteGroupData First FirstPassageTimeDistribution FischerGroupFi22 FischerGroupFi23 FischerGroupFi24Prime FisherHypergeometricDistribution FisherRatioTest FisherZDistribution Fit FitAll FittedModel FixedPoint FixedPointList FlashSelection Flat Flatten FlattenAt FlatTopWindow FlipView Floor FlushPrintOutputPacket Fold FoldList Font FontColor FontFamily FontForm FontName FontOpacity FontPostScriptName FontProperties FontReencoding FontSize FontSlant FontSubstitutions FontTracking FontVariations FontWeight For ForAll Format FormatRules FormatType FormatTypeAutoConvert FormatValues FormBox FormBoxOptions FortranForm Forward ForwardBackward Fourier FourierCoefficient FourierCosCoefficient FourierCosSeries FourierCosTransform FourierDCT FourierDCTFilter FourierDCTMatrix FourierDST FourierDSTMatrix FourierMatrix FourierParameters FourierSequenceTransform FourierSeries FourierSinCoefficient FourierSinSeries FourierSinTransform FourierTransform FourierTrigSeries FractionalBrownianMotionProcess FractionalPart FractionBox FractionBoxOptions FractionLine Frame FrameBox FrameBoxOptions Framed FrameInset FrameLabel Frameless FrameMargins FrameStyle FrameTicks FrameTicksStyle FRatioDistribution FrechetDistribution FreeQ FrequencySamplingFilterKernel FresnelC FresnelS Friday FrobeniusNumber FrobeniusSolve FromCharacterCode FromCoefficientRules FromContinuedFraction FromDate FromDigits FromDMS Front FrontEndDynamicExpression FrontEndEventActions FrontEndExecute FrontEndObject FrontEndResource FrontEndResourceString FrontEndStackSize FrontEndToken FrontEndTokenExecute FrontEndValueCache FrontEndVersion FrontFaceColor FrontFaceOpacity Full FullAxes FullDefinition FullForm FullGraphics FullOptions FullSimplify Function FunctionExpand FunctionInterpolation FunctionSpace FussellVeselyImportance GaborFilter GaborMatrix GaborWavelet GainMargins GainPhaseMargins Gamma GammaDistribution GammaRegularized GapPenalty Gather GatherBy GaugeFaceElementFunction GaugeFaceStyle GaugeFrameElementFunction GaugeFrameSize GaugeFrameStyle GaugeLabels GaugeMarkers GaugeStyle GaussianFilter GaussianIntegers GaussianMatrix GaussianWindow GCD GegenbauerC General GeneralizedLinearModelFit GenerateConditions GeneratedCell GeneratedParameters GeneratingFunction Generic GenericCylindricalDecomposition GenomeData GenomeLookup GeodesicClosing GeodesicDilation GeodesicErosion GeodesicOpening GeoDestination GeodesyData GeoDirection GeoDistance GeoGridPosition GeometricBrownianMotionProcess GeometricDistribution GeometricMean GeometricMeanFilter GeometricTransformation GeometricTransformation3DBox GeometricTransformation3DBoxOptions GeometricTransformationBox GeometricTransformationBoxOptions GeoPosition GeoPositionENU GeoPositionXYZ GeoProjectionData GestureHandler GestureHandlerTag Get GetBoundingBoxSizePacket GetContext GetEnvironment GetFileName GetFrontEndOptionsDataPacket GetLinebreakInformationPacket GetMenusPacket GetPageBreakInformationPacket Glaisher GlobalClusteringCoefficient GlobalPreferences GlobalSession Glow GoldenRatio GompertzMakehamDistribution GoodmanKruskalGamma GoodmanKruskalGammaTest Goto Grad Gradient GradientFilter GradientOrientationFilter Graph GraphAssortativity GraphCenter GraphComplement GraphData GraphDensity GraphDiameter GraphDifference GraphDisjointUnion GraphDistance GraphDistanceMatrix GraphElementData GraphEmbedding GraphHighlight GraphHighlightStyle GraphHub Graphics Graphics3D Graphics3DBox Graphics3DBoxOptions GraphicsArray GraphicsBaseline GraphicsBox GraphicsBoxOptions GraphicsColor GraphicsColumn GraphicsComplex GraphicsComplex3DBox GraphicsComplex3DBoxOptions GraphicsComplexBox GraphicsComplexBoxOptions GraphicsContents GraphicsData GraphicsGrid GraphicsGridBox GraphicsGroup GraphicsGroup3DBox GraphicsGroup3DBoxOptions GraphicsGroupBox GraphicsGroupBoxOptions GraphicsGrouping GraphicsHighlightColor GraphicsRow GraphicsSpacing GraphicsStyle GraphIntersection GraphLayout GraphLinkEfficiency GraphPeriphery GraphPlot GraphPlot3D GraphPower GraphPropertyDistribution GraphQ GraphRadius GraphReciprocity GraphRoot GraphStyle GraphUnion Gray GrayLevel GreatCircleDistance Greater GreaterEqual GreaterEqualLess GreaterFullEqual GreaterGreater GreaterLess GreaterSlantEqual GreaterTilde Green Grid GridBaseline GridBox GridBoxAlignment GridBoxBackground GridBoxDividers GridBoxFrame GridBoxItemSize GridBoxItemStyle GridBoxOptions GridBoxSpacings GridCreationSettings GridDefaultElement GridElementStyleOptions GridFrame GridFrameMargins GridGraph GridLines GridLinesStyle GroebnerBasis GroupActionBase GroupCentralizer GroupElementFromWord GroupElementPosition GroupElementQ GroupElements GroupElementToWord GroupGenerators GroupMultiplicationTable GroupOrbits GroupOrder GroupPageBreakWithin GroupSetwiseStabilizer GroupStabilizer GroupStabilizerChain Gudermannian GumbelDistribution HaarWavelet HadamardMatrix HalfNormalDistribution HamiltonianGraphQ HammingDistance HammingWindow HankelH1 HankelH2 HankelMatrix HannPoissonWindow HannWindow HaradaNortonGroupHN HararyGraph HarmonicMean HarmonicMeanFilter HarmonicNumber Hash HashTable Haversine HazardFunction Head HeadCompose Heads HeavisideLambda HeavisidePi HeavisideTheta HeldGroupHe HeldPart HelpBrowserLookup HelpBrowserNotebook HelpBrowserSettings HermiteDecomposition HermiteH HermitianMatrixQ HessenbergDecomposition Hessian HexadecimalCharacter Hexahedron HexahedronBox HexahedronBoxOptions HiddenSurface HighlightGraph HighlightImage HighpassFilter HigmanSimsGroupHS HilbertFilter HilbertMatrix Histogram Histogram3D HistogramDistribution HistogramList HistogramTransform HistogramTransformInterpolation HitMissTransform HITSCentrality HodgeDual HoeffdingD HoeffdingDTest Hold HoldAll HoldAllComplete HoldComplete HoldFirst HoldForm HoldPattern HoldRest HolidayCalendar HomeDirectory HomePage Horizontal HorizontalForm HorizontalGauge HorizontalScrollPosition HornerForm HotellingTSquareDistribution HoytDistribution HTMLSave Hue HumpDownHump HumpEqual HurwitzLerchPhi HurwitzZeta HyperbolicDistribution HypercubeGraph HyperexponentialDistribution Hyperfactorial Hypergeometric0F1 Hypergeometric0F1Regularized Hypergeometric1F1 Hypergeometric1F1Regularized Hypergeometric2F1 Hypergeometric2F1Regularized HypergeometricDistribution HypergeometricPFQ HypergeometricPFQRegularized HypergeometricU Hyperlink HyperlinkCreationSettings Hyphenation HyphenationOptions HypoexponentialDistribution HypothesisTestData I Identity IdentityMatrix If IgnoreCase Im Image Image3D Image3DSlices ImageAccumulate ImageAdd ImageAdjust ImageAlign ImageApply ImageAspectRatio ImageAssemble ImageCache ImageCacheValid ImageCapture ImageChannels ImageClip ImageColorSpace ImageCompose ImageConvolve ImageCooccurrence ImageCorners ImageCorrelate ImageCorrespondingPoints ImageCrop ImageData ImageDataPacket ImageDeconvolve ImageDemosaic ImageDifference ImageDimensions ImageDistance ImageEffect ImageFeatureTrack ImageFileApply ImageFileFilter ImageFileScan ImageFilter ImageForestingComponents ImageForwardTransformation ImageHistogram ImageKeypoints ImageLevels ImageLines ImageMargins ImageMarkers ImageMeasurements ImageMultiply ImageOffset ImagePad ImagePadding ImagePartition ImagePeriodogram ImagePerspectiveTransformation ImageQ ImageRangeCache ImageReflect ImageRegion ImageResize ImageResolution ImageRotate ImageRotated ImageScaled ImageScan ImageSize ImageSizeAction ImageSizeCache ImageSizeMultipliers ImageSizeRaw ImageSubtract ImageTake ImageTransformation ImageTrim ImageType ImageValue ImageValuePositions Implies Import ImportAutoReplacements ImportString ImprovementImportance In IncidenceGraph IncidenceList IncidenceMatrix IncludeConstantBasis IncludeFileExtension IncludePods IncludeSingularTerm Increment Indent IndentingNewlineSpacings IndentMaxFraction IndependenceTest IndependentEdgeSetQ IndependentUnit IndependentVertexSetQ Indeterminate IndexCreationOptions Indexed IndexGraph IndexTag Inequality InexactNumberQ InexactNumbers Infinity Infix Information Inherited InheritScope Initialization InitializationCell InitializationCellEvaluation InitializationCellWarning InlineCounterAssignments InlineCounterIncrements InlineRules Inner Inpaint Input InputAliases InputAssumptions InputAutoReplacements InputField InputFieldBox InputFieldBoxOptions InputForm InputGrouping InputNamePacket InputNotebook InputPacket InputSettings InputStream InputString InputStringPacket InputToBoxFormPacket Insert InsertionPointObject InsertResults Inset Inset3DBox Inset3DBoxOptions InsetBox InsetBoxOptions Install InstallService InString Integer IntegerDigits IntegerExponent IntegerLength IntegerPart IntegerPartitions IntegerQ Integers IntegerString Integral Integrate Interactive InteractiveTradingChart Interlaced Interleaving InternallyBalancedDecomposition InterpolatingFunction InterpolatingPolynomial Interpolation InterpolationOrder InterpolationPoints InterpolationPrecision Interpretation InterpretationBox InterpretationBoxOptions InterpretationFunction InterpretTemplate InterquartileRange Interrupt InterruptSettings Intersection Interval IntervalIntersection IntervalMemberQ IntervalUnion Inverse InverseBetaRegularized InverseCDF InverseChiSquareDistribution InverseContinuousWaveletTransform InverseDistanceTransform InverseEllipticNomeQ InverseErf InverseErfc InverseFourier InverseFourierCosTransform InverseFourierSequenceTransform InverseFourierSinTransform InverseFourierTransform InverseFunction InverseFunctions InverseGammaDistribution InverseGammaRegularized InverseGaussianDistribution InverseGudermannian InverseHaversine InverseJacobiCD InverseJacobiCN InverseJacobiCS InverseJacobiDC InverseJacobiDN InverseJacobiDS InverseJacobiNC InverseJacobiND InverseJacobiNS InverseJacobiSC InverseJacobiSD InverseJacobiSN InverseLaplaceTransform InversePermutation InverseRadon InverseSeries InverseSurvivalFunction InverseWaveletTransform InverseWeierstrassP InverseZTransform Invisible InvisibleApplication InvisibleTimes IrreduciblePolynomialQ IsolatingInterval IsomorphicGraphQ IsotopeData Italic Item ItemBox ItemBoxOptions ItemSize ItemStyle ItoProcess JaccardDissimilarity JacobiAmplitude Jacobian JacobiCD JacobiCN JacobiCS JacobiDC JacobiDN JacobiDS JacobiNC JacobiND JacobiNS JacobiP JacobiSC JacobiSD JacobiSN JacobiSymbol JacobiZeta JankoGroupJ1 JankoGroupJ2 JankoGroupJ3 JankoGroupJ4 JarqueBeraALMTest JohnsonDistribution Join Joined JoinedCurve JoinedCurveBox JoinForm JordanDecomposition JordanModelDecomposition K KagiChart KaiserBesselWindow KaiserWindow KalmanEstimator KalmanFilter KarhunenLoeveDecomposition KaryTree KatzCentrality KCoreComponents KDistribution KelvinBei KelvinBer KelvinKei KelvinKer KendallTau KendallTauTest KernelExecute KernelMixtureDistribution KernelObject Kernels Ket Khinchin KirchhoffGraph KirchhoffMatrix KleinInvariantJ KnightTourGraph KnotData KnownUnitQ KolmogorovSmirnovTest KroneckerDelta KroneckerModelDecomposition KroneckerProduct KroneckerSymbol KuiperTest KumaraswamyDistribution Kurtosis KuwaharaFilter Label Labeled LabeledSlider LabelingFunction LabelStyle LaguerreL LambdaComponents LambertW LanczosWindow LandauDistribution Language LanguageCategory LaplaceDistribution LaplaceTransform Laplacian LaplacianFilter LaplacianGaussianFilter Large Larger Last Latitude LatitudeLongitude LatticeData LatticeReduce Launch LaunchKernels LayeredGraphPlot LayerSizeFunction LayoutInformation LCM LeafCount LeapYearQ LeastSquares LeastSquaresFilterKernel Left LeftArrow LeftArrowBar LeftArrowRightArrow LeftDownTeeVector LeftDownVector LeftDownVectorBar LeftRightArrow LeftRightVector LeftTee LeftTeeArrow LeftTeeVector LeftTriangle LeftTriangleBar LeftTriangleEqual LeftUpDownVector LeftUpTeeVector LeftUpVector LeftUpVectorBar LeftVector LeftVectorBar LegendAppearance Legended LegendFunction LegendLabel LegendLayout LegendMargins LegendMarkers LegendMarkerSize LegendreP LegendreQ LegendreType Length LengthWhile LerchPhi Less LessEqual LessEqualGreater LessFullEqual LessGreater LessLess LessSlantEqual LessTilde LetterCharacter LetterQ Level LeveneTest LeviCivitaTensor LevyDistribution Lexicographic LibraryFunction LibraryFunctionError LibraryFunctionInformation LibraryFunctionLoad LibraryFunctionUnload LibraryLoad LibraryUnload LicenseID LiftingFilterData LiftingWaveletTransform LightBlue LightBrown LightCyan Lighter LightGray LightGreen Lighting LightingAngle LightMagenta LightOrange LightPink LightPurple LightRed LightSources LightYellow Likelihood Limit LimitsPositioning LimitsPositioningTokens LindleyDistribution Line Line3DBox LinearFilter LinearFractionalTransform LinearModelFit LinearOffsetFunction LinearProgramming LinearRecurrence LinearSolve LinearSolveFunction LineBox LineBreak LinebreakAdjustments LineBreakChart LineBreakWithin LineColor LineForm LineGraph LineIndent LineIndentMaxFraction LineIntegralConvolutionPlot LineIntegralConvolutionScale LineLegend LineOpacity LineSpacing LineWrapParts LinkActivate LinkClose LinkConnect LinkConnectedQ LinkCreate LinkError LinkFlush LinkFunction LinkHost LinkInterrupt LinkLaunch LinkMode LinkObject LinkOpen LinkOptions LinkPatterns LinkProtocol LinkRead LinkReadHeld LinkReadyQ Links LinkWrite LinkWriteHeld LiouvilleLambda List Listable ListAnimate ListContourPlot ListContourPlot3D ListConvolve ListCorrelate ListCurvePathPlot ListDeconvolve ListDensityPlot Listen ListFourierSequenceTransform ListInterpolation ListLineIntegralConvolutionPlot ListLinePlot ListLogLinearPlot ListLogLogPlot ListLogPlot ListPicker ListPickerBox ListPickerBoxBackground ListPickerBoxOptions ListPlay ListPlot ListPlot3D ListPointPlot3D ListPolarPlot ListQ ListStreamDensityPlot ListStreamPlot ListSurfacePlot3D ListVectorDensityPlot ListVectorPlot ListVectorPlot3D ListZTransform Literal LiteralSearch LocalClusteringCoefficient LocalizeVariables LocationEquivalenceTest LocationTest Locator LocatorAutoCreate LocatorBox LocatorBoxOptions LocatorCentering LocatorPane LocatorPaneBox LocatorPaneBoxOptions LocatorRegion Locked Log Log10 Log2 LogBarnesG LogGamma LogGammaDistribution LogicalExpand LogIntegral LogisticDistribution LogitModelFit LogLikelihood LogLinearPlot LogLogisticDistribution LogLogPlot LogMultinormalDistribution LogNormalDistribution LogPlot LogRankTest LogSeriesDistribution LongEqual Longest LongestAscendingSequence LongestCommonSequence LongestCommonSequencePositions LongestCommonSubsequence LongestCommonSubsequencePositions LongestMatch LongForm Longitude LongLeftArrow LongLeftRightArrow LongRightArrow Loopback LoopFreeGraphQ LowerCaseQ LowerLeftArrow LowerRightArrow LowerTriangularize LowpassFilter LQEstimatorGains LQGRegulator LQOutputRegulatorGains LQRegulatorGains LUBackSubstitution LucasL LuccioSamiComponents LUDecomposition LyapunovSolve LyonsGroupLy MachineID MachineName MachineNumberQ MachinePrecision MacintoshSystemPageSetup Magenta Magnification Magnify MainSolve MaintainDynamicCaches Majority MakeBoxes MakeExpression MakeRules MangoldtLambda ManhattanDistance Manipulate Manipulator MannWhitneyTest MantissaExponent Manual Map MapAll MapAt MapIndexed MAProcess MapThread MarcumQ MardiaCombinedTest MardiaKurtosisTest MardiaSkewnessTest MarginalDistribution MarkovProcessProperties Masking MatchingDissimilarity MatchLocalNameQ MatchLocalNames MatchQ Material MathematicaNotation MathieuC MathieuCharacteristicA MathieuCharacteristicB MathieuCharacteristicExponent MathieuCPrime MathieuGroupM11 MathieuGroupM12 MathieuGroupM22 MathieuGroupM23 MathieuGroupM24 MathieuS MathieuSPrime MathMLForm MathMLText Matrices MatrixExp MatrixForm MatrixFunction MatrixLog MatrixPlot MatrixPower MatrixQ MatrixRank Max MaxBend MaxDetect MaxExtraBandwidths MaxExtraConditions MaxFeatures MaxFilter Maximize MaxIterations MaxMemoryUsed MaxMixtureKernels MaxPlotPoints MaxPoints MaxRecursion MaxStableDistribution MaxStepFraction MaxSteps MaxStepSize MaxValue MaxwellDistribution McLaughlinGroupMcL Mean MeanClusteringCoefficient MeanDegreeConnectivity MeanDeviation MeanFilter MeanGraphDistance MeanNeighborDegree MeanShift MeanShiftFilter Median MedianDeviation MedianFilter Medium MeijerG MeixnerDistribution MemberQ MemoryConstrained MemoryInUse Menu MenuAppearance MenuCommandKey MenuEvaluator MenuItem MenuPacket MenuSortingValue MenuStyle MenuView MergeDifferences Mesh MeshFunctions MeshRange MeshShading MeshStyle Message MessageDialog MessageList MessageName MessageOptions MessagePacket Messages MessagesNotebook MetaCharacters MetaInformation Method MethodOptions MexicanHatWavelet MeyerWavelet Min MinDetect MinFilter MinimalPolynomial MinimalStateSpaceModel Minimize Minors MinRecursion MinSize MinStableDistribution Minus MinusPlus MinValue Missing MissingDataMethod MittagLefflerE MixedRadix MixedRadixQuantity MixtureDistribution Mod Modal Mode Modular ModularLambda Module Modulus MoebiusMu Moment Momentary MomentConvert MomentEvaluate MomentGeneratingFunction Monday Monitor MonomialList MonomialOrder MonsterGroupM MorletWavelet MorphologicalBinarize MorphologicalBranchPoints MorphologicalComponents MorphologicalEulerNumber MorphologicalGraph MorphologicalPerimeter MorphologicalTransform Most MouseAnnotation MouseAppearance MouseAppearanceTag MouseButtons Mouseover MousePointerNote MousePosition MovingAverage MovingMedian MoyalDistribution MultiedgeStyle MultilaunchWarning MultiLetterItalics MultiLetterStyle MultilineFunction Multinomial MultinomialDistribution MultinormalDistribution MultiplicativeOrder Multiplicity Multiselection MultivariateHypergeometricDistribution MultivariatePoissonDistribution MultivariateTDistribution N NakagamiDistribution NameQ Names NamespaceBox Nand NArgMax NArgMin NBernoulliB NCache NDSolve NDSolveValue Nearest NearestFunction NeedCurrentFrontEndPackagePacket NeedCurrentFrontEndSymbolsPacket NeedlemanWunschSimilarity Needs Negative NegativeBinomialDistribution NegativeMultinomialDistribution NeighborhoodGraph Nest NestedGreaterGreater NestedLessLess NestedScriptRules NestList NestWhile NestWhileList NevilleThetaC NevilleThetaD NevilleThetaN NevilleThetaS NewPrimitiveStyle NExpectation Next NextPrime NHoldAll NHoldFirst NHoldRest NicholsGridLines NicholsPlot NIntegrate NMaximize NMaxValue NMinimize NMinValue NominalVariables NonAssociative NoncentralBetaDistribution NoncentralChiSquareDistribution NoncentralFRatioDistribution NoncentralStudentTDistribution NonCommutativeMultiply NonConstants None NonlinearModelFit NonlocalMeansFilter NonNegative NonPositive Nor NorlundB Norm Normal NormalDistribution NormalGrouping Normalize NormalizedSquaredEuclideanDistance NormalsFunction NormFunction Not NotCongruent NotCupCap NotDoubleVerticalBar Notebook NotebookApply NotebookAutoSave NotebookClose NotebookConvertSettings NotebookCreate NotebookCreateReturnObject NotebookDefault NotebookDelete NotebookDirectory NotebookDynamicExpression NotebookEvaluate NotebookEventActions NotebookFileName NotebookFind NotebookFindReturnObject NotebookGet NotebookGetLayoutInformationPacket NotebookGetMisspellingsPacket NotebookInformation NotebookInterfaceObject NotebookLocate NotebookObject NotebookOpen NotebookOpenReturnObject NotebookPath NotebookPrint NotebookPut NotebookPutReturnObject NotebookRead NotebookResetGeneratedCells Notebooks NotebookSave NotebookSaveAs NotebookSelection NotebookSetupLayoutInformationPacket NotebooksMenu NotebookWrite NotElement NotEqualTilde NotExists NotGreater NotGreaterEqual NotGreaterFullEqual NotGreaterGreater NotGreaterLess NotGreaterSlantEqual NotGreaterTilde NotHumpDownHump NotHumpEqual NotLeftTriangle NotLeftTriangleBar NotLeftTriangleEqual NotLess NotLessEqual NotLessFullEqual NotLessGreater NotLessLess NotLessSlantEqual NotLessTilde NotNestedGreaterGreater NotNestedLessLess NotPrecedes NotPrecedesEqual NotPrecedesSlantEqual NotPrecedesTilde NotReverseElement NotRightTriangle NotRightTriangleBar NotRightTriangleEqual NotSquareSubset NotSquareSubsetEqual NotSquareSuperset NotSquareSupersetEqual NotSubset NotSubsetEqual NotSucceeds NotSucceedsEqual NotSucceedsSlantEqual NotSucceedsTilde NotSuperset NotSupersetEqual NotTilde NotTildeEqual NotTildeFullEqual NotTildeTilde NotVerticalBar NProbability NProduct NProductFactors NRoots NSolve NSum NSumTerms Null NullRecords NullSpace NullWords Number NumberFieldClassNumber NumberFieldDiscriminant NumberFieldFundamentalUnits NumberFieldIntegralBasis NumberFieldNormRepresentatives NumberFieldRegulator NumberFieldRootsOfUnity NumberFieldSignature NumberForm NumberFormat NumberMarks NumberMultiplier NumberPadding NumberPoint NumberQ NumberSeparator NumberSigns NumberString Numerator NumericFunction NumericQ NuttallWindow NValues NyquistGridLines NyquistPlot O ObservabilityGramian ObservabilityMatrix ObservableDecomposition ObservableModelQ OddQ Off Offset OLEData On ONanGroupON OneIdentity Opacity Open OpenAppend Opener OpenerBox OpenerBoxOptions OpenerView OpenFunctionInspectorPacket Opening OpenRead OpenSpecialOptions OpenTemporary OpenWrite Operate OperatingSystem OptimumFlowData Optional OptionInspectorSettings OptionQ Options OptionsPacket OptionsPattern OptionValue OptionValueBox OptionValueBoxOptions Or Orange Order OrderDistribution OrderedQ Ordering Orderless OrnsteinUhlenbeckProcess Orthogonalize Out Outer OutputAutoOverwrite OutputControllabilityMatrix OutputControllableModelQ OutputForm OutputFormData OutputGrouping OutputMathEditExpression OutputNamePacket OutputResponse OutputSizeLimit OutputStream Over OverBar OverDot Overflow OverHat Overlaps Overlay OverlayBox OverlayBoxOptions Overscript OverscriptBox OverscriptBoxOptions OverTilde OverVector OwenT OwnValues PackingMethod PaddedForm Padding PadeApproximant PadLeft PadRight PageBreakAbove PageBreakBelow PageBreakWithin PageFooterLines PageFooters PageHeaderLines PageHeaders PageHeight PageRankCentrality PageWidth PairedBarChart PairedHistogram PairedSmoothHistogram PairedTTest PairedZTest PaletteNotebook PalettePath Pane PaneBox PaneBoxOptions Panel PanelBox PanelBoxOptions Paneled PaneSelector PaneSelectorBox PaneSelectorBoxOptions PaperWidth ParabolicCylinderD ParagraphIndent ParagraphSpacing ParallelArray ParallelCombine ParallelDo ParallelEvaluate Parallelization Parallelize ParallelMap ParallelNeeds ParallelProduct ParallelSubmit ParallelSum ParallelTable ParallelTry Parameter ParameterEstimator ParameterMixtureDistribution ParameterVariables ParametricFunction ParametricNDSolve ParametricNDSolveValue ParametricPlot ParametricPlot3D ParentConnect ParentDirectory ParentForm Parenthesize ParentList ParetoDistribution Part PartialCorrelationFunction PartialD ParticleData Partition PartitionsP PartitionsQ ParzenWindow PascalDistribution PassEventsDown PassEventsUp Paste PasteBoxFormInlineCells PasteButton Path PathGraph PathGraphQ Pattern PatternSequence PatternTest PauliMatrix PaulWavelet Pause PausedTime PDF PearsonChiSquareTest PearsonCorrelationTest PearsonDistribution PerformanceGoal PeriodicInterpolation Periodogram PeriodogramArray PermutationCycles PermutationCyclesQ PermutationGroup PermutationLength PermutationList PermutationListQ PermutationMax PermutationMin PermutationOrder PermutationPower PermutationProduct PermutationReplace Permutations PermutationSupport Permute PeronaMalikFilter Perpendicular PERTDistribution PetersenGraph PhaseMargins Pi Pick PIDData PIDDerivativeFilter PIDFeedforward PIDTune Piecewise PiecewiseExpand PieChart PieChart3D PillaiTrace PillaiTraceTest Pink Pivoting PixelConstrained PixelValue PixelValuePositions Placed Placeholder PlaceholderReplace Plain PlanarGraphQ Play PlayRange Plot Plot3D Plot3Matrix PlotDivision PlotJoined PlotLabel PlotLayout PlotLegends PlotMarkers PlotPoints PlotRange PlotRangeClipping PlotRangePadding PlotRegion PlotStyle Plus PlusMinus Pochhammer PodStates PodWidth Point Point3DBox PointBox PointFigureChart PointForm PointLegend PointSize PoissonConsulDistribution PoissonDistribution PoissonProcess PoissonWindow PolarAxes PolarAxesOrigin PolarGridLines PolarPlot PolarTicks PoleZeroMarkers PolyaAeppliDistribution PolyGamma Polygon Polygon3DBox Polygon3DBoxOptions PolygonBox PolygonBoxOptions PolygonHoleScale PolygonIntersections PolygonScale PolyhedronData PolyLog PolynomialExtendedGCD PolynomialForm PolynomialGCD PolynomialLCM PolynomialMod PolynomialQ PolynomialQuotient PolynomialQuotientRemainder PolynomialReduce PolynomialRemainder Polynomials PopupMenu PopupMenuBox PopupMenuBoxOptions PopupView PopupWindow Position Positive PositiveDefiniteMatrixQ PossibleZeroQ Postfix PostScript Power PowerDistribution PowerExpand PowerMod PowerModList PowerSpectralDensity PowersRepresentations PowerSymmetricPolynomial Precedence PrecedenceForm Precedes PrecedesEqual PrecedesSlantEqual PrecedesTilde Precision PrecisionGoal PreDecrement PredictionRoot PreemptProtect PreferencesPath Prefix PreIncrement Prepend PrependTo PreserveImageOptions Previous PriceGraphDistribution PrimaryPlaceholder Prime PrimeNu PrimeOmega PrimePi PrimePowerQ PrimeQ Primes PrimeZetaP PrimitiveRoot PrincipalComponents PrincipalValue Print PrintAction PrintForm PrintingCopies PrintingOptions PrintingPageRange PrintingStartingPageNumber PrintingStyleEnvironment PrintPrecision PrintTemporary Prism PrismBox PrismBoxOptions PrivateCellOptions PrivateEvaluationOptions PrivateFontOptions PrivateFrontEndOptions PrivateNotebookOptions PrivatePaths Probability ProbabilityDistribution ProbabilityPlot ProbabilityPr ProbabilityScalePlot ProbitModelFit ProcessEstimator ProcessParameterAssumptions ProcessParameterQ ProcessStateDomain ProcessTimeDomain Product ProductDistribution ProductLog ProgressIndicator ProgressIndicatorBox ProgressIndicatorBoxOptions Projection Prolog PromptForm Properties Property PropertyList PropertyValue Proportion Proportional Protect Protected ProteinData Pruning PseudoInverse Purple Put PutAppend Pyramid PyramidBox PyramidBoxOptions QBinomial QFactorial QGamma QHypergeometricPFQ QPochhammer QPolyGamma QRDecomposition QuadraticIrrationalQ Quantile QuantilePlot Quantity QuantityForm QuantityMagnitude QuantityQ QuantityUnit Quartics QuartileDeviation Quartiles QuartileSkewness QueueingNetworkProcess QueueingProcess QueueProperties Quiet Quit Quotient QuotientRemainder RadialityCentrality RadicalBox RadicalBoxOptions RadioButton RadioButtonBar RadioButtonBox RadioButtonBoxOptions Radon RamanujanTau RamanujanTauL RamanujanTauTheta RamanujanTauZ Random RandomChoice RandomComplex RandomFunction RandomGraph RandomImage RandomInteger RandomPermutation RandomPrime RandomReal RandomSample RandomSeed RandomVariate RandomWalkProcess Range RangeFilter RangeSpecification RankedMax RankedMin Raster Raster3D Raster3DBox Raster3DBoxOptions RasterArray RasterBox RasterBoxOptions Rasterize RasterSize Rational RationalFunctions Rationalize Rationals Ratios Raw RawArray RawBoxes RawData RawMedium RayleighDistribution Re Read ReadList ReadProtected Real RealBlockDiagonalForm RealDigits RealExponent Reals Reap Record RecordLists RecordSeparators Rectangle RectangleBox RectangleBoxOptions RectangleChart RectangleChart3D RecurrenceFilter RecurrenceTable RecurringDigitsForm Red Reduce RefBox ReferenceLineStyle ReferenceMarkers ReferenceMarkerStyle Refine ReflectionMatrix ReflectionTransform Refresh RefreshRate RegionBinarize RegionFunction RegionPlot RegionPlot3D RegularExpression Regularization Reinstall Release ReleaseHold ReliabilityDistribution ReliefImage ReliefPlot Remove RemoveAlphaChannel RemoveAsynchronousTask Removed RemoveInputStreamMethod RemoveOutputStreamMethod RemoveProperty RemoveScheduledTask RenameDirectory RenameFile RenderAll RenderingOptions RenewalProcess RenkoChart Repeated RepeatedNull RepeatedString Replace ReplaceAll ReplaceHeldPart ReplaceImageValue ReplaceList ReplacePart ReplacePixelValue ReplaceRepeated Resampling Rescale RescalingTransform ResetDirectory ResetMenusPacket ResetScheduledTask Residue Resolve Rest Resultant ResumePacket Return ReturnExpressionPacket ReturnInputFormPacket ReturnPacket ReturnTextPacket Reverse ReverseBiorthogonalSplineWavelet ReverseElement ReverseEquilibrium ReverseGraph ReverseUpEquilibrium RevolutionAxis RevolutionPlot3D RGBColor RiccatiSolve RiceDistribution RidgeFilter RiemannR RiemannSiegelTheta RiemannSiegelZ Riffle Right RightArrow RightArrowBar RightArrowLeftArrow RightCosetRepresentative RightDownTeeVector RightDownVector RightDownVectorBar RightTee RightTeeArrow RightTeeVector RightTriangle RightTriangleBar RightTriangleEqual RightUpDownVector RightUpTeeVector RightUpVector RightUpVectorBar RightVector RightVectorBar RiskAchievementImportance RiskReductionImportance RogersTanimotoDissimilarity Root RootApproximant RootIntervals RootLocusPlot RootMeanSquare RootOfUnityQ RootReduce Roots RootSum Rotate RotateLabel RotateLeft RotateRight RotationAction RotationBox RotationBoxOptions RotationMatrix RotationTransform Round RoundImplies RoundingRadius Row RowAlignments RowBackgrounds RowBox RowHeights RowLines RowMinHeight RowReduce RowsEqual RowSpacings RSolve RudvalisGroupRu Rule RuleCondition RuleDelayed RuleForm RulerUnits Run RunScheduledTask RunThrough RuntimeAttributes RuntimeOptions RussellRaoDissimilarity SameQ SameTest SampleDepth SampledSoundFunction SampledSoundList SampleRate SamplingPeriod SARIMAProcess SARMAProcess SatisfiabilityCount SatisfiabilityInstances SatisfiableQ Saturday Save Saveable SaveAutoDelete SaveDefinitions SawtoothWave Scale Scaled ScaleDivisions ScaledMousePosition ScaleOrigin ScalePadding ScaleRanges ScaleRangeStyle ScalingFunctions ScalingMatrix ScalingTransform Scan ScheduledTaskActiveQ ScheduledTaskData ScheduledTaskObject ScheduledTasks SchurDecomposition ScientificForm ScreenRectangle ScreenStyleEnvironment ScriptBaselineShifts ScriptLevel ScriptMinSize ScriptRules ScriptSizeMultipliers Scrollbars ScrollingOptions ScrollPosition Sec Sech SechDistribution SectionGrouping SectorChart SectorChart3D SectorOrigin SectorSpacing SeedRandom Select Selectable SelectComponents SelectedCells SelectedNotebook Selection SelectionAnimate SelectionCell SelectionCellCreateCell SelectionCellDefaultStyle SelectionCellParentStyle SelectionCreateCell SelectionDebuggerTag SelectionDuplicateCell SelectionEvaluate SelectionEvaluateCreateCell SelectionMove SelectionPlaceholder SelectionSetStyle SelectWithContents SelfLoops SelfLoopStyle SemialgebraicComponentInstances SendMail Sequence SequenceAlignment SequenceForm SequenceHold SequenceLimit Series SeriesCoefficient SeriesData SessionTime Set SetAccuracy SetAlphaChannel SetAttributes Setbacks SetBoxFormNamesPacket SetDelayed SetDirectory SetEnvironment SetEvaluationNotebook SetFileDate SetFileLoadingContext SetNotebookStatusLine SetOptions SetOptionsPacket SetPrecision SetProperty SetSelectedNotebook SetSharedFunction SetSharedVariable SetSpeechParametersPacket SetStreamPosition SetSystemOptions Setter SetterBar SetterBox SetterBoxOptions Setting SetValue Shading Shallow ShannonWavelet ShapiroWilkTest Share Sharpen ShearingMatrix ShearingTransform ShenCastanMatrix Short ShortDownArrow Shortest ShortestMatch ShortestPathFunction ShortLeftArrow ShortRightArrow ShortUpArrow Show ShowAutoStyles ShowCellBracket ShowCellLabel ShowCellTags ShowClosedCellArea ShowContents ShowControls ShowCursorTracker ShowGroupOpenCloseIcon ShowGroupOpener ShowInvisibleCharacters ShowPageBreaks ShowPredictiveInterface ShowSelection ShowShortBoxForm ShowSpecialCharacters ShowStringCharacters ShowSyntaxStyles ShrinkingDelay ShrinkWrapBoundingBox SiegelTheta SiegelTukeyTest Sign Signature SignedRankTest SignificanceLevel SignPadding SignTest SimilarityRules SimpleGraph SimpleGraphQ Simplify Sin Sinc SinghMaddalaDistribution SingleEvaluation SingleLetterItalics SingleLetterStyle SingularValueDecomposition SingularValueList SingularValuePlot SingularValues Sinh SinhIntegral SinIntegral SixJSymbol Skeleton SkeletonTransform SkellamDistribution Skewness SkewNormalDistribution Skip SliceDistribution Slider Slider2D Slider2DBox Slider2DBoxOptions SliderBox SliderBoxOptions SlideView Slot SlotSequence Small SmallCircle Smaller SmithDelayCompensator SmithWatermanSimilarity SmoothDensityHistogram SmoothHistogram SmoothHistogram3D SmoothKernelDistribution SocialMediaData Socket SokalSneathDissimilarity Solve SolveAlways SolveDelayed Sort SortBy Sound SoundAndGraphics SoundNote SoundVolume Sow Space SpaceForm Spacer Spacings Span SpanAdjustments SpanCharacterRounding SpanFromAbove SpanFromBoth SpanFromLeft SpanLineThickness SpanMaxSize SpanMinSize SpanningCharacters SpanSymmetric SparseArray SpatialGraphDistribution Speak SpeakTextPacket SpearmanRankTest SpearmanRho Spectrogram SpectrogramArray Specularity SpellingCorrection SpellingDictionaries SpellingDictionariesPath SpellingOptions SpellingSuggestionsPacket Sphere SphereBox SphericalBesselJ SphericalBesselY SphericalHankelH1 SphericalHankelH2 SphericalHarmonicY SphericalPlot3D SphericalRegion SpheroidalEigenvalue SpheroidalJoiningFactor SpheroidalPS SpheroidalPSPrime SpheroidalQS SpheroidalQSPrime SpheroidalRadialFactor SpheroidalS1 SpheroidalS1Prime SpheroidalS2 SpheroidalS2Prime Splice SplicedDistribution SplineClosed SplineDegree SplineKnots SplineWeights Split SplitBy SpokenString Sqrt SqrtBox SqrtBoxOptions Square SquaredEuclideanDistance SquareFreeQ SquareIntersection SquaresR SquareSubset SquareSubsetEqual SquareSuperset SquareSupersetEqual SquareUnion SquareWave StabilityMargins StabilityMarginsStyle StableDistribution Stack StackBegin StackComplete StackInhibit StandardDeviation StandardDeviationFilter StandardForm Standardize StandbyDistribution Star StarGraph StartAsynchronousTask StartingStepSize StartOfLine StartOfString StartScheduledTask StartupSound StateDimensions StateFeedbackGains StateOutputEstimator StateResponse StateSpaceModel StateSpaceRealization StateSpaceTransform StationaryDistribution StationaryWaveletPacketTransform StationaryWaveletTransform StatusArea StatusCentrality StepMonitor StieltjesGamma StirlingS1 StirlingS2 StopAsynchronousTask StopScheduledTask StrataVariables StratonovichProcess StreamColorFunction StreamColorFunctionScaling StreamDensityPlot StreamPlot StreamPoints StreamPosition Streams StreamScale StreamStyle String StringBreak StringByteCount StringCases StringCount StringDrop StringExpression StringForm StringFormat StringFreeQ StringInsert StringJoin StringLength StringMatchQ StringPosition StringQ StringReplace StringReplaceList StringReplacePart StringReverse StringRotateLeft StringRotateRight StringSkeleton StringSplit StringTake StringToStream StringTrim StripBoxes StripOnInput StripWrapperBoxes StrokeForm StructuralImportance StructuredArray StructuredSelection StruveH StruveL Stub StudentTDistribution Style StyleBox StyleBoxAutoDelete StyleBoxOptions StyleData StyleDefinitions StyleForm StyleKeyMapping StyleMenuListing StyleNameDialogSettings StyleNames StylePrint StyleSheetPath Subfactorial Subgraph SubMinus SubPlus SubresultantPolynomialRemainders SubresultantPolynomials Subresultants Subscript SubscriptBox SubscriptBoxOptions Subscripted Subset SubsetEqual Subsets SubStar Subsuperscript SubsuperscriptBox SubsuperscriptBoxOptions Subtract SubtractFrom SubValues Succeeds SucceedsEqual SucceedsSlantEqual SucceedsTilde SuchThat Sum SumConvergence Sunday SuperDagger SuperMinus SuperPlus Superscript SuperscriptBox SuperscriptBoxOptions Superset SupersetEqual SuperStar Surd SurdForm SurfaceColor SurfaceGraphics SurvivalDistribution SurvivalFunction SurvivalModel SurvivalModelFit SuspendPacket SuzukiDistribution SuzukiGroupSuz SwatchLegend Switch Symbol SymbolName SymletWavelet Symmetric SymmetricGroup SymmetricMatrixQ SymmetricPolynomial SymmetricReduction Symmetrize SymmetrizedArray SymmetrizedArrayRules SymmetrizedDependentComponents SymmetrizedIndependentComponents SymmetrizedReplacePart SynchronousInitialization SynchronousUpdating Syntax SyntaxForm SyntaxInformation SyntaxLength SyntaxPacket SyntaxQ SystemDialogInput SystemException SystemHelpPath SystemInformation SystemInformationData SystemOpen SystemOptions SystemsModelDelay SystemsModelDelayApproximate SystemsModelDelete SystemsModelDimensions SystemsModelExtract SystemsModelFeedbackConnect SystemsModelLabels SystemsModelOrder SystemsModelParallelConnect SystemsModelSeriesConnect SystemsModelStateFeedbackConnect SystemStub Tab TabFilling Table TableAlignments TableDepth TableDirections TableForm TableHeadings TableSpacing TableView TableViewBox TabSpacings TabView TabViewBox TabViewBoxOptions TagBox TagBoxNote TagBoxOptions TaggingRules TagSet TagSetDelayed TagStyle TagUnset Take TakeWhile Tally Tan Tanh TargetFunctions TargetUnits TautologyQ TelegraphProcess TemplateBox TemplateBoxOptions TemplateSlotSequence TemporalData Temporary TemporaryVariable TensorContract TensorDimensions TensorExpand TensorProduct TensorQ TensorRank TensorReduce TensorSymmetry TensorTranspose TensorWedge Tetrahedron TetrahedronBox TetrahedronBoxOptions TeXForm TeXSave Text Text3DBox Text3DBoxOptions TextAlignment TextBand TextBoundingBox TextBox TextCell TextClipboardType TextData TextForm TextJustification TextLine TextPacket TextParagraph TextRecognize TextRendering TextStyle Texture TextureCoordinateFunction TextureCoordinateScaling Therefore ThermometerGauge Thick Thickness Thin Thinning ThisLink ThompsonGroupTh Thread ThreeJSymbol Threshold Through Throw Thumbnail Thursday Ticks TicksStyle Tilde TildeEqual TildeFullEqual TildeTilde TimeConstrained TimeConstraint Times TimesBy TimeSeriesForecast TimeSeriesInvertibility TimeUsed TimeValue TimeZone Timing Tiny TitleGrouping TitsGroupT ToBoxes ToCharacterCode ToColor ToContinuousTimeModel ToDate ToDiscreteTimeModel ToeplitzMatrix ToExpression ToFileName Together Toggle ToggleFalse Toggler TogglerBar TogglerBox TogglerBoxOptions ToHeldExpression ToInvertibleTimeSeries TokenWords Tolerance ToLowerCase ToNumberField TooBig Tooltip TooltipBox TooltipBoxOptions TooltipDelay TooltipStyle Top TopHatTransform TopologicalSort ToRadicals ToRules ToString Total TotalHeight TotalVariationFilter TotalWidth TouchscreenAutoZoom TouchscreenControlPlacement ToUpperCase Tr Trace TraceAbove TraceAction TraceBackward TraceDepth TraceDialog TraceForward TraceInternal TraceLevel TraceOff TraceOn TraceOriginal TracePrint TraceScan TrackedSymbols TradingChart TraditionalForm TraditionalFunctionNotation TraditionalNotation TraditionalOrder TransferFunctionCancel TransferFunctionExpand TransferFunctionFactor TransferFunctionModel TransferFunctionPoles TransferFunctionTransform TransferFunctionZeros TransformationFunction TransformationFunctions TransformationMatrix TransformedDistribution TransformedField Translate TranslationTransform TransparentColor Transpose TreeForm TreeGraph TreeGraphQ TreePlot TrendStyle TriangleWave TriangularDistribution Trig TrigExpand TrigFactor TrigFactorList Trigger TrigReduce TrigToExp TrimmedMean True TrueQ TruncatedDistribution TsallisQExponentialDistribution TsallisQGaussianDistribution TTest Tube TubeBezierCurveBox TubeBezierCurveBoxOptions TubeBox TubeBSplineCurveBox TubeBSplineCurveBoxOptions Tuesday TukeyLambdaDistribution TukeyWindow Tuples TuranGraph TuringMachine Transparent UnateQ Uncompress Undefined UnderBar Underflow Underlined Underoverscript UnderoverscriptBox UnderoverscriptBoxOptions Underscript UnderscriptBox UnderscriptBoxOptions UndirectedEdge UndirectedGraph UndirectedGraphQ UndocumentedTestFEParserPacket UndocumentedTestGetSelectionPacket Unequal Unevaluated UniformDistribution UniformGraphDistribution UniformSumDistribution Uninstall Union UnionPlus Unique UnitBox UnitConvert UnitDimensions Unitize UnitRootTest UnitSimplify UnitStep UnitTriangle UnitVector Unprotect UnsameQ UnsavedVariables Unset UnsetShared UntrackedVariables Up UpArrow UpArrowBar UpArrowDownArrow Update UpdateDynamicObjects UpdateDynamicObjectsSynchronous UpdateInterval UpDownArrow UpEquilibrium UpperCaseQ UpperLeftArrow UpperRightArrow UpperTriangularize Upsample UpSet UpSetDelayed UpTee UpTeeArrow UpValues URL URLFetch URLFetchAsynchronous URLSave URLSaveAsynchronous UseGraphicsRange Using UsingFrontEnd V2Get ValidationLength Value ValueBox ValueBoxOptions ValueForm ValueQ ValuesData Variables Variance VarianceEquivalenceTest VarianceEstimatorFunction VarianceGammaDistribution VarianceTest VectorAngle VectorColorFunction VectorColorFunctionScaling VectorDensityPlot VectorGlyphData VectorPlot VectorPlot3D VectorPoints VectorQ Vectors VectorScale VectorStyle Vee Verbatim Verbose VerboseConvertToPostScriptPacket VerifyConvergence VerifySolutions VerifyTestAssumptions Version VersionNumber VertexAdd VertexCapacity VertexColors VertexComponent VertexConnectivity VertexCoordinateRules VertexCoordinates VertexCorrelationSimilarity VertexCosineSimilarity VertexCount VertexCoverQ VertexDataCoordinates VertexDegree VertexDelete VertexDiceSimilarity VertexEccentricity VertexInComponent VertexInDegree VertexIndex VertexJaccardSimilarity VertexLabeling VertexLabels VertexLabelStyle VertexList VertexNormals VertexOutComponent VertexOutDegree VertexQ VertexRenderingFunction VertexReplace VertexShape VertexShapeFunction VertexSize VertexStyle VertexTextureCoordinates VertexWeight Vertical VerticalBar VerticalForm VerticalGauge VerticalSeparator VerticalSlider VerticalTilde ViewAngle ViewCenter ViewMatrix ViewPoint ViewPointSelectorSettings ViewPort ViewRange ViewVector ViewVertical VirtualGroupData Visible VisibleCell VoigtDistribution VonMisesDistribution WaitAll WaitAsynchronousTask WaitNext WaitUntil WakebyDistribution WalleniusHypergeometricDistribution WaringYuleDistribution WatershedComponents WatsonUSquareTest WattsStrogatzGraphDistribution WaveletBestBasis WaveletFilterCoefficients WaveletImagePlot WaveletListPlot WaveletMapIndexed WaveletMatrixPlot WaveletPhi WaveletPsi WaveletScale WaveletScalogram WaveletThreshold WeaklyConnectedComponents WeaklyConnectedGraphQ WeakStationarity WeatherData WeberE Wedge Wednesday WeibullDistribution WeierstrassHalfPeriods WeierstrassInvariants WeierstrassP WeierstrassPPrime WeierstrassSigma WeierstrassZeta WeightedAdjacencyGraph WeightedAdjacencyMatrix WeightedData WeightedGraphQ Weights WelchWindow WheelGraph WhenEvent Which While White Whitespace WhitespaceCharacter WhittakerM WhittakerW WienerFilter WienerProcess WignerD WignerSemicircleDistribution WilksW WilksWTest WindowClickSelect WindowElements WindowFloating WindowFrame WindowFrameElements WindowMargins WindowMovable WindowOpacity WindowSelected WindowSize WindowStatusArea WindowTitle WindowToolbars WindowWidth With WolframAlpha WolframAlphaDate WolframAlphaQuantity WolframAlphaResult Word WordBoundary WordCharacter WordData WordSearch WordSeparators WorkingPrecision Write WriteString Wronskian XMLElement XMLObject Xnor Xor Yellow YuleDissimilarity ZernikeR ZeroSymmetric ZeroTest ZeroWidthTimes Zeta ZetaZero ZipfDistribution ZTest ZTransform $Aborted $ActivationGroupID $ActivationKey $ActivationUserRegistered $AddOnsDirectory $AssertFunction $Assumptions $AsynchronousTask $BaseDirectory $BatchInput $BatchOutput $BoxForms $ByteOrdering $Canceled $CharacterEncoding $CharacterEncodings $CommandLine $CompilationTarget $ConditionHold $ConfiguredKernels $Context $ContextPath $ControlActiveSetting $CreationDate $CurrentLink $DateStringFormat $DefaultFont $DefaultFrontEnd $DefaultImagingDevice $DefaultPath $Display $DisplayFunction $DistributedContexts $DynamicEvaluation $Echo $Epilog $ExportFormats $Failed $FinancialDataSource $FormatType $FrontEnd $FrontEndSession $GeoLocation $HistoryLength $HomeDirectory $HTTPCookies $IgnoreEOF $ImagingDevices $ImportFormats $InitialDirectory $Input $InputFileName $InputStreamMethods $Inspector $InstallationDate $InstallationDirectory $InterfaceEnvironment $IterationLimit $KernelCount $KernelID $Language $LaunchDirectory $LibraryPath $LicenseExpirationDate $LicenseID $LicenseProcesses $LicenseServer $LicenseSubprocesses $LicenseType $Line $Linked $LinkSupported $LoadedFiles $MachineAddresses $MachineDomain $MachineDomains $MachineEpsilon $MachineID $MachineName $MachinePrecision $MachineType $MaxExtraPrecision $MaxLicenseProcesses $MaxLicenseSubprocesses $MaxMachineNumber $MaxNumber $MaxPiecewiseCases $MaxPrecision $MaxRootDegree $MessageGroups $MessageList $MessagePrePrint $Messages $MinMachineNumber $MinNumber $MinorReleaseNumber $MinPrecision $ModuleNumber $NetworkLicense $NewMessage $NewSymbol $Notebooks $NumberMarks $Off $OperatingSystem $Output $OutputForms $OutputSizeLimit $OutputStreamMethods $Packages $ParentLink $ParentProcessID $PasswordFile $PatchLevelID $Path $PathnameSeparator $PerformanceGoal $PipeSupported $Post $Pre $PreferencesDirectory $PrePrint $PreRead $PrintForms $PrintLiteral $ProcessID $ProcessorCount $ProcessorType $ProductInformation $ProgramName $RandomState $RecursionLimit $ReleaseNumber $RootDirectory $ScheduledTask $ScriptCommandLine $SessionID $SetParentLink $SharedFunctions $SharedVariables $SoundDisplay $SoundDisplayFunction $SuppressInputFormHeads $SynchronousEvaluation $SyntaxHandler $System $SystemCharacterEncoding $SystemID $SystemWordLength $TemporaryDirectory $TemporaryPrefix $TextStyle $TimedOut $TimeUnit $TimeZone $TopDirectory $TraceOff $TraceOn $TracePattern $TracePostAction $TracePreAction $Urgent $UserAddOnsDirectory $UserBaseDirectory $UserDocumentsDirectory $UserName $Version $VersionNumber", +c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{cN:"list",b:/\{/,e:/\}/,i:/:/}]}});hljs.registerLanguage("fsharp",function(e){var t={b:"<",e:">",c:[e.inherit(e.TM,{b:/'[a-zA-Z0-9_]+/})]};return{aliases:["fs"],k:"yield! return! let! do!abstract and as assert base begin class default delegate do done downcast downto elif else end exception extern false finally for fun function global if in inherit inline interface internal lazy let match member module mutable namespace new null of open or override private public rec return sig static struct then to true try type upcast use val void when while with yield",c:[{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},{cN:"string",b:'"""',e:'"""'},e.C("\\(\\*","\\*\\)"),{cN:"class",bK:"type",e:"\\(|=|$",eE:!0,c:[e.UTM,t]},{cN:"annotation",b:"\\[<",e:">\\]",r:10},{cN:"attribute",b:"\\B('[A-Za-z])\\b",c:[e.BE]},e.CLCM,e.inherit(e.QSM,{i:null}),e.CNM]}});hljs.registerLanguage("verilog",function(e){return{aliases:["v"],cI:!0,k:{keyword:"always and assign begin buf bufif0 bufif1 case casex casez cmos deassign default defparam disable edge else end endcase endfunction endmodule endprimitive endspecify endtable endtask event for force forever fork function if ifnone initial inout input join macromodule module nand negedge nmos nor not notif0 notif1 or output parameter pmos posedge primitive pulldown pullup rcmos release repeat rnmos rpmos rtran rtranif0 rtranif1 specify specparam table task timescale tran tranif0 tranif1 wait while xnor xor",typename:"highz0 highz1 integer large medium pull0 pull1 real realtime reg scalared signed small strong0 strong1 supply0 supply0 supply1 supply1 time tri tri0 tri1 triand trior trireg vectored wand weak0 weak1 wire wor"},c:[e.CBCM,e.CLCM,e.QSM,{cN:"number",b:"\\b(\\d+'(b|h|o|d|B|H|O|D))?[0-9xzXZ]+",c:[e.BE],r:0},{cN:"typename",b:"\\.\\w+",r:0},{cN:"value",b:"#\\((?!parameter).+\\)"},{cN:"keyword",b:"\\+|-|\\*|/|%|<|>|=|#|`|\\!|&|\\||@|:|\\^|~|\\{|\\}",r:0}]}});hljs.registerLanguage("dos",function(e){var r=e.C(/@?rem\b/,/$/,{r:10}),t={cN:"label",b:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)",r:0};return{aliases:["bat","cmd"],cI:!0,k:{flow:"if else goto for in do call exit not exist errorlevel defined",operator:"equ neq lss leq gtr geq",keyword:"shift cd dir echo setlocal endlocal set pause copy",stream:"prn nul lpt3 lpt2 lpt1 con com4 com3 com2 com1 aux",winutils:"ping net ipconfig taskkill xcopy ren del",built_in:"append assoc at attrib break cacls cd chcp chdir chkdsk chkntfs cls cmd color comp compact convert date dir diskcomp diskcopy doskey erase fs find findstr format ftype graftabl help keyb label md mkdir mode more move path pause print popd pushd promt rd recover rem rename replace restore rmdir shiftsort start subst time title tree type ver verify vol"},c:[{cN:"envvar",b:/%%[^ ]|%[^ ]+?%|![^ ]+?!/},{cN:"function",b:t.b,e:"goto:eof",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),r]},{cN:"number",b:"\\b\\d+",r:0},r]}});hljs.registerLanguage("gherkin",function(e){return{aliases:["feature"],k:"Feature Background Ability Business Need Scenario Scenarios Scenario Outline Scenario Template Examples Given And Then But When",c:[{cN:"keyword",b:"\\*"},e.C("@[^@\r\n ]+","$"),{cN:"string",b:"\\|",e:"\\$"},{cN:"variable",b:"<",e:">"},e.HCM,{cN:"string",b:'"""',e:'"""'},e.QSM]}});hljs.registerLanguage("xml",function(t){var e="[A-Za-z0-9\\._:-]+",s={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"},c={eW:!0,i:/</,r:0,c:[s,{cN:"attribute",b:e,r:0},{b:"=",r:0,c:[{cN:"value",c:[s],v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s\/>]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"doctype",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},t.C("<!--","-->",{r:10}),{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{title:"style"},c:[c],starts:{e:"</style>",rE:!0,sL:"css"}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{title:"script"},c:[c],starts:{e:"</script>",rE:!0,sL:""}},s,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},c]}]}});hljs.registerLanguage("autohotkey",function(e){var r={cN:"escape",b:"`[\\s\\S]"},c=e.C(";","$",{r:0}),n=[{cN:"built_in",b:"A_[a-zA-Z0-9]+"},{cN:"built_in",bK:"ComSpec Clipboard ClipboardAll ErrorLevel"}];return{cI:!0,k:{keyword:"Break Continue Else Gosub If Loop Return While",literal:"A true false NOT AND OR"},c:n.concat([r,e.inherit(e.QSM,{c:[r]}),c,{cN:"number",b:e.NR,r:0},{cN:"var_expand",b:"%",e:"%",i:"\\n",c:[r]},{cN:"label",c:[r],v:[{b:'^[^\\n";]+::(?!=)'},{b:'^[^\\n";]+:(?!=)',r:0}]},{b:",\\s*,",r:10}])}});hljs.registerLanguage("r",function(e){var r="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[e.HCM,{b:r,l:r,k:{keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",c:[e.BE],v:[{b:'"',e:'"'},{b:"'",e:"'"}]}]}});hljs.registerLanguage("cs",function(e){var r="abstract as base bool break byte case catch char checked const continue decimal dynamic default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long null when object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async protected public private internal ascending descending from get group into join let orderby partial select set value var where yield",t=e.IR+"(<"+e.IR+">)?";return{aliases:["csharp"],k:r,i:/::/,c:[e.C("///","$",{rB:!0,c:[{cN:"xmlDocTag",v:[{b:"///",r:0},{b:"<!--|-->"},{b:"</?",e:">"}]}]}),e.CLCM,e.CBCM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},e.ASM,e.QSM,e.CNM,{bK:"class namespace interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"new return throw await",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}});hljs.registerLanguage("nsis",function(e){var t={cN:"symbol",b:"\\$(ADMINTOOLS|APPDATA|CDBURN_AREA|CMDLINE|COMMONFILES32|COMMONFILES64|COMMONFILES|COOKIES|DESKTOP|DOCUMENTS|EXEDIR|EXEFILE|EXEPATH|FAVORITES|FONTS|HISTORY|HWNDPARENT|INSTDIR|INTERNET_CACHE|LANGUAGE|LOCALAPPDATA|MUSIC|NETHOOD|OUTDIR|PICTURES|PLUGINSDIR|PRINTHOOD|PROFILE|PROGRAMFILES32|PROGRAMFILES64|PROGRAMFILES|QUICKLAUNCH|RECENT|RESOURCES_LOCALIZED|RESOURCES|SENDTO|SMPROGRAMS|SMSTARTUP|STARTMENU|SYSDIR|TEMP|TEMPLATES|VIDEOS|WINDIR)"},n={cN:"constant",b:"\\$+{[a-zA-Z0-9_]+}"},i={cN:"variable",b:"\\$+[a-zA-Z0-9_]+",i:"\\(\\){}"},r={cN:"constant",b:"\\$+\\([a-zA-Z0-9_]+\\)"},o={cN:"params",b:"(ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)"},l={cN:"constant",b:"\\!(addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversionsystem|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|searchparse|searchreplace|tempfile|undef|verbose|warning)"};return{cI:!1,k:{keyword:"Abort AddBrandingImage AddSize AllowRootDirInstall AllowSkipFiles AutoCloseWindow BGFont BGGradient BrandingText BringToFront Call CallInstDLL Caption ChangeUI CheckBitmap ClearErrors CompletedText ComponentText CopyFiles CRCCheck CreateDirectory CreateFont CreateShortCut Delete DeleteINISec DeleteINIStr DeleteRegKey DeleteRegValue DetailPrint DetailsButtonText DirText DirVar DirVerify EnableWindow EnumRegKey EnumRegValue Exch Exec ExecShell ExecWait ExpandEnvStrings File FileBufSize FileClose FileErrorText FileOpen FileRead FileReadByte FileReadUTF16LE FileReadWord FileSeek FileWrite FileWriteByte FileWriteUTF16LE FileWriteWord FindClose FindFirst FindNext FindWindow FlushINI FunctionEnd GetCurInstType GetCurrentAddress GetDlgItem GetDLLVersion GetDLLVersionLocal GetErrorLevel GetFileTime GetFileTimeLocal GetFullPathName GetFunctionAddress GetInstDirError GetLabelAddress GetTempFileName Goto HideWindow Icon IfAbort IfErrors IfFileExists IfRebootFlag IfSilent InitPluginsDir InstallButtonText InstallColors InstallDir InstallDirRegKey InstProgressFlags InstType InstTypeGetText InstTypeSetText IntCmp IntCmpU IntFmt IntOp IsWindow LangString LicenseBkColor LicenseData LicenseForceSelection LicenseLangString LicenseText LoadLanguageFile LockWindow LogSet LogText ManifestDPIAware ManifestSupportedOS MessageBox MiscButtonText Name Nop OutFile Page PageCallbacks PageExEnd Pop Push Quit ReadEnvStr ReadINIStr ReadRegDWORD ReadRegStr Reboot RegDLL Rename RequestExecutionLevel ReserveFile Return RMDir SearchPath SectionEnd SectionGetFlags SectionGetInstTypes SectionGetSize SectionGetText SectionGroupEnd SectionIn SectionSetFlags SectionSetInstTypes SectionSetSize SectionSetText SendMessage SetAutoClose SetBrandingImage SetCompress SetCompressor SetCompressorDictSize SetCtlColors SetCurInstType SetDatablockOptimize SetDateSave SetDetailsPrint SetDetailsView SetErrorLevel SetErrors SetFileAttributes SetFont SetOutPath SetOverwrite SetPluginUnload SetRebootFlag SetRegView SetShellVarContext SetSilent ShowInstDetails ShowUninstDetails ShowWindow SilentInstall SilentUnInstall Sleep SpaceTexts StrCmp StrCmpS StrCpy StrLen SubCaption SubSectionEnd Unicode UninstallButtonText UninstallCaption UninstallIcon UninstallSubCaption UninstallText UninstPage UnRegDLL Var VIAddVersionKey VIFileVersion VIProductVersion WindowIcon WriteINIStr WriteRegBin WriteRegDWORD WriteRegExpandStr WriteRegStr WriteUninstaller XPStyle",literal:"admin all auto both colored current false force hide highest lastused leave listonly none normal notset off on open print show silent silentlog smooth textonly true user "},c:[e.HCM,e.CBCM,{cN:"string",b:'"',e:'"',i:"\\n",c:[{cN:"symbol",b:"\\$(\\\\(n|r|t)|\\$)"},t,n,i,r]},e.C(";","$",{r:0}),{cN:"function",bK:"Function PageEx Section SectionGroup SubSection",e:"$"},l,n,i,r,o,e.NM,{cN:"literal",b:e.IR+"::"+e.IR}]}});hljs.registerLanguage("less",function(e){var r="[\\w-]+",t="("+r+"|@{"+r+"})",a=[],c=[],n=function(e){return{cN:"string",b:"~?"+e+".*?"+e}},i=function(e,r,t){return{cN:e,b:r,r:t}},s=function(r,t,a){return e.inherit({cN:r,b:t+"\\(",e:"\\(",rB:!0,eE:!0,r:0},a)},b={b:"\\(",e:"\\)",c:c,r:0};c.push(e.CLCM,e.CBCM,n("'"),n('"'),e.CSSNM,i("hexcolor","#[0-9A-Fa-f]+\\b"),s("function","(url|data-uri)",{starts:{cN:"string",e:"[\\)\\n]",eE:!0}}),s("function",r),b,i("variable","@@?"+r,10),i("variable","@{"+r+"}"),i("built_in","~?`[^`]*?`"),{cN:"attribute",b:r+"\\s*:",e:":",rB:!0,eE:!0});var o=c.concat({b:"{",e:"}",c:a}),u={bK:"when",eW:!0,c:[{bK:"and not"}].concat(c)},C={cN:"attribute",b:t,e:":",eE:!0,c:[e.CLCM,e.CBCM],i:/\S/,starts:{e:"[;}]",rE:!0,c:c,i:"[<=$]"}},l={cN:"at_rule",b:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{e:"[;{}]",rE:!0,c:c,r:0}},d={cN:"variable",v:[{b:"@"+r+"\\s*:",r:15},{b:"@"+r}],starts:{e:"[;}]",rE:!0,c:o}},p={v:[{b:"[\\.#:&\\[]",e:"[;{}]"},{b:t+"[^;]*{",e:"{"}],rB:!0,rE:!0,i:"[<='$\"]",c:[e.CLCM,e.CBCM,u,i("keyword","all\\b"),i("variable","@{"+r+"}"),i("tag",t+"%?",0),i("id","#"+t),i("class","\\."+t,0),i("keyword","&",0),s("pseudo",":not"),s("keyword",":extend"),i("pseudo","::?"+t),{cN:"attr_selector",b:"\\[",e:"\\]"},{b:"\\(",e:"\\)",c:o},{b:"!important"}]};return a.push(e.CLCM,e.CBCM,l,d,p,C),{cI:!0,i:"[=>'/<($\"]",c:a}});hljs.registerLanguage("pf",function(t){var o={cN:"variable",b:/\$[\w\d#@][\w\d_]*/},e={cN:"variable",b:/</,e:/>/};return{aliases:["pf.conf"],l:/[a-z0-9_<>-]+/,k:{built_in:"block match pass load anchor|5 antispoof|10 set table",keyword:"in out log quick on rdomain inet inet6 proto from port os to routeallow-opts divert-packet divert-reply divert-to flags group icmp-typeicmp6-type label once probability recieved-on rtable prio queuetos tag tagged user keep fragment for os dropaf-to|10 binat-to|10 nat-to|10 rdr-to|10 bitmask least-stats random round-robinsource-hash static-portdup-to reply-to route-toparent bandwidth default min max qlimitblock-policy debug fingerprints hostid limit loginterface optimizationreassemble ruleset-optimization basic none profile skip state-defaultsstate-policy timeoutconst counters persistno modulate synproxy state|5 floating if-bound no-sync pflow|10 sloppysource-track global rule max-src-nodes max-src-states max-src-connmax-src-conn-rate overload flushscrub|5 max-mss min-ttl no-df|10 random-id",literal:"all any no-route self urpf-failed egress|5 unknown"},c:[t.HCM,t.NM,t.QSM,o,e]}});hljs.registerLanguage("lasso",function(e){var r="[a-zA-Z_][a-zA-Z0-9_.]*",a="<\\?(lasso(script)?|=)",t="\\]|\\?>",s={literal:"true false none minimal full all void and or not bw nbw ew new cn ncn lt lte gt gte eq neq rx nrx ft",built_in:"array date decimal duration integer map pair string tag xml null boolean bytes keyword list locale queue set stack staticarray local var variable global data self inherited",keyword:"error_code error_msg error_pop error_push error_reset cache database_names database_schemanames database_tablenames define_tag define_type email_batch encode_set html_comment handle handle_error header if inline iterate ljax_target link link_currentaction link_currentgroup link_currentrecord link_detail link_firstgroup link_firstrecord link_lastgroup link_lastrecord link_nextgroup link_nextrecord link_prevgroup link_prevrecord log loop namespace_using output_none portal private protect records referer referrer repeating resultset rows search_args search_arguments select sort_args sort_arguments thread_atomic value_list while abort case else if_empty if_false if_null if_true loop_abort loop_continue loop_count params params_up return return_value run_children soap_definetag soap_lastrequest soap_lastresponse tag_name ascending average by define descending do equals frozen group handle_failure import in into join let match max min on order parent protected provide public require returnhome skip split_thread sum take thread to trait type where with yield yieldhome"},n=e.C("<!--","-->",{r:0}),o={cN:"preprocessor",b:"\\[noprocess\\]",starts:{cN:"markup",e:"\\[/noprocess\\]",rE:!0,c:[n]}},i={cN:"preprocessor",b:"\\[/noprocess|"+a},l={cN:"variable",b:"'"+r+"'"},c=[e.CLCM,{cN:"javadoc",b:"/\\*\\*!",e:"\\*/",c:[e.PWM]},e.CBCM,e.inherit(e.CNM,{b:e.CNR+"|(-?infinity|nan)\\b"}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"`",e:"`"},{cN:"variable",v:[{b:"[#$]"+r},{b:"#",e:"\\d+",i:"\\W"}]},{cN:"tag",b:"::\\s*",e:r,i:"\\W"},{cN:"attribute",v:[{b:"-"+e.UIR,r:0},{b:"(\\.\\.\\.)"}]},{cN:"subst",v:[{b:"->\\s*",c:[l]},{b:":=|/(?!\\w)=?|[-+*%=<>&|!?\\\\]+",r:0}]},{cN:"built_in",b:"\\.\\.?\\s*",r:0,c:[l]},{cN:"class",bK:"define",rE:!0,e:"\\(|=>",c:[e.inherit(e.TM,{b:e.UIR+"(=(?!>))?"})]}];return{aliases:["ls","lassoscript"],cI:!0,l:r+"|&[lg]t;",k:s,c:[{cN:"preprocessor",b:t,r:0,starts:{cN:"markup",e:"\\[|"+a,rE:!0,r:0,c:[n]}},o,i,{cN:"preprocessor",b:"\\[no_square_brackets",starts:{e:"\\[/no_square_brackets\\]",l:r+"|&[lg]t;",k:s,c:[{cN:"preprocessor",b:t,r:0,starts:{cN:"markup",e:"\\[noprocess\\]|"+a,rE:!0,c:[n]}},o,i].concat(c)}},{cN:"preprocessor",b:"\\[",r:0},{cN:"shebang",b:"^#!.+lasso9\\b",r:10}].concat(c)}});hljs.registerLanguage("prolog",function(c){var r={cN:"atom",b:/[a-z][A-Za-z0-9_]*/,r:0},b={cN:"name",v:[{b:/[A-Z][a-zA-Z0-9_]*/},{b:/_[A-Za-z0-9_]*/}],r:0},a={b:/\(/,e:/\)/,r:0},e={b:/\[/,e:/\]/},n={cN:"comment",b:/%/,e:/$/,c:[c.PWM]},t={cN:"string",b:/`/,e:/`/,c:[c.BE]},g={cN:"string",b:/0\'(\\\'|.)/},N={cN:"string",b:/0\'\\s/},o={b:/:-/},s=[r,b,a,o,e,n,c.CBCM,c.QSM,c.ASM,t,g,N,c.CNM];return a.c=s,e.c=s,{c:s.concat([{b:/\.$/}])}});hljs.registerLanguage("oxygene",function(e){var r="abstract add and array as asc aspect assembly async begin break block by case class concat const copy constructor continue create default delegate desc distinct div do downto dynamic each else empty end ensure enum equals event except exit extension external false final finalize finalizer finally flags for forward from function future global group has if implementation implements implies in index inherited inline interface into invariants is iterator join locked locking loop matching method mod module namespace nested new nil not notify nullable of old on operator or order out override parallel params partial pinned private procedure property protected public queryable raise read readonly record reintroduce remove repeat require result reverse sealed select self sequence set shl shr skip static step soft take then to true try tuple type union unit unsafe until uses using var virtual raises volatile where while with write xor yield await mapped deprecated stdcall cdecl pascal register safecall overload library platform reference packed strict published autoreleasepool selector strong weak unretained",t=e.C("{","}",{r:0}),a=e.C("\\(\\*","\\*\\)",{r:10}),n={cN:"string",b:"'",e:"'",c:[{b:"''"}]},o={cN:"string",b:"(#\\d+)+"},i={cN:"function",bK:"function constructor destructor procedure method",e:"[:;]",k:"function constructor|10 destructor|10 procedure|10 method|10",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",k:r,c:[n,o]},t,a]};return{cI:!0,k:r,i:'("|\\$[G-Zg-z]|\\/\\*|</|=>|->)',c:[t,a,e.CLCM,n,o,e.NM,i,{cN:"class",b:"=\\bclass\\b",e:"end;",k:r,c:[n,o,t,a,e.CLCM,i]}]}});hljs.registerLanguage("applescript",function(e){var t=e.inherit(e.QSM,{i:""}),r={cN:"params",b:"\\(",e:"\\)",c:["self",e.CNM,t]},o=e.C("--","$"),n=e.C("\\(\\*","\\*\\)",{c:["self",o]}),a=[o,n,e.HCM];return{aliases:["osascript"],k:{keyword:"about above after against and around as at back before beginning behind below beneath beside between but by considering contain contains continue copy div does eighth else end equal equals error every exit fifth first for fourth from front get given global if ignoring in into is it its last local me middle mod my ninth not of on onto or over prop property put ref reference repeat returning script second set seventh since sixth some tell tenth that the|0 then third through thru timeout times to transaction try until where while whose with without",constant:"AppleScript false linefeed return pi quote result space tab true",type:"alias application boolean class constant date file integer list number real record string text",command:"activate beep count delay launch log offset read round run say summarize write",property:"character characters contents day frontmost id item length month name paragraph paragraphs rest reverse running time version weekday word words year"},c:[t,e.CNM,{cN:"type",b:"\\bPOSIX file\\b"},{cN:"command",b:"\\b(clipboard info|the clipboard|info for|list (disks|folder)|mount volume|path to|(close|open for) access|(get|set) eof|current date|do shell script|get volume settings|random number|set volume|system attribute|system info|time to GMT|(load|run|store) script|scripting components|ASCII (character|number)|localized string|choose (application|color|file|file name|folder|from list|remote application|URL)|display (alert|dialog))\\b|^\\s*return\\b"},{cN:"constant",b:"\\b(text item delimiters|current application|missing value)\\b"},{cN:"keyword",b:"\\b(apart from|aside from|instead of|out of|greater than|isn't|(doesn't|does not) (equal|come before|come after|contain)|(greater|less) than( or equal)?|(starts?|ends|begins?) with|contained by|comes (before|after)|a (ref|reference))\\b"},{cN:"property",b:"\\b(POSIX path|(date|time) string|quoted form)\\b"},{cN:"function_start",bK:"on",i:"[${=;\\n]",c:[e.UTM,r]}].concat(a),i:"//|->|=>"}});hljs.registerLanguage("makefile",function(e){var a={cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]};return{aliases:["mk","mak"],c:[e.HCM,{b:/^\w+\s*\W*=/,rB:!0,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:!0,starts:{e:/$/,r:0,c:[a]}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,r:0,c:[e.QSM,a]}]}});hljs.registerLanguage("dust",function(e){var a="if eq ne lt lte gt gte select default math sep";return{aliases:["dst"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[{cN:"expression",b:"{",e:"}",r:0,c:[{cN:"begin-block",b:"#[a-zA-Z- .]+",k:a},{cN:"string",b:'"',e:'"'},{cN:"end-block",b:"\\/[a-zA-Z- .]+",k:a},{cN:"variable",b:"[a-zA-Z-.]+",k:a,r:0}]}]}});hljs.registerLanguage("clojure-repl",function(e){return{c:[{cN:"prompt",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure",subLanguageMode:"continuous"}}]}});hljs.registerLanguage("dart",function(e){var t={cN:"subst",b:"\\$\\{",e:"}",k:"true false null this is new super"},r={cN:"string",v:[{b:"r'''",e:"'''"},{b:'r"""',e:'"""'},{b:"r'",e:"'",i:"\\n"},{b:'r"',e:'"',i:"\\n"},{b:"'''",e:"'''",c:[e.BE,t]},{b:'"""',e:'"""',c:[e.BE,t]},{b:"'",e:"'",i:"\\n",c:[e.BE,t]},{b:'"',e:'"',i:"\\n",c:[e.BE,t]}]};t.c=[e.CNM,r];var n={keyword:"assert break case catch class const continue default do else enum extends false final finally for if in is new null rethrow return super switch this throw true try var void while with",literal:"abstract as dynamic export external factory get implements import library operator part set static typedef",built_in:"print Comparable DateTime Duration Function Iterable Iterator List Map Match Null Object Pattern RegExp Set Stopwatch String StringBuffer StringSink Symbol Type Uri bool double int num document window querySelector querySelectorAll Element ElementList"};return{k:n,c:[r,{cN:"dartdoc",b:"/\\*\\*",e:"\\*/",sL:"markdown",subLanguageMode:"continuous"},{cN:"dartdoc",b:"///",e:"$",sL:"markdown",subLanguageMode:"continuous"},e.CLCM,e.CBCM,{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"annotation",b:"@[A-Za-z]+"},{b:"=>"}]}}); \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/jquery.json-view.min.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/jquery.json-view.min.js new file mode 100644 index 0000000000000000000000000000000000000000..ce3a60435e2da5a986f8c24458c1f2b0d837022c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/docs/js/jquery.json-view.min.js @@ -0,0 +1,7 @@ +/** + * jquery.json-view - jQuery collapsible JSON plugin + * @version v1.0.0 + * @link http://github.com/bazh/jquery.json-view + * @license MIT + */ +!function(e){"use strict";var n=function(n){var a=e("<span />",{"class":"collapser",on:{click:function(){var n=e(this);n.toggleClass("collapsed");var a=n.parent().children(".block"),p=a.children("ul");n.hasClass("collapsed")?(p.hide(),a.children(".dots, .comments").show()):(p.show(),a.children(".dots, .comments").hide())}}});return n&&a.addClass("collapsed"),a},a=function(a,p){var t=e.extend({},{nl2br:!0},p),r=function(e){return e.toString()?e.toString().replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">"):""},s=function(n,a){return e("<span />",{"class":a,html:r(n)})},l=function(a,p){switch(e.type(a)){case"object":p||(p=0);var c=e("<span />",{"class":"block"}),d=Object.keys(a).length;if(!d)return c.append(s("{","b")).append(" ").append(s("}","b"));c.append(s("{","b"));var i=e("<ul />",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("<li />").append(s('"',"q")).append(a).append(s('"',"q")).append(": ").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("}","b")),c.append(1===Object.keys(a).length?s("// 1 item","comments"):s("// "+Object.keys(a).length+" items","comments")),c;case"array":p||(p=0);var d=a.length,c=e("<span />",{"class":"block"});if(!d)return c.append(s("[","b")).append(" ").append(s("]","b"));c.append(s("[","b"));var i=e("<ul />",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("<li />").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("]","b")),c.append(1===a.length?s("// 1 item","comments"):s("// "+a.length+" items","comments")),c;case"string":if(a=r(a),/^(http|https|file):\/\/[^\s]+$/i.test(a))return e("<span />").append(s('"',"q")).append(e("<a />",{href:a,text:a})).append(s('"',"q"));if(t.nl2br){var o=/\n/g;o.test(a)&&(a=(a+"").replace(o,"<br />"))}var u=e("<span />",{"class":"str"}).html(a);return e("<span />").append(s('"',"q")).append(u).append(s('"',"q"));case"number":return s(a.toString(),"num");case"undefined":return s("undefined","undef");case"null":return s("null","null");case"boolean":return s(a?"true":"false","bool")}};return l(a)};return e.fn.jsonView=function(n,p){var t=e(this);if(p=e.extend({},{nl2br:!0},p),"string"==typeof n)try{n=JSON.parse(n)}catch(r){}return t.append(e("<div />",{"class":"json-view"}).append(a(n,p))),t}}(jQuery); \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.eot b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..7c79c6a6bc9a128a2a8eaffbe49a4338625fdbc2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.eot differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.svg b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..4b2226d6910bb6a6ffeb1369836d2706576d23d4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="fontawesomeregular" horiz-adv-x="1536" > +<font-face units-per-em="1792" ascent="1536" descent="-256" /> +<missing-glyph horiz-adv-x="448" /> +<glyph unicode=" " horiz-adv-x="448" /> +<glyph unicode="	" horiz-adv-x="448" /> +<glyph unicode=" " horiz-adv-x="448" /> +<glyph unicode="¨" horiz-adv-x="1792" /> +<glyph unicode="©" horiz-adv-x="1792" /> +<glyph unicode="®" horiz-adv-x="1792" /> +<glyph unicode="´" horiz-adv-x="1792" /> +<glyph unicode="Æ" horiz-adv-x="1792" /> +<glyph unicode=" " horiz-adv-x="768" /> +<glyph unicode=" " /> +<glyph unicode=" " horiz-adv-x="768" /> +<glyph unicode=" " /> +<glyph unicode=" " horiz-adv-x="512" /> +<glyph unicode=" " horiz-adv-x="384" /> +<glyph unicode=" " horiz-adv-x="256" /> +<glyph unicode=" " horiz-adv-x="256" /> +<glyph unicode=" " horiz-adv-x="192" /> +<glyph unicode=" " horiz-adv-x="307" /> +<glyph unicode=" " horiz-adv-x="85" /> +<glyph unicode=" " horiz-adv-x="307" /> +<glyph unicode=" " horiz-adv-x="384" /> +<glyph unicode="™" horiz-adv-x="1792" /> +<glyph unicode="∞" horiz-adv-x="1792" /> +<glyph unicode="≠" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" /> +<glyph unicode="" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> +<glyph unicode="" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> +<glyph unicode="" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> +<glyph unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " /> +<glyph unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" /> +<glyph unicode="" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" /> +<glyph unicode="" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" /> +<glyph unicode="" horiz-adv-x="1280" d="M128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280zM768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z " /> +<glyph unicode="" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" /> +<glyph unicode="" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" /> +<glyph unicode="" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" /> +<glyph unicode="" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" /> +<glyph unicode="" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" /> +<glyph unicode="" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" /> +<glyph unicode="" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" /> +<glyph unicode="" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" /> +<glyph unicode="" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> +<glyph unicode="" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M725 977l-170 -450q73 -1 153.5 -2t119 -1.5t52.5 -0.5l29 2q-32 95 -92 241q-53 132 -92 211zM21 -128h-21l2 79q22 7 80 18q89 16 110 31q20 16 48 68l237 616l280 724h75h53l11 -21l205 -480q103 -242 124 -297q39 -102 96 -235q26 -58 65 -164q24 -67 65 -149 q22 -49 35 -57q22 -19 69 -23q47 -6 103 -27q6 -39 6 -57q0 -14 -1 -26q-80 0 -192 8q-93 8 -189 8q-79 0 -135 -2l-200 -11l-58 -2q0 45 4 78l131 28q56 13 68 23q12 12 12 27t-6 32l-47 114l-92 228l-450 2q-29 -65 -104 -274q-23 -64 -23 -84q0 -31 17 -43 q26 -21 103 -32q3 0 13.5 -2t30 -5t40.5 -6q1 -28 1 -58q0 -17 -2 -27q-66 0 -349 20l-48 -8q-81 -14 -167 -14z" /> +<glyph unicode="" horiz-adv-x="1408" d="M555 15q76 -32 140 -32q131 0 216 41t122 113q38 70 38 181q0 114 -41 180q-58 94 -141 126q-80 32 -247 32q-74 0 -101 -10v-144l-1 -173l3 -270q0 -15 12 -44zM541 761q43 -7 109 -7q175 0 264 65t89 224q0 112 -85 187q-84 75 -255 75q-52 0 -130 -13q0 -44 2 -77 q7 -122 6 -279l-1 -98q0 -43 1 -77zM0 -128l2 94q45 9 68 12q77 12 123 31q17 27 21 51q9 66 9 194l-2 497q-5 256 -9 404q-1 87 -11 109q-1 4 -12 12q-18 12 -69 15q-30 2 -114 13l-4 83l260 6l380 13l45 1q5 0 14 0.5t14 0.5q1 0 21.5 -0.5t40.5 -0.5h74q88 0 191 -27 q43 -13 96 -39q57 -29 102 -76q44 -47 65 -104t21 -122q0 -70 -32 -128t-95 -105q-26 -20 -150 -77q177 -41 267 -146q92 -106 92 -236q0 -76 -29 -161q-21 -62 -71 -117q-66 -72 -140 -108q-73 -36 -203 -60q-82 -15 -198 -11l-197 4q-84 2 -298 -11q-33 -3 -272 -11z" /> +<glyph unicode="" horiz-adv-x="1024" d="M0 -126l17 85q4 1 77 20q76 19 116 39q29 37 41 101l27 139l56 268l12 64q8 44 17 84.5t16 67t12.5 46.5t9 30.5t3.5 11.5l29 157l16 63l22 135l8 50v38q-41 22 -144 28q-28 2 -38 4l19 103l317 -14q39 -2 73 -2q66 0 214 9q33 2 68 4.5t36 2.5q-2 -19 -6 -38 q-7 -29 -13 -51q-55 -19 -109 -31q-64 -16 -101 -31q-12 -31 -24 -88q-9 -44 -13 -82q-44 -199 -66 -306l-61 -311l-38 -158l-43 -235l-12 -45q-2 -7 1 -27q64 -15 119 -21q36 -5 66 -10q-1 -29 -7 -58q-7 -31 -9 -41q-18 0 -23 -1q-24 -2 -42 -2q-9 0 -28 3q-19 4 -145 17 l-198 2q-41 1 -174 -11q-74 -7 -98 -9z" /> +<glyph unicode="" horiz-adv-x="1792" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l215 -1h293l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -42.5 2t-103.5 -1t-111 -1 q-34 0 -67 -5q-10 -97 -8 -136l1 -152v-332l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-88 0 -233 -14q-48 -4 -70 -4q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q8 192 6 433l-5 428q-1 62 -0.5 118.5t0.5 102.5t-2 57t-6 15q-6 5 -14 6q-38 6 -148 6q-43 0 -100 -13.5t-73 -24.5q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1744 128q33 0 42 -18.5t-11 -44.5 l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80z" /> +<glyph unicode="" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l446 -1h318l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -58.5 2t-138.5 -1t-128 -1 q-94 0 -127 -5q-10 -97 -8 -136l1 -152v52l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-82 0 -233 -13q-45 -5 -70 -5q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q6 137 6 433l-5 44q0 265 -2 278q-2 11 -6 15q-6 5 -14 6q-38 6 -148 6q-50 0 -168.5 -14t-132.5 -24q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1505 113q26 -20 26 -49t-26 -49l-162 -126 q-26 -20 -44.5 -11t-18.5 42v80h-1024v-80q0 -33 -18.5 -42t-44.5 11l-162 126q-26 20 -26 49t26 49l162 126q26 20 44.5 11t18.5 -42v-80h1024v80q0 33 18.5 42t44.5 -11z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" /> +<glyph unicode="" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> +<glyph unicode="" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" /> +<glyph unicode="" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" /> +<glyph unicode="" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" /> +<glyph unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" /> +<glyph unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" /> +<glyph unicode="" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" /> +<glyph unicode="" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" /> +<glyph unicode="" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" /> +<glyph unicode="" horiz-adv-x="1152" d="M742 -37l-652 651q-37 37 -37 90.5t37 90.5l652 651q37 37 90.5 37t90.5 -37l75 -75q37 -37 37 -90.5t-37 -90.5l-486 -486l486 -485q37 -38 37 -91t-37 -90l-75 -75q-37 -37 -90.5 -37t-90.5 37z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1099 704q0 -52 -37 -91l-652 -651q-37 -37 -90 -37t-90 37l-76 75q-37 39 -37 91q0 53 37 90l486 486l-486 485q-37 39 -37 91q0 53 37 90l76 75q36 38 90 38t90 -38l652 -651q37 -37 37 -90z" /> +<glyph unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" /> +<glyph unicode="" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" /> +<glyph unicode="" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" /> +<glyph unicode="" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" /> +<glyph unicode="" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" /> +<glyph unicode="" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" /> +<glyph unicode="" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" /> +<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" /> +<glyph unicode="" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" /> +<glyph unicode="" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " /> +<glyph unicode="" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" /> +<glyph unicode="" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> +<glyph unicode="" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" /> +<glyph unicode="" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1611 320q0 -53 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-486 485l-486 -485q-36 -38 -90 -38t-90 38l-75 75q-38 36 -38 90q0 53 38 91l651 651q37 37 90 37q52 0 91 -37l650 -651q38 -38 38 -91z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1611 832q0 -53 -37 -90l-651 -651q-38 -38 -91 -38q-54 0 -90 38l-651 651q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l486 -486l486 486q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " /> +<glyph unicode="" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" /> +<glyph unicode="" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1920" d="M512 512v-384h-256v384h256zM896 1024v-896h-256v896h256zM1280 768v-640h-256v640h256zM1664 1152v-1024h-256v1024h256zM1792 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5z M1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> +<glyph unicode="" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1307 618l23 219h-198v109q0 49 15.5 68.5t71.5 19.5h110v219h-175q-152 0 -218 -72t-66 -213v-131h-131v-219h131v-635h262v635h175zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" /> +<glyph unicode="" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" /> +<glyph unicode="" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" /> +<glyph unicode="" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" /> +<glyph unicode="" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" /> +<glyph unicode="" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" /> +<glyph unicode="" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" /> +<glyph unicode="" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" /> +<glyph unicode="" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" /> +<glyph unicode="" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> +<glyph unicode="" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" /> +<glyph unicode="" horiz-adv-x="768" d="M511 980h257l-30 -284h-227v-824h-341v824h-170v284h170v171q0 182 86 275.5t283 93.5h227v-284h-142q-39 0 -62.5 -6.5t-34 -23.5t-13.5 -34.5t-3 -49.5v-142z" /> +<glyph unicode="" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" /> +<glyph unicode="" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" /> +<glyph unicode="" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM183 128h1298q-164 181 -246.5 411.5t-82.5 484.5q0 256 -320 256t-320 -256q0 -254 -82.5 -484.5t-246.5 -411.5zM1664 128q0 -52 -38 -90t-90 -38 h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" /> +<glyph unicode="" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" /> +<glyph unicode="" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" /> +<glyph unicode="" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" /> +<glyph unicode="" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" /> +<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" /> +<glyph unicode="" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" /> +<glyph unicode="" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" /> +<glyph unicode="" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " /> +<glyph unicode="" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " /> +<glyph unicode="" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" /> +<glyph unicode="" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" /> +<glyph unicode="" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" /> +<glyph unicode="" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" /> +<glyph unicode="" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" /> +<glyph unicode="" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" /> +<glyph unicode="" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" /> +<glyph unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" /> +<glyph unicode="" d="M678 -57q0 -38 -10 -71h-380q-95 0 -171.5 56.5t-103.5 147.5q24 45 69 77.5t100 49.5t107 24t107 7q32 0 49 -2q6 -4 30.5 -21t33 -23t31 -23t32 -25.5t27.5 -25.5t26.5 -29.5t21 -30.5t17.5 -34.5t9.5 -36t4.5 -40.5zM385 294q-234 -7 -385 -85v433q103 -118 273 -118 q32 0 70 5q-21 -61 -21 -86q0 -67 63 -149zM558 805q0 -100 -43.5 -160.5t-140.5 -60.5q-51 0 -97 26t-78 67.5t-56 93.5t-35.5 104t-11.5 99q0 96 51.5 165t144.5 69q66 0 119 -41t84 -104t47 -130t16 -128zM1536 896v-736q0 -119 -84.5 -203.5t-203.5 -84.5h-468 q39 73 39 157q0 66 -22 122.5t-55.5 93t-72 71t-72 59.5t-55.5 54.5t-22 59.5q0 36 23 68t56 61.5t65.5 64.5t55.5 93t23 131t-26.5 145.5t-75.5 118.5q-6 6 -14 11t-12.5 7.5t-10 9.5t-10.5 17h135l135 64h-437q-138 0 -244.5 -38.5t-182.5 -133.5q0 126 81 213t207 87h960 q119 0 203.5 -84.5t84.5 -203.5v-96h-256v256h-128v-256h-256v-128h256v-256h128v256h256z" /> +<glyph unicode="" horiz-adv-x="1664" d="M876 71q0 21 -4.5 40.5t-9.5 36t-17.5 34.5t-21 30.5t-26.5 29.5t-27.5 25.5t-32 25.5t-31 23t-33 23t-30.5 21q-17 2 -50 2q-54 0 -106 -7t-108 -25t-98 -46t-69 -75t-27 -107q0 -68 35.5 -121.5t93 -84t120.5 -45.5t127 -15q59 0 112.5 12.5t100.5 39t74.5 73.5 t27.5 110zM756 933q0 60 -16.5 127.5t-47 130.5t-84 104t-119.5 41q-93 0 -144 -69t-51 -165q0 -47 11.5 -99t35.5 -104t56 -93.5t78 -67.5t97 -26q97 0 140.5 60.5t43.5 160.5zM625 1408h437l-135 -79h-135q71 -45 110 -126t39 -169q0 -74 -23 -131.5t-56 -92.5t-66 -64.5 t-56 -61t-23 -67.5q0 -26 16.5 -51t43 -48t58.5 -48t64 -55.5t58.5 -66t43 -85t16.5 -106.5q0 -160 -140 -282q-152 -131 -420 -131q-59 0 -119.5 10t-122 33.5t-108.5 58t-77 89t-30 121.5q0 61 37 135q32 64 96 110.5t145 71t155 36t150 13.5q-64 83 -64 149q0 12 2 23.5 t5 19.5t8 21.5t7 21.5q-40 -5 -70 -5q-149 0 -255.5 98t-106.5 246q0 140 95 250.5t234 141.5q94 20 187 20zM1664 1152v-128h-256v-256h-128v256h-256v128h256v256h128v-256h256z" /> +<glyph unicode="" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" /> +<glyph unicode="" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" /> +<glyph unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" /> +<glyph unicode="" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> +<glyph unicode="" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" /> +<glyph unicode="" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" /> +<glyph unicode="" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" /> +<glyph unicode="" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" /> +<glyph unicode="" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" /> +<glyph unicode="" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1664 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5 q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1024 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1024 608v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280z M768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" /> +<glyph unicode="" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" /> +<glyph unicode="" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> +<glyph unicode="" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" /> +<glyph unicode="" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" /> +<glyph unicode="" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> +<glyph unicode="" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" /> +<glyph unicode="" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" /> +<glyph unicode="" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" /> +<glyph unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" /> +<glyph unicode="" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" /> +<glyph unicode="" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> +<glyph unicode="" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> +<glyph unicode="" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" /> +<glyph unicode="" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" /> +<glyph unicode="" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" /> +<glyph unicode="" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> +<glyph unicode="" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" /> +<glyph unicode="" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" /> +<glyph unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" /> +<glyph unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" /> +<glyph unicode="" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" /> +<glyph unicode="" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> +<glyph unicode="" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" /> +<glyph unicode="" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" /> +<glyph unicode="" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" /> +<glyph unicode="" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" /> +<glyph unicode="" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> +<glyph unicode="" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> +<glyph unicode="" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" /> +<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" /> +<glyph unicode="" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" /> +<glyph unicode="" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" /> +<glyph unicode="" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" /> +<glyph unicode="" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1024 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1024 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28 t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" /> +<glyph unicode="" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" /> +<glyph unicode="" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" /> +<glyph unicode="" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" /> +<glyph unicode="" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" /> +<glyph unicode="" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" /> +<glyph unicode="" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" /> +<glyph unicode="" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" /> +<glyph unicode="" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" /> +<glyph unicode="" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" /> +<glyph unicode="" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" /> +<glyph unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" /> +<glyph unicode="" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" /> +<glyph unicode="" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M390 1408h219v-388h364v-241h-364v-394q0 -136 14 -172q13 -37 52 -60q50 -31 117 -31q117 0 232 76v-242q-102 -48 -178 -65q-77 -19 -173 -19q-105 0 -186 27q-78 25 -138 75q-58 51 -79 105q-22 54 -22 161v539h-170v217q91 30 155 84q64 55 103 132q39 78 54 196z " /> +<glyph unicode="" d="M1123 127v181q-88 -56 -174 -56q-51 0 -88 23q-29 17 -39 45q-11 30 -11 129v295h274v181h-274v291h-164q-11 -90 -40 -147t-78 -99q-48 -40 -116 -63v-163h127v-404q0 -78 17 -121q17 -42 59 -78q43 -37 104 -57q62 -20 140 -20q67 0 129 14q57 13 134 49zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" /> +<glyph unicode="" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" /> +<glyph unicode="" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" /> +<glyph unicode="" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" /> +<glyph unicode="" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" /> +<glyph unicode="" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1483 512l-587 -587q-52 -53 -127.5 -53t-128.5 53l-587 587q-53 53 -53 128t53 128l587 587q53 53 128 53t128 -53l265 -265l-398 -399l-188 188q-42 42 -99 42q-59 0 -100 -41l-120 -121q-42 -40 -42 -99q0 -58 42 -100l406 -408q30 -28 67 -37l6 -4h28q60 0 99 41 l619 619l2 -3q53 -53 53 -128t-53 -128zM1406 1138l120 -120q14 -15 14 -36t-14 -36l-730 -730q-17 -15 -37 -15v0q-4 0 -6 1q-18 2 -30 14l-407 408q-14 15 -14 36t14 35l121 120q13 15 35 15t36 -15l252 -252l574 575q15 15 36 15t36 -15z" /> +<glyph unicode="" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> +<glyph unicode="" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> +<glyph unicode="" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" /> +<glyph unicode="" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" /> +<glyph unicode="" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" /> +<glyph unicode="" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" /> +<glyph unicode="" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" /> +<glyph unicode="" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" /> +<glyph unicode="" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " /> +<glyph unicode="" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> +<glyph unicode="" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" /> +<glyph unicode="" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> +<glyph unicode="" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +<glyph unicode="" horiz-adv-x="1792" /> +</font> +</defs></svg> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.ttf b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e89738de5eaf8fca33a2f2cdc5cb4929caa62b71 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.ttf differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.woff b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..8c1748aab7a790d510fb3f42a8a8971d96efa79d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/fontawesome-webfont.woff differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000000000000000000000000000000000000..187805af66929715b59e8d408c88b0542c85d608 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="glyphicons_halflingsregular" horiz-adv-x="1200" > +<font-face units-per-em="1200" ascent="960" descent="-240" /> +<missing-glyph horiz-adv-x="500" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="400" /> +<glyph unicode=" " /> +<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" /> +<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode=" " /> +<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" /> +<glyph unicode=" " horiz-adv-x="650" /> +<glyph unicode=" " horiz-adv-x="1300" /> +<glyph unicode=" " horiz-adv-x="650" /> +<glyph unicode=" " horiz-adv-x="1300" /> +<glyph unicode=" " horiz-adv-x="433" /> +<glyph unicode=" " horiz-adv-x="325" /> +<glyph unicode=" " horiz-adv-x="216" /> +<glyph unicode=" " horiz-adv-x="216" /> +<glyph unicode=" " horiz-adv-x="162" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="72" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="325" /> +<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" /> +<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" /> +<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" /> +<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" /> +<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " /> +<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" /> +<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" /> +<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" /> +<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" /> +<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" /> +<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" /> +<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" /> +<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" /> +<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" /> +<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" /> +<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" /> +<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" /> +<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" /> +<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" /> +<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" /> +<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" /> +<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" /> +<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" /> +<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> +<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" /> +<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" /> +<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" /> +<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" /> +<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" /> +<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" /> +<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" /> +<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" /> +<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" /> +<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" /> +<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> +<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> +<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" /> +<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" /> +<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" /> +<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" /> +<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" /> +<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" /> +<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" /> +<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" /> +<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" /> +<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" /> +<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" /> +<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" /> +<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" /> +<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" /> +<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" /> +<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" /> +<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" /> +<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" /> +<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" /> +<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" /> +<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" /> +<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" /> +<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" /> +<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" /> +<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" /> +<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" /> +<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" /> +<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" /> +<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" /> +<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" /> +<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> +<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> +<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" /> +<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" /> +<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" /> +<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" /> +<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" /> +<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" /> +<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" /> +<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" /> +<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" /> +<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" /> +<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" /> +<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" /> +<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" /> +<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" /> +<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" /> +<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" /> +<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" /> +<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" /> +<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" /> +<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " /> +<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" /> +<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" /> +<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" /> +<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" /> +<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" /> +<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" /> +<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" /> +<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" /> +<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" /> +<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" /> +<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" /> +<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" /> +<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> +<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" /> +<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" /> +<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> +<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" /> +<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> +<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" /> +<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" /> +<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" /> +<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" /> +<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" /> +<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" /> +<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" /> +<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" /> +<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" /> +<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" /> +<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" /> +<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" /> +<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" /> +<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" /> +<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" /> +<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" /> +<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" /> +<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" /> +<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" /> +<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" /> +<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" /> +<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" /> +<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" /> +<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" /> +<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" /> +<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" /> +<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" /> +<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" /> +<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" /> +<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" /> +<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " /> +<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" /> +<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" /> +<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" /> +<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> +<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> +<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" /> +<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> +<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> +<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" /> +<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" /> +<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" /> +<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" /> +<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" /> +<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" /> +<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" /> +<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" /> +<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" /> +<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" /> +<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" /> +<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" /> +<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" /> +<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" /> +<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" /> +<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" /> +<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" /> +<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" /> +<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" /> +<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" /> +<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" /> +<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" /> +<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" /> +<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" /> +</font> +</defs></svg> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..9e612858f802245ddcbf59788a0db942224bab35 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings-white.png b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings-white.png differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings.png b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..36c3b1ed9e71dce20dca9e35c36c97fd8afd718c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/glyphicons-halflings.png differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/grid.png b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..878c3ed5c196539c4e2da35b7787ab08e98b9cca Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/img/grid.png differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/ajax-form.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/ajax-form.js new file mode 100644 index 0000000000000000000000000000000000000000..1483305ff95fbb97393d68b94f5b341029fd3f65 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/ajax-form.js @@ -0,0 +1,127 @@ +function replaceDocument(docString) { + var doc = document.open("text/html"); + + doc.write(docString); + doc.close(); +} + +function doAjaxSubmit(e) { + var form = $(this); + var btn = $(this.clk); + var method = ( + btn.data('method') || + form.data('method') || + form.attr('method') || 'GET' + ).toUpperCase(); + + if (method === 'GET') { + // GET requests can always use standard form submits. + return; + } + + var contentType = + form.find('input[data-override="content-type"]').val() || + form.find('select[data-override="content-type"] option:selected').text(); + + if (method === 'POST' && !contentType) { + // POST requests can use standard form submits, unless we have + // overridden the content type. + return; + } + + // At this point we need to make an AJAX form submission. + e.preventDefault(); + + var url = form.attr('action'); + var data; + + if (contentType) { + data = form.find('[data-override="content"]').val() || '' + + if (contentType === 'multipart/form-data') { + // We need to add a boundary parameter to the header + // We assume the first valid-looking boundary line in the body is correct + // regex is from RFC 2046 appendix A + var boundaryCharNoSpace = "0-9A-Z'()+_,-./:=?"; + var boundaryChar = boundaryCharNoSpace + ' '; + var re = new RegExp('^--([' + boundaryChar + ']{0,69}[' + boundaryCharNoSpace + '])[\\s]*?$', 'im'); + var boundary = data.match(re); + if (boundary !== null) { + contentType += '; boundary="' + boundary[1] + '"'; + } + // Fix textarea.value EOL normalisation (multipart/form-data should use CR+NL, not NL) + data = data.replace(/\n/g, '\r\n'); + } + } else { + contentType = form.attr('enctype') || form.attr('encoding') + + if (contentType === 'multipart/form-data') { + if (!window.FormData) { + alert('Your browser does not support AJAX multipart form submissions'); + return; + } + + // Use the FormData API and allow the content type to be set automatically, + // so it includes the boundary string. + // See https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects + contentType = false; + data = new FormData(form[0]); + } else { + contentType = 'application/x-www-form-urlencoded; charset=UTF-8' + data = form.serialize(); + } + } + + var ret = $.ajax({ + url: url, + method: method, + data: data, + contentType: contentType, + processData: false, + headers: { + 'Accept': 'text/html; q=1.0, */*' + }, + }); + + ret.always(function(data, textStatus, jqXHR) { + if (textStatus != 'success') { + jqXHR = data; + } + + var responseContentType = jqXHR.getResponseHeader("content-type") || ""; + + if (responseContentType.toLowerCase().indexOf('text/html') === 0) { + replaceDocument(jqXHR.responseText); + + try { + // Modify the location and scroll to top, as if after page load. + history.replaceState({}, '', url); + scroll(0, 0); + } catch (err) { + // History API not supported, so redirect. + window.location = url; + } + } else { + // Not HTML content. We can't open this directly, so redirect. + window.location = url; + } + }); + + return ret; +} + +function captureSubmittingElement(e) { + var target = e.target; + var form = this; + + form.clk = target; +} + +$.fn.ajaxForm = function() { + var options = {} + + return this + .unbind('submit.form-plugin click.form-plugin') + .bind('submit.form-plugin', options, doAjaxSubmit) + .bind('click.form-plugin', options, captureSubmittingElement); +}; diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/bootstrap.min.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/bootstrap.min.js new file mode 100644 index 0000000000000000000000000000000000000000..eb0a8b410f59eb8abcd21e588f1a7b718db3eebd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");!function(t){"use strict";var e=jQuery.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||3<e[0])throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(),function(n){"use strict";n.fn.emulateTransitionEnd=function(t){var e=!1,i=this;n(this).one("bsTransitionEnd",function(){e=!0});return setTimeout(function(){e||n(i).trigger(n.support.transition.end)},t),this},n(function(){n.support.transition=function o(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(t.style[i]!==undefined)return{end:e[i]};return!1}(),n.support.transition&&(n.event.special.bsTransitionEnd={bindType:n.support.transition.end,delegateType:n.support.transition.end,handle:function(t){if(n(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(s){"use strict";var e='[data-dismiss="alert"]',a=function(t){s(t).on("click",e,this.close)};a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.close=function(t){var e=s(this),i=e.attr("data-target");i||(i=(i=e.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),i="#"===i?[]:i;var o=s(document).find(i);function n(){o.detach().trigger("closed.bs.alert").remove()}t&&t.preventDefault(),o.length||(o=e.closest(".alert")),o.trigger(t=s.Event("close.bs.alert")),t.isDefaultPrevented()||(o.removeClass("in"),s.support.transition&&o.hasClass("fade")?o.one("bsTransitionEnd",n).emulateTransitionEnd(a.TRANSITION_DURATION):n())};var t=s.fn.alert;s.fn.alert=function o(i){return this.each(function(){var t=s(this),e=t.data("bs.alert");e||t.data("bs.alert",e=new a(this)),"string"==typeof i&&e[i].call(t)})},s.fn.alert.Constructor=a,s.fn.alert.noConflict=function(){return s.fn.alert=t,this},s(document).on("click.bs.alert.data-api",e,a.prototype.close)}(jQuery),function(s){"use strict";var n=function(t,e){this.$element=s(t),this.options=s.extend({},n.DEFAULTS,e),this.isLoading=!1};function i(o){return this.each(function(){var t=s(this),e=t.data("bs.button"),i="object"==typeof o&&o;e||t.data("bs.button",e=new n(this,i)),"toggle"==o?e.toggle():o&&e.setState(o)})}n.VERSION="3.4.1",n.DEFAULTS={loadingText:"loading..."},n.prototype.setState=function(t){var e="disabled",i=this.$element,o=i.is("input")?"val":"html",n=i.data();t+="Text",null==n.resetText&&i.data("resetText",i[o]()),setTimeout(s.proxy(function(){i[o](null==n[t]?this.options[t]:n[t]),"loadingText"==t?(this.isLoading=!0,i.addClass(e).attr(e,e).prop(e,!0)):this.isLoading&&(this.isLoading=!1,i.removeClass(e).removeAttr(e).prop(e,!1))},this),0)},n.prototype.toggle=function(){var t=!0,e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var i=this.$element.find("input");"radio"==i.prop("type")?(i.prop("checked")&&(t=!1),e.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==i.prop("type")&&(i.prop("checked")!==this.$element.hasClass("active")&&(t=!1),this.$element.toggleClass("active")),i.prop("checked",this.$element.hasClass("active")),t&&i.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var t=s.fn.button;s.fn.button=i,s.fn.button.Constructor=n,s.fn.button.noConflict=function(){return s.fn.button=t,this},s(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=s(t.target).closest(".btn");i.call(e,"toggle"),s(t.target).is('input[type="radio"], input[type="checkbox"]')||(t.preventDefault(),e.is("input,button")?e.trigger("focus"):e.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(t){s(t.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(t.type))})}(jQuery),function(p){"use strict";var c=function(t,e){this.$element=p(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=e,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",p.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",p.proxy(this.pause,this)).on("mouseleave.bs.carousel",p.proxy(this.cycle,this))};function r(n){return this.each(function(){var t=p(this),e=t.data("bs.carousel"),i=p.extend({},c.DEFAULTS,t.data(),"object"==typeof n&&n),o="string"==typeof n?n:i.slide;e||t.data("bs.carousel",e=new c(this,i)),"number"==typeof n?e.to(n):o?e[o]():i.interval&&e.pause().cycle()})}c.VERSION="3.4.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},c.prototype.cycle=function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(p.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},c.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e);if(("prev"==t&&0===i||"next"==t&&i==this.$items.length-1)&&!this.options.wrap)return e;var o=(i+("prev"==t?-1:1))%this.$items.length;return this.$items.eq(o)},c.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(t>this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(i<t?"next":"prev",this.$items.eq(t))},c.prototype.pause=function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&p.support.transition&&(this.$element.trigger(p.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(t,e){var i=this.$element.find(".item.active"),o=e||this.getItemForDirection(t,i),n=this.interval,s="next"==t?"left":"right",a=this;if(o.hasClass("active"))return this.sliding=!1;var r=o[0],l=p.Event("slide.bs.carousel",{relatedTarget:r,direction:s});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,n&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var h=p(this.$indicators.children()[this.getItemIndex(o)]);h&&h.addClass("active")}var d=p.Event("slid.bs.carousel",{relatedTarget:r,direction:s});return p.support.transition&&this.$element.hasClass("slide")?(o.addClass(t),"object"==typeof o&&o.length&&o[0].offsetWidth,i.addClass(s),o.addClass(s),i.one("bsTransitionEnd",function(){o.removeClass([t,s].join(" ")).addClass("active"),i.removeClass(["active",s].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger(d)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(i.removeClass("active"),o.addClass("active"),this.sliding=!1,this.$element.trigger(d)),n&&this.cycle(),this}};var t=p.fn.carousel;p.fn.carousel=r,p.fn.carousel.Constructor=c,p.fn.carousel.noConflict=function(){return p.fn.carousel=t,this};var e=function(t){var e=p(this),i=e.attr("href");i&&(i=i.replace(/.*(?=#[^\s]+$)/,""));var o=e.attr("data-target")||i,n=p(document).find(o);if(n.hasClass("carousel")){var s=p.extend({},n.data(),e.data()),a=e.attr("data-slide-to");a&&(s.interval=!1),r.call(n,s),a&&n.data("bs.carousel").to(a),t.preventDefault()}};p(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),p(window).on("load",function(){p('[data-ride="carousel"]').each(function(){var t=p(this);r.call(t,t.data())})})}(jQuery),function(a){"use strict";var r=function(t,e){this.$element=a(t),this.options=a.extend({},r.DEFAULTS,e),this.$trigger=a('[data-toggle="collapse"][href="#'+t.id+'"],[data-toggle="collapse"][data-target="#'+t.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function n(t){var e,i=t.attr("data-target")||(e=t.attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(i)}function l(o){return this.each(function(){var t=a(this),e=t.data("bs.collapse"),i=a.extend({},r.DEFAULTS,t.data(),"object"==typeof o&&o);!e&&i.toggle&&/show|hide/.test(o)&&(i.toggle=!1),e||t.data("bs.collapse",e=new r(this,i)),"string"==typeof o&&e[o]()})}r.VERSION="3.4.1",r.TRANSITION_DURATION=350,r.DEFAULTS={toggle:!0},r.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},r.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var t,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(t=e.data("bs.collapse"))&&t.transitioning)){var i=a.Event("show.bs.collapse");if(this.$element.trigger(i),!i.isDefaultPrevented()){e&&e.length&&(l.call(e,"hide"),t||e.data("bs.collapse",null));var o=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[o](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var n=function(){this.$element.removeClass("collapsing").addClass("collapse in")[o](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return n.call(this);var s=a.camelCase(["scroll",o].join("-"));this.$element.one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(r.TRANSITION_DURATION)[o](this.$element[0][s])}}}},r.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var t=a.Event("hide.bs.collapse");if(this.$element.trigger(t),!t.isDefaultPrevented()){var e=this.dimension();this.$element[e](this.$element[e]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var i=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return i.call(this);this.$element[e](0).one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(r.TRANSITION_DURATION)}}},r.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},r.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(t,e){var i=a(e);this.addAriaAndCollapsedClass(n(i),i)},this)).end()},r.prototype.addAriaAndCollapsedClass=function(t,e){var i=t.hasClass("in");t.attr("aria-expanded",i),e.toggleClass("collapsed",!i).attr("aria-expanded",i)};var t=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=r,a.fn.collapse.noConflict=function(){return a.fn.collapse=t,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(t){var e=a(this);e.attr("data-target")||t.preventDefault();var i=n(e),o=i.data("bs.collapse")?"toggle":e.data();l.call(i,o)})}(jQuery),function(a){"use strict";var r='[data-toggle="dropdown"]',o=function(t){a(t).on("click.bs.dropdown",this.toggle)};function l(t){var e=t.attr("data-target");e||(e=(e=t.attr("href"))&&/#[A-Za-z]/.test(e)&&e.replace(/.*(?=#[^\s]*$)/,""));var i="#"!==e?a(document).find(e):null;return i&&i.length?i:t.parent()}function s(o){o&&3===o.which||(a(".dropdown-backdrop").remove(),a(r).each(function(){var t=a(this),e=l(t),i={relatedTarget:this};e.hasClass("open")&&(o&&"click"==o.type&&/input|textarea/i.test(o.target.tagName)&&a.contains(e[0],o.target)||(e.trigger(o=a.Event("hide.bs.dropdown",i)),o.isDefaultPrevented()||(t.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",i)))))}))}o.VERSION="3.4.1",o.prototype.toggle=function(t){var e=a(this);if(!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(s(),!o){"ontouchstart"in document.documentElement&&!i.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",s);var n={relatedTarget:this};if(i.trigger(t=a.Event("show.bs.dropdown",n)),t.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),i.toggleClass("open").trigger(a.Event("shown.bs.dropdown",n))}return!1}},o.prototype.keydown=function(t){if(/(38|40|27|32)/.test(t.which)&&!/input|textarea/i.test(t.target.tagName)){var e=a(this);if(t.preventDefault(),t.stopPropagation(),!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(!o&&27!=t.which||o&&27==t.which)return 27==t.which&&i.find(r).trigger("focus"),e.trigger("click");var n=i.find(".dropdown-menu li:not(.disabled):visible a");if(n.length){var s=n.index(t.target);38==t.which&&0<s&&s--,40==t.which&&s<n.length-1&&s++,~s||(s=0),n.eq(s).trigger("focus")}}}};var t=a.fn.dropdown;a.fn.dropdown=function e(i){return this.each(function(){var t=a(this),e=t.data("bs.dropdown");e||t.data("bs.dropdown",e=new o(this)),"string"==typeof i&&e[i].call(t)})},a.fn.dropdown.Constructor=o,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=t,this},a(document).on("click.bs.dropdown.data-api",s).on("click.bs.dropdown.data-api",".dropdown form",function(t){t.stopPropagation()}).on("click.bs.dropdown.data-api",r,o.prototype.toggle).on("keydown.bs.dropdown.data-api",r,o.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",o.prototype.keydown)}(jQuery),function(a){"use strict";var s=function(t,e){this.options=e,this.$body=a(document.body),this.$element=a(t),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.fixedContent=".navbar-fixed-top, .navbar-fixed-bottom",this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};function r(o,n){return this.each(function(){var t=a(this),e=t.data("bs.modal"),i=a.extend({},s.DEFAULTS,t.data(),"object"==typeof o&&o);e||t.data("bs.modal",e=new s(this,i)),"string"==typeof o?e[o](n):i.show&&e.show(n)})}s.VERSION="3.4.1",s.TRANSITION_DURATION=300,s.BACKDROP_TRANSITION_DURATION=150,s.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},s.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},s.prototype.show=function(i){var o=this,t=a.Event("show.bs.modal",{relatedTarget:i});this.$element.trigger(t),this.isShown||t.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(t){a(t.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var t=a.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),t&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:i});t?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(s.TRANSITION_DURATION):o.$element.trigger("focus").trigger(e)}))},s.prototype.hide=function(t){t&&t.preventDefault(),t=a.Event("hide.bs.modal"),this.$element.trigger(t),this.isShown&&!t.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(s.TRANSITION_DURATION):this.hideModal())},s.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(t){document===t.target||this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},s.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},s.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},s.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},s.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},s.prototype.backdrop=function(t){var e=this,i=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var o=a.support.transition&&i;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+i).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(t){this.ignoreBackdropClick?this.ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide())},this)),o&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!t)return;o?this.$backdrop.one("bsTransitionEnd",t).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):t()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var n=function(){e.removeBackdrop(),t&&t()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",n).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):n()}else t&&t()},s.prototype.handleUpdate=function(){this.adjustDialog()},s.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},s.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},s.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth<t,this.scrollbarWidth=this.measureScrollbar()},s.prototype.setScrollbar=function(){var t=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"";var n=this.scrollbarWidth;this.bodyIsOverflowing&&(this.$body.css("padding-right",t+n),a(this.fixedContent).each(function(t,e){var i=e.style.paddingRight,o=a(e).css("padding-right");a(e).data("padding-right",i).css("padding-right",parseFloat(o)+n+"px")}))},s.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad),a(this.fixedContent).each(function(t,e){var i=a(e).data("padding-right");a(e).removeData("padding-right"),e.style.paddingRight=i||""})},s.prototype.measureScrollbar=function(){var t=document.createElement("div");t.className="modal-scrollbar-measure",this.$body.append(t);var e=t.offsetWidth-t.clientWidth;return this.$body[0].removeChild(t),e};var t=a.fn.modal;a.fn.modal=r,a.fn.modal.Constructor=s,a.fn.modal.noConflict=function(){return a.fn.modal=t,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(t){var e=a(this),i=e.attr("href"),o=e.attr("data-target")||i&&i.replace(/.*(?=#[^\s]+$)/,""),n=a(document).find(o),s=n.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(i)&&i},n.data(),e.data());e.is("a")&&t.preventDefault(),n.one("show.bs.modal",function(t){t.isDefaultPrevented()||n.one("hidden.bs.modal",function(){e.is(":visible")&&e.trigger("focus")})}),r.call(n,s,this)})}(jQuery),function(g){"use strict";var o=["sanitize","whiteList","sanitizeFn"],a=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],t={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},r=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,l=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function u(t,e){var i=t.nodeName.toLowerCase();if(-1!==g.inArray(i,e))return-1===g.inArray(i,a)||Boolean(t.nodeValue.match(r)||t.nodeValue.match(l));for(var o=g(e).filter(function(t,e){return e instanceof RegExp}),n=0,s=o.length;n<s;n++)if(i.match(o[n]))return!0;return!1}function n(t,e,i){if(0===t.length)return t;if(i&&"function"==typeof i)return i(t);if(!document.implementation||!document.implementation.createHTMLDocument)return t;var o=document.implementation.createHTMLDocument("sanitization");o.body.innerHTML=t;for(var n=g.map(e,function(t,e){return e}),s=g(o.body).find("*"),a=0,r=s.length;a<r;a++){var l=s[a],h=l.nodeName.toLowerCase();if(-1!==g.inArray(h,n))for(var d=g.map(l.attributes,function(t){return t}),p=[].concat(e["*"]||[],e[h]||[]),c=0,f=d.length;c<f;c++)u(d[c],p)||l.removeAttribute(d[c].nodeName);else l.parentNode.removeChild(l)}return o.body.innerHTML}var m=function(t,e){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",t,e)};m.VERSION="3.4.1",m.TRANSITION_DURATION=150,m.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:t},m.prototype.init=function(t,e,i){if(this.enabled=!0,this.type=t,this.$element=g(e),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var o=this.options.trigger.split(" "),n=o.length;n--;){var s=o[n];if("click"==s)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=s){var a="hover"==s?"mouseenter":"focusin",r="hover"==s?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(r+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},m.prototype.getDefaults=function(){return m.DEFAULTS},m.prototype.getOptions=function(t){var e=this.$element.data();for(var i in e)e.hasOwnProperty(i)&&-1!==g.inArray(i,o)&&delete e[i];return(t=g.extend({},this.getDefaults(),e,t)).delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.sanitize&&(t.template=n(t.template,t.whiteList,t.sanitizeFn)),t},m.prototype.getDelegateOptions=function(){var i={},o=this.getDefaults();return this._options&&g.each(this._options,function(t,e){o[t]!=e&&(i[t]=e)}),i},m.prototype.enter=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusin"==t.type?"focus":"hover"]=!0),e.tip().hasClass("in")||"in"==e.hoverState)e.hoverState="in";else{if(clearTimeout(e.timeout),e.hoverState="in",!e.options.delay||!e.options.delay.show)return e.show();e.timeout=setTimeout(function(){"in"==e.hoverState&&e.show()},e.options.delay.show)}},m.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},m.prototype.leave=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusout"==t.type?"focus":"hover"]=!1),!e.isInStateTrue()){if(clearTimeout(e.timeout),e.hoverState="out",!e.options.delay||!e.options.delay.hide)return e.hide();e.timeout=setTimeout(function(){"out"==e.hoverState&&e.hide()},e.options.delay.hide)}},m.prototype.show=function(){var t=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var e=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!e)return;var i=this,o=this.tip(),n=this.getUID(this.type);this.setContent(),o.attr("id",n),this.$element.attr("aria-describedby",n),this.options.animation&&o.addClass("fade");var s="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,r=a.test(s);r&&(s=s.replace(a,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(s).data("bs."+this.type,this),this.options.container?o.appendTo(g(document).find(this.options.container)):o.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),h=o[0].offsetWidth,d=o[0].offsetHeight;if(r){var p=s,c=this.getPosition(this.$viewport);s="bottom"==s&&l.bottom+d>c.bottom?"top":"top"==s&&l.top-d<c.top?"bottom":"right"==s&&l.right+h>c.width?"left":"left"==s&&l.left-h<c.left?"right":s,o.removeClass(p).addClass(s)}var f=this.getCalculatedOffset(s,l,h,d);this.applyPlacement(f,s);var u=function(){var t=i.hoverState;i.$element.trigger("shown.bs."+i.type),i.hoverState=null,"out"==t&&i.leave(i)};g.support.transition&&this.$tip.hasClass("fade")?o.one("bsTransitionEnd",u).emulateTransitionEnd(m.TRANSITION_DURATION):u()}},m.prototype.applyPlacement=function(t,e){var i=this.tip(),o=i[0].offsetWidth,n=i[0].offsetHeight,s=parseInt(i.css("margin-top"),10),a=parseInt(i.css("margin-left"),10);isNaN(s)&&(s=0),isNaN(a)&&(a=0),t.top+=s,t.left+=a,g.offset.setOffset(i[0],g.extend({using:function(t){i.css({top:Math.round(t.top),left:Math.round(t.left)})}},t),0),i.addClass("in");var r=i[0].offsetWidth,l=i[0].offsetHeight;"top"==e&&l!=n&&(t.top=t.top+n-l);var h=this.getViewportAdjustedDelta(e,t,r,l);h.left?t.left+=h.left:t.top+=h.top;var d=/top|bottom/.test(e),p=d?2*h.left-o+r:2*h.top-n+l,c=d?"offsetWidth":"offsetHeight";i.offset(t),this.replaceArrow(p,i[0][c],d)},m.prototype.replaceArrow=function(t,e,i){this.arrow().css(i?"left":"top",50*(1-t/e)+"%").css(i?"top":"left","")},m.prototype.setContent=function(){var t=this.tip(),e=this.getTitle();this.options.html?(this.options.sanitize&&(e=n(e,this.options.whiteList,this.options.sanitizeFn)),t.find(".tooltip-inner").html(e)):t.find(".tooltip-inner").text(e),t.removeClass("fade in top bottom left right")},m.prototype.hide=function(t){var e=this,i=g(this.$tip),o=g.Event("hide.bs."+this.type);function n(){"in"!=e.hoverState&&i.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),t&&t()}if(this.$element.trigger(o),!o.isDefaultPrevented())return i.removeClass("in"),g.support.transition&&i.hasClass("fade")?i.one("bsTransitionEnd",n).emulateTransitionEnd(m.TRANSITION_DURATION):n(),this.hoverState=null,this},m.prototype.fixTitle=function(){var t=this.$element;(t.attr("title")||"string"!=typeof t.attr("data-original-title"))&&t.attr("data-original-title",t.attr("title")||"").attr("title","")},m.prototype.hasContent=function(){return this.getTitle()},m.prototype.getPosition=function(t){var e=(t=t||this.$element)[0],i="BODY"==e.tagName,o=e.getBoundingClientRect();null==o.width&&(o=g.extend({},o,{width:o.right-o.left,height:o.bottom-o.top}));var n=window.SVGElement&&e instanceof window.SVGElement,s=i?{top:0,left:0}:n?null:t.offset(),a={scroll:i?document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop()},r=i?{width:g(window).width(),height:g(window).height()}:null;return g.extend({},o,a,r,s)},m.prototype.getCalculatedOffset=function(t,e,i,o){return"bottom"==t?{top:e.top+e.height,left:e.left+e.width/2-i/2}:"top"==t?{top:e.top-o,left:e.left+e.width/2-i/2}:"left"==t?{top:e.top+e.height/2-o/2,left:e.left-i}:{top:e.top+e.height/2-o/2,left:e.left+e.width}},m.prototype.getViewportAdjustedDelta=function(t,e,i,o){var n={top:0,left:0};if(!this.$viewport)return n;var s=this.options.viewport&&this.options.viewport.padding||0,a=this.getPosition(this.$viewport);if(/right|left/.test(t)){var r=e.top-s-a.scroll,l=e.top+s-a.scroll+o;r<a.top?n.top=a.top-r:l>a.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;h<a.left?n.left=a.left-h:d>a.right&&(n.left=a.left+a.width-d)}return n},m.prototype.getTitle=function(){var t=this.$element,e=this.options;return t.attr("data-original-title")||("function"==typeof e.title?e.title.call(t[0]):e.title)},m.prototype.getUID=function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},m.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},m.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},m.prototype.enable=function(){this.enabled=!0},m.prototype.disable=function(){this.enabled=!1},m.prototype.toggleEnabled=function(){this.enabled=!this.enabled},m.prototype.toggle=function(t){var e=this;t&&((e=g(t.currentTarget).data("bs."+this.type))||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e))),t?(e.inState.click=!e.inState.click,e.isInStateTrue()?e.enter(e):e.leave(e)):e.tip().hasClass("in")?e.leave(e):e.enter(e)},m.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})},m.prototype.sanitizeHtml=function(t){return n(t,this.options.whiteList,this.options.sanitizeFn)};var e=g.fn.tooltip;g.fn.tooltip=function i(o){return this.each(function(){var t=g(this),e=t.data("bs.tooltip"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.tooltip",e=new m(this,i)),"string"==typeof o&&e[o]())})},g.fn.tooltip.Constructor=m,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=e,this}}(jQuery),function(n){"use strict";var s=function(t,e){this.init("popover",t,e)};if(!n.fn.tooltip)throw new Error("Popover requires tooltip.js");s.VERSION="3.4.1",s.DEFAULTS=n.extend({},n.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),((s.prototype=n.extend({},n.fn.tooltip.Constructor.prototype)).constructor=s).prototype.getDefaults=function(){return s.DEFAULTS},s.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();if(this.options.html){var o=typeof i;this.options.sanitize&&(e=this.sanitizeHtml(e),"string"===o&&(i=this.sanitizeHtml(i))),t.find(".popover-title").html(e),t.find(".popover-content").children().detach().end()["string"===o?"html":"append"](i)}else t.find(".popover-title").text(e),t.find(".popover-content").children().detach().end().text(i);t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},s.prototype.hasContent=function(){return this.getTitle()||this.getContent()},s.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},s.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var t=n.fn.popover;n.fn.popover=function e(o){return this.each(function(){var t=n(this),e=t.data("bs.popover"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.popover",e=new s(this,i)),"string"==typeof o&&e[o]())})},n.fn.popover.Constructor=s,n.fn.popover.noConflict=function(){return n.fn.popover=t,this}}(jQuery),function(s){"use strict";function n(t,e){this.$body=s(document.body),this.$scrollElement=s(t).is(document.body)?s(window):s(t),this.options=s.extend({},n.DEFAULTS,e),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",s.proxy(this.process,this)),this.refresh(),this.process()}function e(o){return this.each(function(){var t=s(this),e=t.data("bs.scrollspy"),i="object"==typeof o&&o;e||t.data("bs.scrollspy",e=new n(this,i)),"string"==typeof o&&e[o]()})}n.VERSION="3.4.1",n.DEFAULTS={offset:10},n.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},n.prototype.refresh=function(){var t=this,o="offset",n=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),s.isWindow(this.$scrollElement[0])||(o="position",n=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var t=s(this),e=t.data("target")||t.attr("href"),i=/^#./.test(e)&&s(e);return i&&i.length&&i.is(":visible")&&[[i[o]().top+n,e]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},n.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),o<=e)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e<n[0])return this.activeTarget=null,this.clear();for(t=n.length;t--;)a!=s[t]&&e>=n[t]&&(n[t+1]===undefined||e<n[t+1])&&this.activate(s[t])},n.prototype.activate=function(t){this.activeTarget=t,this.clear();var e=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',i=s(e).parents("li").addClass("active");i.parent(".dropdown-menu").length&&(i=i.closest("li.dropdown").addClass("active")),i.trigger("activate.bs.scrollspy")},n.prototype.clear=function(){s(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var t=s.fn.scrollspy;s.fn.scrollspy=e,s.fn.scrollspy.Constructor=n,s.fn.scrollspy.noConflict=function(){return s.fn.scrollspy=t,this},s(window).on("load.bs.scrollspy.data-api",function(){s('[data-spy="scroll"]').each(function(){var t=s(this);e.call(t,t.data())})})}(jQuery),function(r){"use strict";var a=function(t){this.element=r(t)};function e(i){return this.each(function(){var t=r(this),e=t.data("bs.tab");e||t.data("bs.tab",e=new a(this)),"string"==typeof i&&e[i]()})}a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.show=function(){var t=this.element,e=t.closest("ul:not(.dropdown-menu)"),i=t.data("target");if(i||(i=(i=t.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),!t.parent("li").hasClass("active")){var o=e.find(".active:last a"),n=r.Event("hide.bs.tab",{relatedTarget:t[0]}),s=r.Event("show.bs.tab",{relatedTarget:o[0]});if(o.trigger(n),t.trigger(s),!s.isDefaultPrevented()&&!n.isDefaultPrevented()){var a=r(document).find(i);this.activate(t.closest("li"),e),this.activate(a,a.parent(),function(){o.trigger({type:"hidden.bs.tab",relatedTarget:t[0]}),t.trigger({type:"shown.bs.tab",relatedTarget:o[0]})})}}},a.prototype.activate=function(t,e,i){var o=e.find("> .active"),n=i&&r.support.transition&&(o.length&&o.hasClass("fade")||!!e.find("> .fade").length);function s(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),t.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),n?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu").length&&t.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),i&&i()}o.length&&n?o.one("bsTransitionEnd",s).emulateTransitionEnd(a.TRANSITION_DURATION):s(),o.removeClass("in")};var t=r.fn.tab;r.fn.tab=e,r.fn.tab.Constructor=a,r.fn.tab.noConflict=function(){return r.fn.tab=t,this};var i=function(t){t.preventDefault(),e.call(r(this),"show")};r(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery),function(l){"use strict";var h=function(t,e){this.options=l.extend({},h.DEFAULTS,e);var i=this.options.target===h.DEFAULTS.target?l(this.options.target):l(document).find(this.options.target);this.$target=i.on("scroll.bs.affix.data-api",l.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",l.proxy(this.checkPositionWithEventLoop,this)),this.$element=l(t),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};function i(o){return this.each(function(){var t=l(this),e=t.data("bs.affix"),i="object"==typeof o&&o;e||t.data("bs.affix",e=new h(this,i)),"string"==typeof o&&e[o]()})}h.VERSION="3.4.1",h.RESET="affix affix-top affix-bottom",h.DEFAULTS={offset:0,target:window},h.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return n<i&&"top";if("bottom"==this.affixed)return null!=i?!(n+this.unpin<=s.top)&&"bottom":!(n+a<=t-o)&&"bottom";var r=null==this.affixed,l=r?n:s.top;return null!=i&&n<=i?"top":null!=o&&t-o<=l+(r?a:e)&&"bottom"},h.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(h.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},h.prototype.checkPositionWithEventLoop=function(){setTimeout(l.proxy(this.checkPosition,this),1)},h.prototype.checkPosition=function(){if(this.$element.is(":visible")){var t=this.$element.height(),e=this.options.offset,i=e.top,o=e.bottom,n=Math.max(l(document).height(),l(document.body).height());"object"!=typeof e&&(o=i=e),"function"==typeof i&&(i=e.top(this.$element)),"function"==typeof o&&(o=e.bottom(this.$element));var s=this.getState(n,t,i,o);if(this.affixed!=s){null!=this.unpin&&this.$element.css("top","");var a="affix"+(s?"-"+s:""),r=l.Event(a+".bs.affix");if(this.$element.trigger(r),r.isDefaultPrevented())return;this.affixed=s,this.unpin="bottom"==s?this.getPinnedOffset():null,this.$element.removeClass(h.RESET).addClass(a).trigger(a.replace("affix","affixed")+".bs.affix")}"bottom"==s&&this.$element.offset({top:n-t-o})}};var t=l.fn.affix;l.fn.affix=i,l.fn.affix.Constructor=h,l.fn.affix.noConflict=function(){return l.fn.affix=t,this},l(window).on("load",function(){l('[data-spy="affix"]').each(function(){var t=l(this),e=t.data();e.offset=e.offset||{},null!=e.offsetBottom&&(e.offset.bottom=e.offsetBottom),null!=e.offsetTop&&(e.offset.top=e.offsetTop),i.call(t,e)})})}(jQuery); \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/coreapi-0.1.1.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/coreapi-0.1.1.js new file mode 100644 index 0000000000000000000000000000000000000000..3c5a2be29da5619509f8969a1ebe3ac0e1e3cc69 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/coreapi-0.1.1.js @@ -0,0 +1,2043 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.coreapi = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var BasicAuthentication = function () { + function BasicAuthentication() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, BasicAuthentication); + + var username = options.username; + var password = options.password; + var hash = window.btoa(username + ':' + password); + this.auth = 'Basic ' + hash; + } + + _createClass(BasicAuthentication, [{ + key: 'authenticate', + value: function authenticate(options) { + options.headers['Authorization'] = this.auth; + return options; + } + }]); + + return BasicAuthentication; +}(); + +module.exports = { + BasicAuthentication: BasicAuthentication +}; + +},{}],2:[function(require,module,exports){ +'use strict'; + +var basic = require('./basic'); +var session = require('./session'); +var token = require('./token'); + +module.exports = { + BasicAuthentication: basic.BasicAuthentication, + SessionAuthentication: session.SessionAuthentication, + TokenAuthentication: token.TokenAuthentication +}; + +},{"./basic":1,"./session":3,"./token":4}],3:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var utils = require('../utils'); + +function trim(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); +} + +function getCookie(cookieName, cookieString) { + cookieString = cookieString || window.document.cookie; + if (cookieString && cookieString !== '') { + var cookies = cookieString.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, cookieName.length + 1) === cookieName + '=') { + return decodeURIComponent(cookie.substring(cookieName.length + 1)); + } + } + } + return null; +} + +var SessionAuthentication = function () { + function SessionAuthentication() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, SessionAuthentication); + + this.csrfToken = getCookie(options.csrfCookieName, options.cookieString); + this.csrfHeaderName = options.csrfHeaderName; + } + + _createClass(SessionAuthentication, [{ + key: 'authenticate', + value: function authenticate(options) { + options.credentials = 'same-origin'; + if (this.csrfToken && !utils.csrfSafeMethod(options.method)) { + options.headers[this.csrfHeaderName] = this.csrfToken; + } + return options; + } + }]); + + return SessionAuthentication; +}(); + +module.exports = { + SessionAuthentication: SessionAuthentication +}; + +},{"../utils":15}],4:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var TokenAuthentication = function () { + function TokenAuthentication() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, TokenAuthentication); + + this.token = options.token; + this.scheme = options.scheme || 'Bearer'; + } + + _createClass(TokenAuthentication, [{ + key: 'authenticate', + value: function authenticate(options) { + options.headers['Authorization'] = this.scheme + ' ' + this.token; + return options; + } + }]); + + return TokenAuthentication; +}(); + +module.exports = { + TokenAuthentication: TokenAuthentication +}; + +},{}],5:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var document = require('./document'); +var codecs = require('./codecs'); +var errors = require('./errors'); +var transports = require('./transports'); +var utils = require('./utils'); + +function lookupLink(node, keys) { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var key = _step.value; + + if (node instanceof document.Document) { + node = node.content[key]; + } else { + node = node[key]; + } + if (node === undefined) { + throw new errors.LinkLookupError('Invalid link lookup: ' + JSON.stringify(keys)); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (!(node instanceof document.Link)) { + throw new errors.LinkLookupError('Invalid link lookup: ' + JSON.stringify(keys)); + } + return node; +} + +var Client = function () { + function Client() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, Client); + + var transportOptions = { + auth: options.auth || null, + headers: options.headers || {}, + requestCallback: options.requestCallback, + responseCallback: options.responseCallback + }; + + this.decoders = options.decoders || [new codecs.CoreJSONCodec(), new codecs.JSONCodec(), new codecs.TextCodec()]; + this.transports = options.transports || [new transports.HTTPTransport(transportOptions)]; + } + + _createClass(Client, [{ + key: 'action', + value: function action(document, keys) { + var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var link = lookupLink(document, keys); + var transport = utils.determineTransport(this.transports, link.url); + return transport.action(link, this.decoders, params); + } + }, { + key: 'get', + value: function get(url) { + var link = new document.Link(url, 'get'); + var transport = utils.determineTransport(this.transports, url); + return transport.action(link, this.decoders); + } + }]); + + return Client; +}(); + +module.exports = { + Client: Client +}; + +},{"./codecs":7,"./document":10,"./errors":11,"./transports":14,"./utils":15}],6:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var document = require('../document'); +var URL = require('url-parse'); + +function unescapeKey(key) { + if (key.match(/__(type|meta)$/)) { + return key.substring(1); + } + return key; +} + +function getString(obj, key) { + var value = obj[key]; + if (typeof value === 'string') { + return value; + } + return ''; +} + +function getBoolean(obj, key) { + var value = obj[key]; + if (typeof value === 'boolean') { + return value; + } + return false; +} + +function getObject(obj, key) { + var value = obj[key]; + if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') { + return value; + } + return {}; +} + +function getArray(obj, key) { + var value = obj[key]; + if (value instanceof Array) { + return value; + } + return []; +} + +function getContent(data, baseUrl) { + var excluded = ['_type', '_meta']; + var content = {}; + for (var property in data) { + if (data.hasOwnProperty(property) && !excluded.includes(property)) { + var key = unescapeKey(property); + var value = primitiveToNode(data[property], baseUrl); + content[key] = value; + } + } + return content; +} + +function primitiveToNode(data, baseUrl) { + var isObject = data instanceof Object && !(data instanceof Array); + + if (isObject && data._type === 'document') { + // Document + var meta = getObject(data, '_meta'); + var relativeUrl = getString(meta, 'url'); + var url = relativeUrl ? URL(relativeUrl, baseUrl).toString() : ''; + var title = getString(meta, 'title'); + var description = getString(meta, 'description'); + var content = getContent(data, url); + return new document.Document(url, title, description, content); + } else if (isObject && data._type === 'link') { + // Link + var _relativeUrl = getString(data, 'url'); + var _url = _relativeUrl ? URL(_relativeUrl, baseUrl).toString() : ''; + var method = getString(data, 'action') || 'get'; + var _title = getString(data, 'title'); + var _description = getString(data, 'description'); + var fieldsData = getArray(data, 'fields'); + var fields = []; + for (var idx = 0, len = fieldsData.length; idx < len; idx++) { + var value = fieldsData[idx]; + var name = getString(value, 'name'); + var required = getBoolean(value, 'required'); + var location = getString(value, 'location'); + var fieldDescription = getString(value, 'fieldDescription'); + var field = new document.Field(name, required, location, fieldDescription); + fields.push(field); + } + return new document.Link(_url, method, 'application/json', fields, _title, _description); + } else if (isObject) { + // Object + var _content = {}; + for (var key in data) { + if (data.hasOwnProperty(key)) { + _content[key] = primitiveToNode(data[key], baseUrl); + } + } + return _content; + } else if (data instanceof Array) { + // Object + var _content2 = []; + for (var _idx = 0, _len = data.length; _idx < _len; _idx++) { + _content2.push(primitiveToNode(data[_idx], baseUrl)); + } + return _content2; + } + // Primitive + return data; +} + +var CoreJSONCodec = function () { + function CoreJSONCodec() { + _classCallCheck(this, CoreJSONCodec); + + this.mediaType = 'application/coreapi+json'; + } + + _createClass(CoreJSONCodec, [{ + key: 'decode', + value: function decode(text) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var data = text; + if (options.preloaded === undefined || !options.preloaded) { + data = JSON.parse(text); + } + return primitiveToNode(data, options.url); + } + }]); + + return CoreJSONCodec; +}(); + +module.exports = { + CoreJSONCodec: CoreJSONCodec +}; + +},{"../document":10,"url-parse":19}],7:[function(require,module,exports){ +'use strict'; + +var corejson = require('./corejson'); +var json = require('./json'); +var text = require('./text'); + +module.exports = { + CoreJSONCodec: corejson.CoreJSONCodec, + JSONCodec: json.JSONCodec, + TextCodec: text.TextCodec +}; + +},{"./corejson":6,"./json":8,"./text":9}],8:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var JSONCodec = function () { + function JSONCodec() { + _classCallCheck(this, JSONCodec); + + this.mediaType = 'application/json'; + } + + _createClass(JSONCodec, [{ + key: 'decode', + value: function decode(text) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return JSON.parse(text); + } + }]); + + return JSONCodec; +}(); + +module.exports = { + JSONCodec: JSONCodec +}; + +},{}],9:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var TextCodec = function () { + function TextCodec() { + _classCallCheck(this, TextCodec); + + this.mediaType = 'text/*'; + } + + _createClass(TextCodec, [{ + key: 'decode', + value: function decode(text) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return text; + } + }]); + + return TextCodec; +}(); + +module.exports = { + TextCodec: TextCodec +}; + +},{}],10:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Document = function Document() { + var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var title = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var description = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + var content = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + _classCallCheck(this, Document); + + this.url = url; + this.title = title; + this.description = description; + this.content = content; +}; + +var Link = function Link(url, method) { + var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'application/json'; + var fields = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; + var title = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : ''; + var description = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : ''; + + _classCallCheck(this, Link); + + if (url === undefined) { + throw new Error('url argument is required'); + } + + if (method === undefined) { + throw new Error('method argument is required'); + } + + this.url = url; + this.method = method; + this.encoding = encoding; + this.fields = fields; + this.title = title; + this.description = description; +}; + +var Field = function Field(name) { + var required = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + var location = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; + var description = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; + + _classCallCheck(this, Field); + + if (name === undefined) { + throw new Error('name argument is required'); + } + + this.name = name; + this.required = required; + this.location = location; + this.description = description; +}; + +module.exports = { + Document: Document, + Link: Link, + Field: Field +}; + +},{}],11:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ParameterError = function (_Error) { + _inherits(ParameterError, _Error); + + function ParameterError(message) { + _classCallCheck(this, ParameterError); + + var _this = _possibleConstructorReturn(this, (ParameterError.__proto__ || Object.getPrototypeOf(ParameterError)).call(this, message)); + + _this.message = message; + _this.name = 'ParameterError'; + return _this; + } + + return ParameterError; +}(Error); + +var LinkLookupError = function (_Error2) { + _inherits(LinkLookupError, _Error2); + + function LinkLookupError(message) { + _classCallCheck(this, LinkLookupError); + + var _this2 = _possibleConstructorReturn(this, (LinkLookupError.__proto__ || Object.getPrototypeOf(LinkLookupError)).call(this, message)); + + _this2.message = message; + _this2.name = 'LinkLookupError'; + return _this2; + } + + return LinkLookupError; +}(Error); + +var ErrorMessage = function (_Error3) { + _inherits(ErrorMessage, _Error3); + + function ErrorMessage(message, content) { + _classCallCheck(this, ErrorMessage); + + var _this3 = _possibleConstructorReturn(this, (ErrorMessage.__proto__ || Object.getPrototypeOf(ErrorMessage)).call(this, message)); + + _this3.message = message; + _this3.content = content; + _this3.name = 'ErrorMessage'; + return _this3; + } + + return ErrorMessage; +}(Error); + +module.exports = { + ParameterError: ParameterError, + LinkLookupError: LinkLookupError, + ErrorMessage: ErrorMessage +}; + +},{}],12:[function(require,module,exports){ +'use strict'; + +var auth = require('./auth'); +var client = require('./client'); +var codecs = require('./codecs'); +var document = require('./document'); +var errors = require('./errors'); +var transports = require('./transports'); +var utils = require('./utils'); + +var coreapi = { + Client: client.Client, + Document: document.Document, + Link: document.Link, + auth: auth, + codecs: codecs, + errors: errors, + transports: transports, + utils: utils +}; + +module.exports = coreapi; + +},{"./auth":2,"./client":5,"./codecs":7,"./document":10,"./errors":11,"./transports":14,"./utils":15}],13:[function(require,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var fetch = require('isomorphic-fetch'); +var errors = require('../errors'); +var utils = require('../utils'); +var URL = require('url-parse'); +var urlTemplate = require('url-template'); + +var parseResponse = function parseResponse(response, decoders, responseCallback) { + return response.text().then(function (text) { + if (responseCallback) { + responseCallback(response, text); + } + var contentType = response.headers.get('Content-Type'); + var decoder = utils.negotiateDecoder(decoders, contentType); + var options = { url: response.url }; + return decoder.decode(text, options); + }); +}; + +var HTTPTransport = function () { + function HTTPTransport() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, HTTPTransport); + + this.schemes = ['http', 'https']; + this.auth = options.auth || null; + this.headers = options.headers || {}; + this.fetch = options.fetch || fetch; + this.FormData = options.FormData || window.FormData; + this.requestCallback = options.requestCallback; + this.responseCallback = options.responseCallback; + } + + _createClass(HTTPTransport, [{ + key: 'buildRequest', + value: function buildRequest(link, decoders) { + var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var fields = link.fields; + var method = link.method.toUpperCase(); + var queryParams = {}; + var pathParams = {}; + var formParams = {}; + var fieldNames = []; + var hasBody = false; + + for (var idx = 0, len = fields.length; idx < len; idx++) { + var field = fields[idx]; + + // Ensure any required fields are included + if (!params.hasOwnProperty(field.name)) { + if (field.required) { + throw new errors.ParameterError('Missing required field: "' + field.name + '"'); + } else { + continue; + } + } + + fieldNames.push(field.name); + if (field.location === 'query') { + queryParams[field.name] = params[field.name]; + } else if (field.location === 'path') { + pathParams[field.name] = params[field.name]; + } else if (field.location === 'form') { + formParams[field.name] = params[field.name]; + hasBody = true; + } else if (field.location === 'body') { + formParams = params[field.name]; + hasBody = true; + } + } + + // Check for any parameters that did not have a matching field + for (var property in params) { + if (params.hasOwnProperty(property) && !fieldNames.includes(property)) { + throw new errors.ParameterError('Unknown parameter: "' + property + '"'); + } + } + + var requestOptions = { method: method, headers: {} }; + + Object.assign(requestOptions.headers, this.headers); + + if (hasBody) { + if (link.encoding === 'application/json') { + requestOptions.body = JSON.stringify(formParams); + requestOptions.headers['Content-Type'] = 'application/json'; + } else if (link.encoding === 'multipart/form-data') { + var form = new this.FormData(); + + for (var paramKey in formParams) { + form.append(paramKey, formParams[paramKey]); + } + requestOptions.body = form; + } else if (link.encoding === 'application/x-www-form-urlencoded') { + var formBody = []; + for (var _paramKey in formParams) { + var encodedKey = encodeURIComponent(_paramKey); + var encodedValue = encodeURIComponent(formParams[_paramKey]); + formBody.push(encodedKey + '=' + encodedValue); + } + formBody = formBody.join('&'); + + requestOptions.body = formBody; + requestOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + } + + if (this.auth) { + requestOptions = this.auth.authenticate(requestOptions); + } + + var parsedUrl = urlTemplate.parse(link.url); + parsedUrl = parsedUrl.expand(pathParams); + parsedUrl = new URL(parsedUrl); + parsedUrl.set('query', queryParams); + + return { + url: parsedUrl.toString(), + options: requestOptions + }; + } + }, { + key: 'action', + value: function action(link, decoders) { + var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var responseCallback = this.responseCallback; + var request = this.buildRequest(link, decoders, params); + + if (this.requestCallback) { + this.requestCallback(request); + } + + return this.fetch(request.url, request.options).then(function (response) { + if (response.status === 204) { + return; + } + return parseResponse(response, decoders, responseCallback).then(function (data) { + if (response.ok) { + return data; + } else { + var title = response.status + ' ' + response.statusText; + var error = new errors.ErrorMessage(title, data); + return Promise.reject(error); + } + }); + }); + } + }]); + + return HTTPTransport; +}(); + +module.exports = { + HTTPTransport: HTTPTransport +}; + +},{"../errors":11,"../utils":15,"isomorphic-fetch":16,"url-parse":19,"url-template":21}],14:[function(require,module,exports){ +'use strict'; + +var http = require('./http'); + +module.exports = { + HTTPTransport: http.HTTPTransport +}; + +},{"./http":13}],15:[function(require,module,exports){ +'use strict'; + +var URL = require('url-parse'); + +var determineTransport = function determineTransport(transports, url) { + var parsedUrl = new URL(url); + var scheme = parsedUrl.protocol.replace(':', ''); + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = transports[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var transport = _step.value; + + if (transport.schemes.includes(scheme)) { + return transport; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + throw Error('Unsupported scheme in URL: ' + url); +}; + +var negotiateDecoder = function negotiateDecoder(decoders, contentType) { + if (contentType === undefined || contentType === null) { + return decoders[0]; + } + + var fullType = contentType.toLowerCase().split(';')[0].trim(); + var mainType = fullType.split('/')[0] + '/*'; + var wildcardType = '*/*'; + var acceptableTypes = [fullType, mainType, wildcardType]; + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = decoders[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var decoder = _step2.value; + + if (acceptableTypes.includes(decoder.mediaType)) { + return decoder; + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + throw Error('Unsupported media in Content-Type header: ' + contentType); +}; + +var csrfSafeMethod = function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method) + ); +}; + +module.exports = { + determineTransport: determineTransport, + negotiateDecoder: negotiateDecoder, + csrfSafeMethod: csrfSafeMethod +}; + +},{"url-parse":19}],16:[function(require,module,exports){ +// the whatwg-fetch polyfill installs the fetch() function +// on the global object (window or self) +// +// Return that as the export for use in Webpack, Browserify etc. +require('whatwg-fetch'); +module.exports = self.fetch.bind(self); + +},{"whatwg-fetch":22}],17:[function(require,module,exports){ +'use strict'; + +var has = Object.prototype.hasOwnProperty; + +/** + * Simple query string parser. + * + * @param {String} query The query string that needs to be parsed. + * @returns {Object} + * @api public + */ +function querystring(query) { + var parser = /([^=?&]+)=?([^&]*)/g + , result = {} + , part; + + // + // Little nifty parsing hack, leverage the fact that RegExp.exec increments + // the lastIndex property so we can continue executing this loop until we've + // parsed all results. + // + for (; + part = parser.exec(query); + result[decodeURIComponent(part[1])] = decodeURIComponent(part[2]) + ); + + return result; +} + +/** + * Transform a query string to an object. + * + * @param {Object} obj Object that should be transformed. + * @param {String} prefix Optional prefix. + * @returns {String} + * @api public + */ +function querystringify(obj, prefix) { + prefix = prefix || ''; + + var pairs = []; + + // + // Optionally prefix with a '?' if needed + // + if ('string' !== typeof prefix) prefix = '?'; + + for (var key in obj) { + if (has.call(obj, key)) { + pairs.push(encodeURIComponent(key) +'='+ encodeURIComponent(obj[key])); + } + } + + return pairs.length ? prefix + pairs.join('&') : ''; +} + +// +// Expose the module. +// +exports.stringify = querystringify; +exports.parse = querystring; + +},{}],18:[function(require,module,exports){ +'use strict'; + +/** + * Check if we're required to add a port number. + * + * @see https://url.spec.whatwg.org/#default-port + * @param {Number|String} port Port number we need to check + * @param {String} protocol Protocol we need to check against. + * @returns {Boolean} Is it a default port for the given protocol + * @api private + */ +module.exports = function required(port, protocol) { + protocol = protocol.split(':')[0]; + port = +port; + + if (!port) return false; + + switch (protocol) { + case 'http': + case 'ws': + return port !== 80; + + case 'https': + case 'wss': + return port !== 443; + + case 'ftp': + return port !== 21; + + case 'gopher': + return port !== 70; + + case 'file': + return false; + } + + return port !== 0; +}; + +},{}],19:[function(require,module,exports){ +'use strict'; + +var required = require('requires-port') + , lolcation = require('./lolcation') + , qs = require('querystringify') + , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i; + +/** + * These are the parse rules for the URL parser, it informs the parser + * about: + * + * 0. The char it Needs to parse, if it's a string it should be done using + * indexOf, RegExp using exec and NaN means set as current value. + * 1. The property we should set when parsing this value. + * 2. Indication if it's backwards or forward parsing, when set as number it's + * the value of extra chars that should be split off. + * 3. Inherit from location if non existing in the parser. + * 4. `toLowerCase` the resulting value. + */ +var rules = [ + ['#', 'hash'], // Extract from the back. + ['?', 'query'], // Extract from the back. + ['/', 'pathname'], // Extract from the back. + ['@', 'auth', 1], // Extract from the front. + [NaN, 'host', undefined, 1, 1], // Set left over value. + [/:(\d+)$/, 'port', undefined, 1], // RegExp the back. + [NaN, 'hostname', undefined, 1, 1] // Set left over. +]; + +/** + * @typedef ProtocolExtract + * @type Object + * @property {String} protocol Protocol matched in the URL, in lowercase. + * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`. + * @property {String} rest Rest of the URL that is not part of the protocol. + */ + +/** + * Extract protocol information from a URL with/without double slash ("//"). + * + * @param {String} address URL we want to extract from. + * @return {ProtocolExtract} Extracted information. + * @api private + */ +function extractProtocol(address) { + var match = protocolre.exec(address); + + return { + protocol: match[1] ? match[1].toLowerCase() : '', + slashes: !!match[2], + rest: match[3] + }; +} + +/** + * Resolve a relative URL pathname against a base URL pathname. + * + * @param {String} relative Pathname of the relative URL. + * @param {String} base Pathname of the base URL. + * @return {String} Resolved pathname. + * @api private + */ +function resolve(relative, base) { + var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/')) + , i = path.length + , last = path[i - 1] + , unshift = false + , up = 0; + + while (i--) { + if (path[i] === '.') { + path.splice(i, 1); + } else if (path[i] === '..') { + path.splice(i, 1); + up++; + } else if (up) { + if (i === 0) unshift = true; + path.splice(i, 1); + up--; + } + } + + if (unshift) path.unshift(''); + if (last === '.' || last === '..') path.push(''); + + return path.join('/'); +} + +/** + * The actual URL instance. Instead of returning an object we've opted-in to + * create an actual constructor as it's much more memory efficient and + * faster and it pleases my OCD. + * + * @constructor + * @param {String} address URL we want to parse. + * @param {Object|String} location Location defaults for relative paths. + * @param {Boolean|Function} parser Parser for the query string. + * @api public + */ +function URL(address, location, parser) { + if (!(this instanceof URL)) { + return new URL(address, location, parser); + } + + var relative, extracted, parse, instruction, index, key + , instructions = rules.slice() + , type = typeof location + , url = this + , i = 0; + + // + // The following if statements allows this module two have compatibility with + // 2 different API: + // + // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments + // where the boolean indicates that the query string should also be parsed. + // + // 2. The `URL` interface of the browser which accepts a URL, object as + // arguments. The supplied object will be used as default values / fall-back + // for relative paths. + // + if ('object' !== type && 'string' !== type) { + parser = location; + location = null; + } + + if (parser && 'function' !== typeof parser) parser = qs.parse; + + location = lolcation(location); + + // + // Extract protocol information before running the instructions. + // + extracted = extractProtocol(address || ''); + relative = !extracted.protocol && !extracted.slashes; + url.slashes = extracted.slashes || relative && location.slashes; + url.protocol = extracted.protocol || location.protocol || ''; + address = extracted.rest; + + // + // When the authority component is absent the URL starts with a path + // component. + // + if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname']; + + for (; i < instructions.length; i++) { + instruction = instructions[i]; + parse = instruction[0]; + key = instruction[1]; + + if (parse !== parse) { + url[key] = address; + } else if ('string' === typeof parse) { + if (~(index = address.indexOf(parse))) { + if ('number' === typeof instruction[2]) { + url[key] = address.slice(0, index); + address = address.slice(index + instruction[2]); + } else { + url[key] = address.slice(index); + address = address.slice(0, index); + } + } + } else if (index = parse.exec(address)) { + url[key] = index[1]; + address = address.slice(0, index.index); + } + + url[key] = url[key] || ( + relative && instruction[3] ? location[key] || '' : '' + ); + + // + // Hostname, host and protocol should be lowercased so they can be used to + // create a proper `origin`. + // + if (instruction[4]) url[key] = url[key].toLowerCase(); + } + + // + // Also parse the supplied query string in to an object. If we're supplied + // with a custom parser as function use that instead of the default build-in + // parser. + // + if (parser) url.query = parser(url.query); + + // + // If the URL is relative, resolve the pathname against the base URL. + // + if ( + relative + && location.slashes + && url.pathname.charAt(0) !== '/' + && (url.pathname !== '' || location.pathname !== '') + ) { + url.pathname = resolve(url.pathname, location.pathname); + } + + // + // We should not add port numbers if they are already the default port number + // for a given protocol. As the host also contains the port number we're going + // override it with the hostname which contains no port number. + // + if (!required(url.port, url.protocol)) { + url.host = url.hostname; + url.port = ''; + } + + // + // Parse down the `auth` for the username and password. + // + url.username = url.password = ''; + if (url.auth) { + instruction = url.auth.split(':'); + url.username = instruction[0] || ''; + url.password = instruction[1] || ''; + } + + url.origin = url.protocol && url.host && url.protocol !== 'file:' + ? url.protocol +'//'+ url.host + : 'null'; + + // + // The href is just the compiled result. + // + url.href = url.toString(); +} + +/** + * This is convenience method for changing properties in the URL instance to + * insure that they all propagate correctly. + * + * @param {String} part Property we need to adjust. + * @param {Mixed} value The newly assigned value. + * @param {Boolean|Function} fn When setting the query, it will be the function + * used to parse the query. + * When setting the protocol, double slash will be + * removed from the final url if it is true. + * @returns {URL} + * @api public + */ +URL.prototype.set = function set(part, value, fn) { + var url = this; + + switch (part) { + case 'query': + if ('string' === typeof value && value.length) { + value = (fn || qs.parse)(value); + } + + url[part] = value; + break; + + case 'port': + url[part] = value; + + if (!required(value, url.protocol)) { + url.host = url.hostname; + url[part] = ''; + } else if (value) { + url.host = url.hostname +':'+ value; + } + + break; + + case 'hostname': + url[part] = value; + + if (url.port) value += ':'+ url.port; + url.host = value; + break; + + case 'host': + url[part] = value; + + if (/:\d+$/.test(value)) { + value = value.split(':'); + url.port = value.pop(); + url.hostname = value.join(':'); + } else { + url.hostname = value; + url.port = ''; + } + + break; + + case 'protocol': + url.protocol = value.toLowerCase(); + url.slashes = !fn; + break; + + case 'pathname': + url.pathname = value.length && value.charAt(0) !== '/' ? '/' + value : value; + + break; + + default: + url[part] = value; + } + + for (var i = 0; i < rules.length; i++) { + var ins = rules[i]; + + if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase(); + } + + url.origin = url.protocol && url.host && url.protocol !== 'file:' + ? url.protocol +'//'+ url.host + : 'null'; + + url.href = url.toString(); + + return url; +}; + +/** + * Transform the properties back in to a valid and full URL string. + * + * @param {Function} stringify Optional query stringify function. + * @returns {String} + * @api public + */ +URL.prototype.toString = function toString(stringify) { + if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify; + + var query + , url = this + , protocol = url.protocol; + + if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':'; + + var result = protocol + (url.slashes ? '//' : ''); + + if (url.username) { + result += url.username; + if (url.password) result += ':'+ url.password; + result += '@'; + } + + result += url.host + url.pathname; + + query = 'object' === typeof url.query ? stringify(url.query) : url.query; + if (query) result += '?' !== query.charAt(0) ? '?'+ query : query; + + if (url.hash) result += url.hash; + + return result; +}; + +// +// Expose the URL parser and some additional properties that might be useful for +// others or testing. +// +URL.extractProtocol = extractProtocol; +URL.location = lolcation; +URL.qs = qs; + +module.exports = URL; + +},{"./lolcation":20,"querystringify":17,"requires-port":18}],20:[function(require,module,exports){ +(function (global){ +'use strict'; + +var slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//; + +/** + * These properties should not be copied or inherited from. This is only needed + * for all non blob URL's as a blob URL does not include a hash, only the + * origin. + * + * @type {Object} + * @private + */ +var ignore = { hash: 1, query: 1 } + , URL; + +/** + * The location object differs when your code is loaded through a normal page, + * Worker or through a worker using a blob. And with the blobble begins the + * trouble as the location object will contain the URL of the blob, not the + * location of the page where our code is loaded in. The actual origin is + * encoded in the `pathname` so we can thankfully generate a good "default" + * location from it so we can generate proper relative URL's again. + * + * @param {Object|String} loc Optional default location object. + * @returns {Object} lolcation object. + * @api public + */ +module.exports = function lolcation(loc) { + loc = loc || global.location || {}; + URL = URL || require('./'); + + var finaldestination = {} + , type = typeof loc + , key; + + if ('blob:' === loc.protocol) { + finaldestination = new URL(unescape(loc.pathname), {}); + } else if ('string' === type) { + finaldestination = new URL(loc, {}); + for (key in ignore) delete finaldestination[key]; + } else if ('object' === type) { + for (key in loc) { + if (key in ignore) continue; + finaldestination[key] = loc[key]; + } + + if (finaldestination.slashes === undefined) { + finaldestination.slashes = slashes.test(loc.href); + } + } + + return finaldestination; +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./":19}],21:[function(require,module,exports){ +(function (root, factory) { + if (typeof exports === 'object') { + module.exports = factory(); + } else if (typeof define === 'function' && define.amd) { + define([], factory); + } else { + root.urltemplate = factory(); + } +}(this, function () { + /** + * @constructor + */ + function UrlTemplate() { + } + + /** + * @private + * @param {string} str + * @return {string} + */ + UrlTemplate.prototype.encodeReserved = function (str) { + return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { + if (!/%[0-9A-Fa-f]/.test(part)) { + part = encodeURI(part).replace(/%5B/g, '[').replace(/%5D/g, ']'); + } + return part; + }).join(''); + }; + + /** + * @private + * @param {string} str + * @return {string} + */ + UrlTemplate.prototype.encodeUnreserved = function (str) { + return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { + return '%' + c.charCodeAt(0).toString(16).toUpperCase(); + }); + } + + /** + * @private + * @param {string} operator + * @param {string} value + * @param {string} key + * @return {string} + */ + UrlTemplate.prototype.encodeValue = function (operator, value, key) { + value = (operator === '+' || operator === '#') ? this.encodeReserved(value) : this.encodeUnreserved(value); + + if (key) { + return this.encodeUnreserved(key) + '=' + value; + } else { + return value; + } + }; + + /** + * @private + * @param {*} value + * @return {boolean} + */ + UrlTemplate.prototype.isDefined = function (value) { + return value !== undefined && value !== null; + }; + + /** + * @private + * @param {string} + * @return {boolean} + */ + UrlTemplate.prototype.isKeyOperator = function (operator) { + return operator === ';' || operator === '&' || operator === '?'; + }; + + /** + * @private + * @param {Object} context + * @param {string} operator + * @param {string} key + * @param {string} modifier + */ + UrlTemplate.prototype.getValues = function (context, operator, key, modifier) { + var value = context[key], + result = []; + + if (this.isDefined(value) && value !== '') { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + value = value.toString(); + + if (modifier && modifier !== '*') { + value = value.substring(0, parseInt(modifier, 10)); + } + + result.push(this.encodeValue(operator, value, this.isKeyOperator(operator) ? key : null)); + } else { + if (modifier === '*') { + if (Array.isArray(value)) { + value.filter(this.isDefined).forEach(function (value) { + result.push(this.encodeValue(operator, value, this.isKeyOperator(operator) ? key : null)); + }, this); + } else { + Object.keys(value).forEach(function (k) { + if (this.isDefined(value[k])) { + result.push(this.encodeValue(operator, value[k], k)); + } + }, this); + } + } else { + var tmp = []; + + if (Array.isArray(value)) { + value.filter(this.isDefined).forEach(function (value) { + tmp.push(this.encodeValue(operator, value)); + }, this); + } else { + Object.keys(value).forEach(function (k) { + if (this.isDefined(value[k])) { + tmp.push(this.encodeUnreserved(k)); + tmp.push(this.encodeValue(operator, value[k].toString())); + } + }, this); + } + + if (this.isKeyOperator(operator)) { + result.push(this.encodeUnreserved(key) + '=' + tmp.join(',')); + } else if (tmp.length !== 0) { + result.push(tmp.join(',')); + } + } + } + } else { + if (operator === ';') { + if (this.isDefined(value)) { + result.push(this.encodeUnreserved(key)); + } + } else if (value === '' && (operator === '&' || operator === '?')) { + result.push(this.encodeUnreserved(key) + '='); + } else if (value === '') { + result.push(''); + } + } + return result; + }; + + /** + * @param {string} template + * @return {function(Object):string} + */ + UrlTemplate.prototype.parse = function (template) { + var that = this; + var operators = ['+', '#', '.', '/', ';', '?', '&']; + + return { + expand: function (context) { + return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) { + if (expression) { + var operator = null, + values = []; + + if (operators.indexOf(expression.charAt(0)) !== -1) { + operator = expression.charAt(0); + expression = expression.substr(1); + } + + expression.split(/,/g).forEach(function (variable) { + var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); + values.push.apply(values, that.getValues(context, operator, tmp[1], tmp[2] || tmp[3])); + }); + + if (operator && operator !== '+') { + var separator = ','; + + if (operator === '?') { + separator = '&'; + } else if (operator !== '#') { + separator = operator; + } + return (values.length !== 0 ? operator : '') + values.join(separator); + } else { + return values.join(','); + } + } else { + return that.encodeReserved(literal); + } + }); + } + }; + }; + + return new UrlTemplate(); +})); + +},{}],22:[function(require,module,exports){ +(function(self) { + 'use strict'; + + if (self.fetch) { + return + } + + var support = { + searchParams: 'URLSearchParams' in self, + iterable: 'Symbol' in self && 'iterator' in Symbol, + blob: 'FileReader' in self && 'Blob' in self && (function() { + try { + new Blob() + return true + } catch(e) { + return false + } + })(), + formData: 'FormData' in self, + arrayBuffer: 'ArrayBuffer' in self + } + + if (support.arrayBuffer) { + var viewClasses = [ + '[object Int8Array]', + '[object Uint8Array]', + '[object Uint8ClampedArray]', + '[object Int16Array]', + '[object Uint16Array]', + '[object Int32Array]', + '[object Uint32Array]', + '[object Float32Array]', + '[object Float64Array]' + ] + + var isDataView = function(obj) { + return obj && DataView.prototype.isPrototypeOf(obj) + } + + var isArrayBufferView = ArrayBuffer.isView || function(obj) { + return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 + } + } + + function normalizeName(name) { + if (typeof name !== 'string') { + name = String(name) + } + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name') + } + return name.toLowerCase() + } + + function normalizeValue(value) { + if (typeof value !== 'string') { + value = String(value) + } + return value + } + + // Build a destructive iterator for the value list + function iteratorFor(items) { + var iterator = { + next: function() { + var value = items.shift() + return {done: value === undefined, value: value} + } + } + + if (support.iterable) { + iterator[Symbol.iterator] = function() { + return iterator + } + } + + return iterator + } + + function Headers(headers) { + this.map = {} + + if (headers instanceof Headers) { + headers.forEach(function(value, name) { + this.append(name, value) + }, this) + + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]) + }, this) + } + } + + Headers.prototype.append = function(name, value) { + name = normalizeName(name) + value = normalizeValue(value) + var oldValue = this.map[name] + this.map[name] = oldValue ? oldValue+','+value : value + } + + Headers.prototype['delete'] = function(name) { + delete this.map[normalizeName(name)] + } + + Headers.prototype.get = function(name) { + name = normalizeName(name) + return this.has(name) ? this.map[name] : null + } + + Headers.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)) + } + + Headers.prototype.set = function(name, value) { + this.map[normalizeName(name)] = normalizeValue(value) + } + + Headers.prototype.forEach = function(callback, thisArg) { + for (var name in this.map) { + if (this.map.hasOwnProperty(name)) { + callback.call(thisArg, this.map[name], name, this) + } + } + } + + Headers.prototype.keys = function() { + var items = [] + this.forEach(function(value, name) { items.push(name) }) + return iteratorFor(items) + } + + Headers.prototype.values = function() { + var items = [] + this.forEach(function(value) { items.push(value) }) + return iteratorFor(items) + } + + Headers.prototype.entries = function() { + var items = [] + this.forEach(function(value, name) { items.push([name, value]) }) + return iteratorFor(items) + } + + if (support.iterable) { + Headers.prototype[Symbol.iterator] = Headers.prototype.entries + } + + function consumed(body) { + if (body.bodyUsed) { + return Promise.reject(new TypeError('Already read')) + } + body.bodyUsed = true + } + + function fileReaderReady(reader) { + return new Promise(function(resolve, reject) { + reader.onload = function() { + resolve(reader.result) + } + reader.onerror = function() { + reject(reader.error) + } + }) + } + + function readBlobAsArrayBuffer(blob) { + var reader = new FileReader() + var promise = fileReaderReady(reader) + reader.readAsArrayBuffer(blob) + return promise + } + + function readBlobAsText(blob) { + var reader = new FileReader() + var promise = fileReaderReady(reader) + reader.readAsText(blob) + return promise + } + + function bufferClone(buf) { + if (buf.slice) { + return buf.slice(0) + } else { + var view = new Uint8Array(buf.byteLength) + view.set(new Uint8Array(buf)) + return view.buffer + } + } + + function Body() { + this.bodyUsed = false + + this._initBody = function(body) { + this._bodyInit = body + if (!body) { + this._bodyText = '' + } else if (typeof body === 'string') { + this._bodyText = body + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this._bodyText = body.toString() + } else if (support.arrayBuffer && support.blob && isDataView(body)) { + this._bodyArrayBuffer = bufferClone(body.buffer) + // IE 10-11 can't handle a DataView body. + this._bodyInit = new Blob([this._bodyArrayBuffer]) + } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { + this._bodyArrayBuffer = bufferClone(body) + } else { + throw new Error('unsupported BodyInit type') + } + + if (!this.headers.get('content-type')) { + if (typeof body === 'string') { + this.headers.set('content-type', 'text/plain;charset=UTF-8') + } else if (this._bodyBlob && this._bodyBlob.type) { + this.headers.set('content-type', this._bodyBlob.type) + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8') + } + } + } + + if (support.blob) { + this.blob = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob) + } else if (this._bodyArrayBuffer) { + return Promise.resolve(new Blob([this._bodyArrayBuffer])) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as blob') + } else { + return Promise.resolve(new Blob([this._bodyText])) + } + } + } + + this.text = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob) + } else if (this._bodyArrayBuffer) { + var view = new Uint8Array(this._bodyArrayBuffer) + var str = String.fromCharCode.apply(null, view) + return Promise.resolve(str) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as text') + } else { + return Promise.resolve(this._bodyText) + } + } + + if (support.arrayBuffer) { + this.arrayBuffer = function() { + if (this._bodyArrayBuffer) { + return consumed(this) || Promise.resolve(this._bodyArrayBuffer) + } else { + return this.blob().then(readBlobAsArrayBuffer) + } + } + } + + if (support.formData) { + this.formData = function() { + return this.text().then(decode) + } + } + + this.json = function() { + return this.text().then(JSON.parse) + } + + return this + } + + // HTTP methods whose capitalization should be normalized + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + + function normalizeMethod(method) { + var upcased = method.toUpperCase() + return (methods.indexOf(upcased) > -1) ? upcased : method + } + + function Request(input, options) { + options = options || {} + var body = options.body + + if (typeof input === 'string') { + this.url = input + } else { + if (input.bodyUsed) { + throw new TypeError('Already read') + } + this.url = input.url + this.credentials = input.credentials + if (!options.headers) { + this.headers = new Headers(input.headers) + } + this.method = input.method + this.mode = input.mode + if (!body && input._bodyInit != null) { + body = input._bodyInit + input.bodyUsed = true + } + } + + this.credentials = options.credentials || this.credentials || 'omit' + if (options.headers || !this.headers) { + this.headers = new Headers(options.headers) + } + this.method = normalizeMethod(options.method || this.method || 'GET') + this.mode = options.mode || this.mode || null + this.referrer = null + + if ((this.method === 'GET' || this.method === 'HEAD') && body) { + throw new TypeError('Body not allowed for GET or HEAD requests') + } + this._initBody(body) + } + + Request.prototype.clone = function() { + return new Request(this, { body: this._bodyInit }) + } + + function decode(body) { + var form = new FormData() + body.trim().split('&').forEach(function(bytes) { + if (bytes) { + var split = bytes.split('=') + var name = split.shift().replace(/\+/g, ' ') + var value = split.join('=').replace(/\+/g, ' ') + form.append(decodeURIComponent(name), decodeURIComponent(value)) + } + }) + return form + } + + function parseHeaders(rawHeaders) { + var headers = new Headers() + rawHeaders.split('\r\n').forEach(function(line) { + var parts = line.split(':') + var key = parts.shift().trim() + if (key) { + var value = parts.join(':').trim() + headers.append(key, value) + } + }) + return headers + } + + Body.call(Request.prototype) + + function Response(bodyInit, options) { + if (!options) { + options = {} + } + + this.type = 'default' + this.status = 'status' in options ? options.status : 200 + this.ok = this.status >= 200 && this.status < 300 + this.statusText = 'statusText' in options ? options.statusText : 'OK' + this.headers = new Headers(options.headers) + this.url = options.url || '' + this._initBody(bodyInit) + } + + Body.call(Response.prototype) + + Response.prototype.clone = function() { + return new Response(this._bodyInit, { + status: this.status, + statusText: this.statusText, + headers: new Headers(this.headers), + url: this.url + }) + } + + Response.error = function() { + var response = new Response(null, {status: 0, statusText: ''}) + response.type = 'error' + return response + } + + var redirectStatuses = [301, 302, 303, 307, 308] + + Response.redirect = function(url, status) { + if (redirectStatuses.indexOf(status) === -1) { + throw new RangeError('Invalid status code') + } + + return new Response(null, {status: status, headers: {location: url}}) + } + + self.Headers = Headers + self.Request = Request + self.Response = Response + + self.fetch = function(input, init) { + return new Promise(function(resolve, reject) { + var request = new Request(input, init) + var xhr = new XMLHttpRequest() + + xhr.onload = function() { + var options = { + status: xhr.status, + statusText: xhr.statusText, + headers: parseHeaders(xhr.getAllResponseHeaders() || '') + } + options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL') + var body = 'response' in xhr ? xhr.response : xhr.responseText + resolve(new Response(body, options)) + } + + xhr.onerror = function() { + reject(new TypeError('Network request failed')) + } + + xhr.ontimeout = function() { + reject(new TypeError('Network request failed')) + } + + xhr.open(request.method, request.url, true) + + if (request.credentials === 'include') { + xhr.withCredentials = true + } + + if ('responseType' in xhr && support.blob) { + xhr.responseType = 'blob' + } + + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value) + }) + + xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) + }) + } + self.fetch.polyfill = true +})(typeof self !== 'undefined' ? self : this); + +},{}]},{},[12])(12) +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvYXV0aC9iYXNpYy5qcyIsImxpYi9hdXRoL2luZGV4LmpzIiwibGliL2F1dGgvc2Vzc2lvbi5qcyIsImxpYi9hdXRoL3Rva2VuLmpzIiwibGliL2NsaWVudC5qcyIsImxpYi9jb2RlY3MvY29yZWpzb24uanMiLCJsaWIvY29kZWNzL2luZGV4LmpzIiwibGliL2NvZGVjcy9qc29uLmpzIiwibGliL2NvZGVjcy90ZXh0LmpzIiwibGliL2RvY3VtZW50LmpzIiwibGliL2Vycm9ycy5qcyIsImxpYi9pbmRleC5qcyIsImxpYi90cmFuc3BvcnRzL2h0dHAuanMiLCJsaWIvdHJhbnNwb3J0cy9pbmRleC5qcyIsImxpYi91dGlscy5qcyIsIm5vZGVfbW9kdWxlcy9pc29tb3JwaGljLWZldGNoL2ZldGNoLW5wbS1icm93c2VyaWZ5LmpzIiwibm9kZV9tb2R1bGVzL3F1ZXJ5c3RyaW5naWZ5L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlcXVpcmVzLXBvcnQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvdXJsLXBhcnNlL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3VybC1wYXJzZS9sb2xjYXRpb24uanMiLCJub2RlX21vZHVsZXMvdXJsLXRlbXBsYXRlL2xpYi91cmwtdGVtcGxhdGUuanMiLCJub2RlX21vZHVsZXMvd2hhdHdnLWZldGNoL2ZldGNoLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0lDQU0sbUI7QUFDSixpQ0FBMkI7QUFBQSxRQUFkLE9BQWMsdUVBQUosRUFBSTs7QUFBQTs7QUFDekIsUUFBTSxXQUFXLFFBQVEsUUFBekI7QUFDQSxRQUFNLFdBQVcsUUFBUSxRQUF6QjtBQUNBLFFBQU0sT0FBTyxPQUFPLElBQVAsQ0FBWSxXQUFXLEdBQVgsR0FBaUIsUUFBN0IsQ0FBYjtBQUNBLFNBQUssSUFBTCxHQUFZLFdBQVcsSUFBdkI7QUFDRDs7OztpQ0FFYSxPLEVBQVM7QUFDckIsY0FBUSxPQUFSLENBQWdCLGVBQWhCLElBQW1DLEtBQUssSUFBeEM7QUFDQSxhQUFPLE9BQVA7QUFDRDs7Ozs7O0FBR0gsT0FBTyxPQUFQLEdBQWlCO0FBQ2YsdUJBQXFCO0FBRE4sQ0FBakI7Ozs7O0FDZEEsSUFBTSxRQUFRLFFBQVEsU0FBUixDQUFkO0FBQ0EsSUFBTSxVQUFVLFFBQVEsV0FBUixDQUFoQjtBQUNBLElBQU0sUUFBUSxRQUFRLFNBQVIsQ0FBZDs7QUFFQSxPQUFPLE9BQVAsR0FBaUI7QUFDZix1QkFBcUIsTUFBTSxtQkFEWjtBQUVmLHlCQUF1QixRQUFRLHFCQUZoQjtBQUdmLHVCQUFxQixNQUFNO0FBSFosQ0FBakI7Ozs7Ozs7OztBQ0pBLElBQU0sUUFBUSxRQUFRLFVBQVIsQ0FBZDs7QUFFQSxTQUFTLElBQVQsQ0FBZSxHQUFmLEVBQW9CO0FBQ2xCLFNBQU8sSUFBSSxPQUFKLENBQVksUUFBWixFQUFzQixFQUF0QixFQUEwQixPQUExQixDQUFrQyxRQUFsQyxFQUE0QyxFQUE1QyxDQUFQO0FBQ0Q7O0FBRUQsU0FBUyxTQUFULENBQW9CLFVBQXBCLEVBQWdDLFlBQWhDLEVBQThDO0FBQzVDLGlCQUFlLGdCQUFnQixPQUFPLFFBQVAsQ0FBZ0IsTUFBL0M7QUFDQSxNQUFJLGdCQUFnQixpQkFBaUIsRUFBckMsRUFBeUM7QUFDdkMsUUFBTSxVQUFVLGFBQWEsS0FBYixDQUFtQixHQUFuQixDQUFoQjtBQUNBLFNBQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxRQUFRLE1BQTVCLEVBQW9DLEdBQXBDLEVBQXlDO0FBQ3ZDLFVBQU0sU0FBUyxLQUFLLFFBQVEsQ0FBUixDQUFMLENBQWY7QUFDQTtBQUNBLFVBQUksT0FBTyxTQUFQLENBQWlCLENBQWpCLEVBQW9CLFdBQVcsTUFBWCxHQUFvQixDQUF4QyxNQUFnRCxhQUFhLEdBQWpFLEVBQXVFO0FBQ3JFLGVBQU8sbUJBQW1CLE9BQU8sU0FBUCxDQUFpQixXQUFXLE1BQVgsR0FBb0IsQ0FBckMsQ0FBbkIsQ0FBUDtBQUNEO0FBQ0Y7QUFDRjtBQUNELFNBQU8sSUFBUDtBQUNEOztJQUVLLHFCO0FBQ0osbUNBQTJCO0FBQUEsUUFBZCxPQUFjLHVFQUFKLEVBQUk7O0FBQUE7O0FBQ3pCLFNBQUssU0FBTCxHQUFpQixVQUFVLFFBQVEsY0FBbEIsRUFBa0MsUUFBUSxZQUExQyxDQUFqQjtBQUNBLFNBQUssY0FBTCxHQUFzQixRQUFRLGNBQTlCO0FBQ0Q7Ozs7aUNBRWEsTyxFQUFTO0FBQ3JCLGNBQVEsV0FBUixHQUFzQixhQUF0QjtBQUNBLFVBQUksS0FBSyxTQUFMLElBQWtCLENBQUMsTUFBTSxjQUFOLENBQXFCLFFBQVEsTUFBN0IsQ0FBdkIsRUFBNkQ7QUFDM0QsZ0JBQVEsT0FBUixDQUFnQixLQUFLLGNBQXJCLElBQXVDLEtBQUssU0FBNUM7QUFDRDtBQUNELGFBQU8sT0FBUDtBQUNEOzs7Ozs7QUFHSCxPQUFPLE9BQVAsR0FBaUI7QUFDZix5QkFBdUI7QUFEUixDQUFqQjs7Ozs7Ozs7O0lDcENNLG1CO0FBQ0osaUNBQTJCO0FBQUEsUUFBZCxPQUFjLHVFQUFKLEVBQUk7O0FBQUE7O0FBQ3pCLFNBQUssS0FBTCxHQUFhLFFBQVEsS0FBckI7QUFDQSxTQUFLLE1BQUwsR0FBYyxRQUFRLE1BQVIsSUFBa0IsUUFBaEM7QUFDRDs7OztpQ0FFYSxPLEVBQVM7QUFDckIsY0FBUSxPQUFSLENBQWdCLGVBQWhCLElBQW1DLEtBQUssTUFBTCxHQUFjLEdBQWQsR0FBb0IsS0FBSyxLQUE1RDtBQUNBLGFBQU8sT0FBUDtBQUNEOzs7Ozs7QUFHSCxPQUFPLE9BQVAsR0FBaUI7QUFDZix1QkFBcUI7QUFETixDQUFqQjs7Ozs7Ozs7O0FDWkEsSUFBTSxXQUFXLFFBQVEsWUFBUixDQUFqQjtBQUNBLElBQU0sU0FBUyxRQUFRLFVBQVIsQ0FBZjtBQUNBLElBQU0sU0FBUyxRQUFRLFVBQVIsQ0FBZjtBQUNBLElBQU0sYUFBYSxRQUFRLGNBQVIsQ0FBbkI7QUFDQSxJQUFNLFFBQVEsUUFBUSxTQUFSLENBQWQ7O0FBRUEsU0FBUyxVQUFULENBQXFCLElBQXJCLEVBQTJCLElBQTNCLEVBQWlDO0FBQUE7QUFBQTtBQUFBOztBQUFBO0FBQy9CLHlCQUFnQixJQUFoQiw4SEFBc0I7QUFBQSxVQUFiLEdBQWE7O0FBQ3BCLFVBQUksZ0JBQWdCLFNBQVMsUUFBN0IsRUFBdUM7QUFDckMsZUFBTyxLQUFLLE9BQUwsQ0FBYSxHQUFiLENBQVA7QUFDRCxPQUZELE1BRU87QUFDTCxlQUFPLEtBQUssR0FBTCxDQUFQO0FBQ0Q7QUFDRCxVQUFJLFNBQVMsU0FBYixFQUF3QjtBQUN0QixjQUFNLElBQUksT0FBTyxlQUFYLDJCQUFtRCxLQUFLLFNBQUwsQ0FBZSxJQUFmLENBQW5ELENBQU47QUFDRDtBQUNGO0FBVjhCO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7O0FBVy9CLE1BQUksRUFBRSxnQkFBZ0IsU0FBUyxJQUEzQixDQUFKLEVBQXNDO0FBQ3BDLFVBQU0sSUFBSSxPQUFPLGVBQVgsMkJBQW1ELEtBQUssU0FBTCxDQUFlLElBQWYsQ0FBbkQsQ0FBTjtBQUNEO0FBQ0QsU0FBTyxJQUFQO0FBQ0Q7O0lBRUssTTtBQUNKLG9CQUEyQjtBQUFBLFFBQWQsT0FBYyx1RUFBSixFQUFJOztBQUFBOztBQUN6QixRQUFNLG1CQUFtQjtBQUN2QixZQUFNLFFBQVEsSUFBUixJQUFnQixJQURDO0FBRXZCLGVBQVMsUUFBUSxPQUFSLElBQW1CLEVBRkw7QUFHdkIsdUJBQWlCLFFBQVEsZUFIRjtBQUl2Qix3QkFBa0IsUUFBUTtBQUpILEtBQXpCOztBQU9BLFNBQUssUUFBTCxHQUFnQixRQUFRLFFBQVIsSUFBb0IsQ0FBQyxJQUFJLE9BQU8sYUFBWCxFQUFELEVBQTZCLElBQUksT0FBTyxTQUFYLEVBQTdCLEVBQXFELElBQUksT0FBTyxTQUFYLEVBQXJELENBQXBDO0FBQ0EsU0FBSyxVQUFMLEdBQWtCLFFBQVEsVUFBUixJQUFzQixDQUFDLElBQUksV0FBVyxhQUFmLENBQTZCLGdCQUE3QixDQUFELENBQXhDO0FBQ0Q7Ozs7MkJBRU8sUSxFQUFVLEksRUFBbUI7QUFBQSxVQUFiLE1BQWEsdUVBQUosRUFBSTs7QUFDbkMsVUFBTSxPQUFPLFdBQVcsUUFBWCxFQUFxQixJQUFyQixDQUFiO0FBQ0EsVUFBTSxZQUFZLE1BQU0sa0JBQU4sQ0FBeUIsS0FBSyxVQUE5QixFQUEwQyxLQUFLLEdBQS9DLENBQWxCO0FBQ0EsYUFBTyxVQUFVLE1BQVYsQ0FBaUIsSUFBakIsRUFBdUIsS0FBSyxRQUE1QixFQUFzQyxNQUF0QyxDQUFQO0FBQ0Q7Ozt3QkFFSSxHLEVBQUs7QUFDUixVQUFNLE9BQU8sSUFBSSxTQUFTLElBQWIsQ0FBa0IsR0FBbEIsRUFBdUIsS0FBdkIsQ0FBYjtBQUNBLFVBQU0sWUFBWSxNQUFNLGtCQUFOLENBQXlCLEtBQUssVUFBOUIsRUFBMEMsR0FBMUMsQ0FBbEI7QUFDQSxhQUFPLFVBQVUsTUFBVixDQUFpQixJQUFqQixFQUF1QixLQUFLLFFBQTVCLENBQVA7QUFDRDs7Ozs7O0FBR0gsT0FBTyxPQUFQLEdBQWlCO0FBQ2YsVUFBUTtBQURPLENBQWpCOzs7Ozs7Ozs7OztBQ2pEQSxJQUFNLFdBQVcsUUFBUSxhQUFSLENBQWpCO0FBQ0EsSUFBTSxNQUFNLFFBQVEsV0FBUixDQUFaOztBQUVBLFNBQVMsV0FBVCxDQUFzQixHQUF0QixFQUEyQjtBQUN6QixNQUFJLElBQUksS0FBSixDQUFVLGdCQUFWLENBQUosRUFBaUM7QUFDL0IsV0FBTyxJQUFJLFNBQUosQ0FBYyxDQUFkLENBQVA7QUFDRDtBQUNELFNBQU8sR0FBUDtBQUNEOztBQUVELFNBQVMsU0FBVCxDQUFvQixHQUFwQixFQUF5QixHQUF6QixFQUE4QjtBQUM1QixNQUFNLFFBQVEsSUFBSSxHQUFKLENBQWQ7QUFDQSxNQUFJLE9BQVEsS0FBUixLQUFtQixRQUF2QixFQUFpQztBQUMvQixXQUFPLEtBQVA7QUFDRDtBQUNELFNBQU8sRUFBUDtBQUNEOztBQUVELFNBQVMsVUFBVCxDQUFxQixHQUFyQixFQUEwQixHQUExQixFQUErQjtBQUM3QixNQUFNLFFBQVEsSUFBSSxHQUFKLENBQWQ7QUFDQSxNQUFJLE9BQVEsS0FBUixLQUFtQixTQUF2QixFQUFrQztBQUNoQyxXQUFPLEtBQVA7QUFDRDtBQUNELFNBQU8sS0FBUDtBQUNEOztBQUVELFNBQVMsU0FBVCxDQUFvQixHQUFwQixFQUF5QixHQUF6QixFQUE4QjtBQUM1QixNQUFNLFFBQVEsSUFBSSxHQUFKLENBQWQ7QUFDQSxNQUFJLFFBQVEsS0FBUix5Q0FBUSxLQUFSLE9BQW1CLFFBQXZCLEVBQWlDO0FBQy9CLFdBQU8sS0FBUDtBQUNEO0FBQ0QsU0FBTyxFQUFQO0FBQ0Q7O0FBRUQsU0FBUyxRQUFULENBQW1CLEdBQW5CLEVBQXdCLEdBQXhCLEVBQTZCO0FBQzNCLE1BQU0sUUFBUSxJQUFJLEdBQUosQ0FBZDtBQUNBLE1BQUksaUJBQWlCLEtBQXJCLEVBQTRCO0FBQzFCLFdBQU8sS0FBUDtBQUNEO0FBQ0QsU0FBTyxFQUFQO0FBQ0Q7O0FBRUQsU0FBUyxVQUFULENBQXFCLElBQXJCLEVBQTJCLE9BQTNCLEVBQW9DO0FBQ2xDLE1BQU0sV0FBVyxDQUFDLE9BQUQsRUFBVSxPQUFWLENBQWpCO0FBQ0EsTUFBSSxVQUFVLEVBQWQ7QUFDQSxPQUFLLElBQUksUUFBVCxJQUFxQixJQUFyQixFQUEyQjtBQUN6QixRQUFJLEtBQUssY0FBTCxDQUFvQixRQUFwQixLQUFpQyxDQUFDLFNBQVMsUUFBVCxDQUFrQixRQUFsQixDQUF0QyxFQUFtRTtBQUNqRSxVQUFNLE1BQU0sWUFBWSxRQUFaLENBQVo7QUFDQSxVQUFNLFFBQVEsZ0JBQWdCLEtBQUssUUFBTCxDQUFoQixFQUFnQyxPQUFoQyxDQUFkO0FBQ0EsY0FBUSxHQUFSLElBQWUsS0FBZjtBQUNEO0FBQ0Y7QUFDRCxTQUFPLE9BQVA7QUFDRDs7QUFFRCxTQUFTLGVBQVQsQ0FBMEIsSUFBMUIsRUFBZ0MsT0FBaEMsRUFBeUM7QUFDdkMsTUFBTSxXQUFXLGdCQUFnQixNQUFoQixJQUEwQixFQUFFLGdCQUFnQixLQUFsQixDQUEzQzs7QUFFQSxNQUFJLFlBQVksS0FBSyxLQUFMLEtBQWUsVUFBL0IsRUFBMkM7QUFDekM7QUFDQSxRQUFNLE9BQU8sVUFBVSxJQUFWLEVBQWdCLE9BQWhCLENBQWI7QUFDQSxRQUFNLGNBQWMsVUFBVSxJQUFWLEVBQWdCLEtBQWhCLENBQXBCO0FBQ0EsUUFBTSxNQUFNLGNBQWMsSUFBSSxXQUFKLEVBQWlCLE9BQWpCLEVBQTBCLFFBQTFCLEVBQWQsR0FBcUQsRUFBakU7QUFDQSxRQUFNLFFBQVEsVUFBVSxJQUFWLEVBQWdCLE9BQWhCLENBQWQ7QUFDQSxRQUFNLGNBQWMsVUFBVSxJQUFWLEVBQWdCLGFBQWhCLENBQXBCO0FBQ0EsUUFBTSxVQUFVLFdBQVcsSUFBWCxFQUFpQixHQUFqQixDQUFoQjtBQUNBLFdBQU8sSUFBSSxTQUFTLFFBQWIsQ0FBc0IsR0FBdEIsRUFBMkIsS0FBM0IsRUFBa0MsV0FBbEMsRUFBK0MsT0FBL0MsQ0FBUDtBQUNELEdBVEQsTUFTTyxJQUFJLFlBQVksS0FBSyxLQUFMLEtBQWUsTUFBL0IsRUFBdUM7QUFDNUM7QUFDQSxRQUFNLGVBQWMsVUFBVSxJQUFWLEVBQWdCLEtBQWhCLENBQXBCO0FBQ0EsUUFBTSxPQUFNLGVBQWMsSUFBSSxZQUFKLEVBQWlCLE9BQWpCLEVBQTBCLFFBQTFCLEVBQWQsR0FBcUQsRUFBakU7QUFDQSxRQUFNLFNBQVMsVUFBVSxJQUFWLEVBQWdCLFFBQWhCLEtBQTZCLEtBQTVDO0FBQ0EsUUFBTSxTQUFRLFVBQVUsSUFBVixFQUFnQixPQUFoQixDQUFkO0FBQ0EsUUFBTSxlQUFjLFVBQVUsSUFBVixFQUFnQixhQUFoQixDQUFwQjtBQUNBLFFBQU0sYUFBYSxTQUFTLElBQVQsRUFBZSxRQUFmLENBQW5CO0FBQ0EsUUFBSSxTQUFTLEVBQWI7QUFDQSxTQUFLLElBQUksTUFBTSxDQUFWLEVBQWEsTUFBTSxXQUFXLE1BQW5DLEVBQTJDLE1BQU0sR0FBakQsRUFBc0QsS0FBdEQsRUFBNkQ7QUFDM0QsVUFBSSxRQUFRLFdBQVcsR0FBWCxDQUFaO0FBQ0EsVUFBSSxPQUFPLFVBQVUsS0FBVixFQUFpQixNQUFqQixDQUFYO0FBQ0EsVUFBSSxXQUFXLFdBQVcsS0FBWCxFQUFrQixVQUFsQixDQUFmO0FBQ0EsVUFBSSxXQUFXLFVBQVUsS0FBVixFQUFpQixVQUFqQixDQUFmO0FBQ0EsVUFBSSxtQkFBbUIsVUFBVSxLQUFWLEVBQWlCLGtCQUFqQixDQUF2QjtBQUNBLFVBQUksUUFBUSxJQUFJLFNBQVMsS0FBYixDQUFtQixJQUFuQixFQUF5QixRQUF6QixFQUFtQyxRQUFuQyxFQUE2QyxnQkFBN0MsQ0FBWjtBQUNBLGFBQU8sSUFBUCxDQUFZLEtBQVo7QUFDRDtBQUNELFdBQU8sSUFBSSxTQUFTLElBQWIsQ0FBa0IsSUFBbEIsRUFBdUIsTUFBdkIsRUFBK0Isa0JBQS9CLEVBQW1ELE1BQW5ELEVBQTJELE1BQTNELEVBQWtFLFlBQWxFLENBQVA7QUFDRCxHQW5CTSxNQW1CQSxJQUFJLFFBQUosRUFBYztBQUNuQjtBQUNBLFFBQUksV0FBVSxFQUFkO0FBQ0EsU0FBSyxJQUFJLEdBQVQsSUFBZ0IsSUFBaEIsRUFBc0I7QUFDcEIsVUFBSSxLQUFLLGNBQUwsQ0FBb0IsR0FBcEIsQ0FBSixFQUE4QjtBQUM1QixpQkFBUSxHQUFSLElBQWUsZ0JBQWdCLEtBQUssR0FBTCxDQUFoQixFQUEyQixPQUEzQixDQUFmO0FBQ0Q7QUFDRjtBQUNELFdBQU8sUUFBUDtBQUNELEdBVE0sTUFTQSxJQUFJLGdCQUFnQixLQUFwQixFQUEyQjtBQUNoQztBQUNBLFFBQUksWUFBVSxFQUFkO0FBQ0EsU0FBSyxJQUFJLE9BQU0sQ0FBVixFQUFhLE9BQU0sS0FBSyxNQUE3QixFQUFxQyxPQUFNLElBQTNDLEVBQWdELE1BQWhELEVBQXVEO0FBQ3JELGdCQUFRLElBQVIsQ0FBYSxnQkFBZ0IsS0FBSyxJQUFMLENBQWhCLEVBQTJCLE9BQTNCLENBQWI7QUFDRDtBQUNELFdBQU8sU0FBUDtBQUNEO0FBQ0Q7QUFDQSxTQUFPLElBQVA7QUFDRDs7SUFFSyxhO0FBQ0osMkJBQWU7QUFBQTs7QUFDYixTQUFLLFNBQUwsR0FBaUIsMEJBQWpCO0FBQ0Q7Ozs7MkJBRU8sSSxFQUFvQjtBQUFBLFVBQWQsT0FBYyx1RUFBSixFQUFJOztBQUMxQixVQUFJLE9BQU8sSUFBWDtBQUNBLFVBQUksUUFBUSxTQUFSLEtBQXNCLFNBQXRCLElBQW1DLENBQUMsUUFBUSxTQUFoRCxFQUEyRDtBQUN6RCxlQUFPLEtBQUssS0FBTCxDQUFXLElBQVgsQ0FBUDtBQUNEO0FBQ0QsYUFBTyxnQkFBZ0IsSUFBaEIsRUFBc0IsUUFBUSxHQUE5QixDQUFQO0FBQ0Q7Ozs7OztBQUdILE9BQU8sT0FBUCxHQUFpQjtBQUNmLGlCQUFlO0FBREEsQ0FBakI7Ozs7O0FDekhBLElBQU0sV0FBVyxRQUFRLFlBQVIsQ0FBakI7QUFDQSxJQUFNLE9BQU8sUUFBUSxRQUFSLENBQWI7QUFDQSxJQUFNLE9BQU8sUUFBUSxRQUFSLENBQWI7O0FBRUEsT0FBTyxPQUFQLEdBQWlCO0FBQ2YsaUJBQWUsU0FBUyxhQURUO0FBRWYsYUFBVyxLQUFLLFNBRkQ7QUFHZixhQUFXLEtBQUs7QUFIRCxDQUFqQjs7Ozs7Ozs7O0lDSk0sUztBQUNKLHVCQUFlO0FBQUE7O0FBQ2IsU0FBSyxTQUFMLEdBQWlCLGtCQUFqQjtBQUNEOzs7OzJCQUVPLEksRUFBb0I7QUFBQSxVQUFkLE9BQWMsdUVBQUosRUFBSTs7QUFDMUIsYUFBTyxLQUFLLEtBQUwsQ0FBVyxJQUFYLENBQVA7QUFDRDs7Ozs7O0FBR0gsT0FBTyxPQUFQLEdBQWlCO0FBQ2YsYUFBVztBQURJLENBQWpCOzs7Ozs7Ozs7SUNWTSxTO0FBQ0osdUJBQWU7QUFBQTs7QUFDYixTQUFLLFNBQUwsR0FBaUIsUUFBakI7QUFDRDs7OzsyQkFFTyxJLEVBQW9CO0FBQUEsVUFBZCxPQUFjLHVFQUFKLEVBQUk7O0FBQzFCLGFBQU8sSUFBUDtBQUNEOzs7Ozs7QUFHSCxPQUFPLE9BQVAsR0FBaUI7QUFDZixhQUFXO0FBREksQ0FBakI7Ozs7Ozs7SUNWTSxRLEdBQ0osb0JBQW1FO0FBQUEsTUFBdEQsR0FBc0QsdUVBQWhELEVBQWdEO0FBQUEsTUFBNUMsS0FBNEMsdUVBQXBDLEVBQW9DO0FBQUEsTUFBaEMsV0FBZ0MsdUVBQWxCLEVBQWtCO0FBQUEsTUFBZCxPQUFjLHVFQUFKLEVBQUk7O0FBQUE7O0FBQ2pFLE9BQUssR0FBTCxHQUFXLEdBQVg7QUFDQSxPQUFLLEtBQUwsR0FBYSxLQUFiO0FBQ0EsT0FBSyxXQUFMLEdBQW1CLFdBQW5CO0FBQ0EsT0FBSyxPQUFMLEdBQWUsT0FBZjtBQUNELEM7O0lBR0csSSxHQUNKLGNBQWEsR0FBYixFQUFrQixNQUFsQixFQUFvRztBQUFBLE1BQTFFLFFBQTBFLHVFQUEvRCxrQkFBK0Q7QUFBQSxNQUEzQyxNQUEyQyx1RUFBbEMsRUFBa0M7QUFBQSxNQUE5QixLQUE4Qix1RUFBdEIsRUFBc0I7QUFBQSxNQUFsQixXQUFrQix1RUFBSixFQUFJOztBQUFBOztBQUNsRyxNQUFJLFFBQVEsU0FBWixFQUF1QjtBQUNyQixVQUFNLElBQUksS0FBSixDQUFVLDBCQUFWLENBQU47QUFDRDs7QUFFRCxNQUFJLFdBQVcsU0FBZixFQUEwQjtBQUN4QixVQUFNLElBQUksS0FBSixDQUFVLDZCQUFWLENBQU47QUFDRDs7QUFFRCxPQUFLLEdBQUwsR0FBVyxHQUFYO0FBQ0EsT0FBSyxNQUFMLEdBQWMsTUFBZDtBQUNBLE9BQUssUUFBTCxHQUFnQixRQUFoQjtBQUNBLE9BQUssTUFBTCxHQUFjLE1BQWQ7QUFDQSxPQUFLLEtBQUwsR0FBYSxLQUFiO0FBQ0EsT0FBSyxXQUFMLEdBQW1CLFdBQW5CO0FBQ0QsQzs7SUFHRyxLLEdBQ0osZUFBYSxJQUFiLEVBQXNFO0FBQUEsTUFBbkQsUUFBbUQsdUVBQXhDLEtBQXdDO0FBQUEsTUFBakMsUUFBaUMsdUVBQXRCLEVBQXNCO0FBQUEsTUFBbEIsV0FBa0IsdUVBQUosRUFBSTs7QUFBQTs7QUFDcEUsTUFBSSxTQUFTLFNBQWIsRUFBd0I7QUFDdEIsVUFBTSxJQUFJLEtBQUosQ0FBVSwyQkFBVixDQUFOO0FBQ0Q7O0FBRUQsT0FBSyxJQUFMLEdBQVksSUFBWjtBQUNBLE9BQUssUUFBTCxHQUFnQixRQUFoQjtBQUNBLE9BQUssUUFBTCxHQUFnQixRQUFoQjtBQUNBLE9BQUssV0FBTCxHQUFtQixXQUFuQjtBQUNELEM7O0FBR0gsT0FBTyxPQUFQLEdBQWlCO0FBQ2YsWUFBVSxRQURLO0FBRWYsUUFBTSxJQUZTO0FBR2YsU0FBTztBQUhRLENBQWpCOzs7Ozs7Ozs7OztJQ3pDTSxjOzs7QUFDSiwwQkFBYSxPQUFiLEVBQXNCO0FBQUE7O0FBQUEsZ0lBQ2QsT0FEYzs7QUFFcEIsVUFBSyxPQUFMLEdBQWUsT0FBZjtBQUNBLFVBQUssSUFBTCxHQUFZLGdCQUFaO0FBSG9CO0FBSXJCOzs7RUFMMEIsSzs7SUFRdkIsZTs7O0FBQ0osMkJBQWEsT0FBYixFQUFzQjtBQUFBOztBQUFBLG1JQUNkLE9BRGM7O0FBRXBCLFdBQUssT0FBTCxHQUFlLE9BQWY7QUFDQSxXQUFLLElBQUwsR0FBWSxpQkFBWjtBQUhvQjtBQUlyQjs7O0VBTDJCLEs7O0lBUXhCLFk7OztBQUNKLHdCQUFhLE9BQWIsRUFBc0IsT0FBdEIsRUFBK0I7QUFBQTs7QUFBQSw2SEFDdkIsT0FEdUI7O0FBRTdCLFdBQUssT0FBTCxHQUFlLE9BQWY7QUFDQSxXQUFLLE9BQUwsR0FBZSxPQUFmO0FBQ0EsV0FBSyxJQUFMLEdBQVksY0FBWjtBQUo2QjtBQUs5Qjs7O0VBTndCLEs7O0FBUzNCLE9BQU8sT0FBUCxHQUFpQjtBQUNmLGtCQUFnQixjQUREO0FBRWYsbUJBQWlCLGVBRkY7QUFHZixnQkFBYztBQUhDLENBQWpCOzs7OztBQ3pCQSxJQUFNLE9BQU8sUUFBUSxRQUFSLENBQWI7QUFDQSxJQUFNLFNBQVMsUUFBUSxVQUFSLENBQWY7QUFDQSxJQUFNLFNBQVMsUUFBUSxVQUFSLENBQWY7QUFDQSxJQUFNLFdBQVcsUUFBUSxZQUFSLENBQWpCO0FBQ0EsSUFBTSxTQUFTLFFBQVEsVUFBUixDQUFmO0FBQ0EsSUFBTSxhQUFhLFFBQVEsY0FBUixDQUFuQjtBQUNBLElBQU0sUUFBUSxRQUFRLFNBQVIsQ0FBZDs7QUFFQSxJQUFNLFVBQVU7QUFDZCxVQUFRLE9BQU8sTUFERDtBQUVkLFlBQVUsU0FBUyxRQUZMO0FBR2QsUUFBTSxTQUFTLElBSEQ7QUFJZCxRQUFNLElBSlE7QUFLZCxVQUFRLE1BTE07QUFNZCxVQUFRLE1BTk07QUFPZCxjQUFZLFVBUEU7QUFRZCxTQUFPO0FBUk8sQ0FBaEI7O0FBV0EsT0FBTyxPQUFQLEdBQWlCLE9BQWpCOzs7Ozs7Ozs7QUNuQkEsSUFBTSxRQUFRLFFBQVEsa0JBQVIsQ0FBZDtBQUNBLElBQU0sU0FBUyxRQUFRLFdBQVIsQ0FBZjtBQUNBLElBQU0sUUFBUSxRQUFRLFVBQVIsQ0FBZDtBQUNBLElBQU0sTUFBTSxRQUFRLFdBQVIsQ0FBWjtBQUNBLElBQU0sY0FBYyxRQUFRLGNBQVIsQ0FBcEI7O0FBRUEsSUFBTSxnQkFBZ0IsU0FBaEIsYUFBZ0IsQ0FBQyxRQUFELEVBQVcsUUFBWCxFQUFxQixnQkFBckIsRUFBMEM7QUFDOUQsU0FBTyxTQUFTLElBQVQsR0FBZ0IsSUFBaEIsQ0FBcUIsZ0JBQVE7QUFDbEMsUUFBSSxnQkFBSixFQUFzQjtBQUNwQix1QkFBaUIsUUFBakIsRUFBMkIsSUFBM0I7QUFDRDtBQUNELFFBQU0sY0FBYyxTQUFTLE9BQVQsQ0FBaUIsR0FBakIsQ0FBcUIsY0FBckIsQ0FBcEI7QUFDQSxRQUFNLFVBQVUsTUFBTSxnQkFBTixDQUF1QixRQUF2QixFQUFpQyxXQUFqQyxDQUFoQjtBQUNBLFFBQU0sVUFBVSxFQUFDLEtBQUssU0FBUyxHQUFmLEVBQWhCO0FBQ0EsV0FBTyxRQUFRLE1BQVIsQ0FBZSxJQUFmLEVBQXFCLE9BQXJCLENBQVA7QUFDRCxHQVJNLENBQVA7QUFTRCxDQVZEOztJQVlNLGE7QUFDSiwyQkFBMkI7QUFBQSxRQUFkLE9BQWMsdUVBQUosRUFBSTs7QUFBQTs7QUFDekIsU0FBSyxPQUFMLEdBQWUsQ0FBQyxNQUFELEVBQVMsT0FBVCxDQUFmO0FBQ0EsU0FBSyxJQUFMLEdBQVksUUFBUSxJQUFSLElBQWdCLElBQTVCO0FBQ0EsU0FBSyxPQUFMLEdBQWUsUUFBUSxPQUFSLElBQW1CLEVBQWxDO0FBQ0EsU0FBSyxLQUFMLEdBQWEsUUFBUSxLQUFSLElBQWlCLEtBQTlCO0FBQ0EsU0FBSyxRQUFMLEdBQWdCLFFBQVEsUUFBUixJQUFvQixPQUFPLFFBQTNDO0FBQ0EsU0FBSyxlQUFMLEdBQXVCLFFBQVEsZUFBL0I7QUFDQSxTQUFLLGdCQUFMLEdBQXdCLFFBQVEsZ0JBQWhDO0FBQ0Q7Ozs7aUNBRWEsSSxFQUFNLFEsRUFBdUI7QUFBQSxVQUFiLE1BQWEsdUVBQUosRUFBSTs7QUFDekMsVUFBTSxTQUFTLEtBQUssTUFBcEI7QUFDQSxVQUFNLFNBQVMsS0FBSyxNQUFMLENBQVksV0FBWixFQUFmO0FBQ0EsVUFBSSxjQUFjLEVBQWxCO0FBQ0EsVUFBSSxhQUFhLEVBQWpCO0FBQ0EsVUFBSSxhQUFhLEVBQWpCO0FBQ0EsVUFBSSxhQUFhLEVBQWpCO0FBQ0EsVUFBSSxVQUFVLEtBQWQ7O0FBRUEsV0FBSyxJQUFJLE1BQU0sQ0FBVixFQUFhLE1BQU0sT0FBTyxNQUEvQixFQUF1QyxNQUFNLEdBQTdDLEVBQWtELEtBQWxELEVBQXlEO0FBQ3ZELFlBQU0sUUFBUSxPQUFPLEdBQVAsQ0FBZDs7QUFFQTtBQUNBLFlBQUksQ0FBQyxPQUFPLGNBQVAsQ0FBc0IsTUFBTSxJQUE1QixDQUFMLEVBQXdDO0FBQ3RDLGNBQUksTUFBTSxRQUFWLEVBQW9CO0FBQ2xCLGtCQUFNLElBQUksT0FBTyxjQUFYLCtCQUFzRCxNQUFNLElBQTVELE9BQU47QUFDRCxXQUZELE1BRU87QUFDTDtBQUNEO0FBQ0Y7O0FBRUQsbUJBQVcsSUFBWCxDQUFnQixNQUFNLElBQXRCO0FBQ0EsWUFBSSxNQUFNLFFBQU4sS0FBbUIsT0FBdkIsRUFBZ0M7QUFDOUIsc0JBQVksTUFBTSxJQUFsQixJQUEwQixPQUFPLE1BQU0sSUFBYixDQUExQjtBQUNELFNBRkQsTUFFTyxJQUFJLE1BQU0sUUFBTixLQUFtQixNQUF2QixFQUErQjtBQUNwQyxxQkFBVyxNQUFNLElBQWpCLElBQXlCLE9BQU8sTUFBTSxJQUFiLENBQXpCO0FBQ0QsU0FGTSxNQUVBLElBQUksTUFBTSxRQUFOLEtBQW1CLE1BQXZCLEVBQStCO0FBQ3BDLHFCQUFXLE1BQU0sSUFBakIsSUFBeUIsT0FBTyxNQUFNLElBQWIsQ0FBekI7QUFDQSxvQkFBVSxJQUFWO0FBQ0QsU0FITSxNQUdBLElBQUksTUFBTSxRQUFOLEtBQW1CLE1BQXZCLEVBQStCO0FBQ3BDLHVCQUFhLE9BQU8sTUFBTSxJQUFiLENBQWI7QUFDQSxvQkFBVSxJQUFWO0FBQ0Q7QUFDRjs7QUFFRDtBQUNBLFdBQUssSUFBSSxRQUFULElBQXFCLE1BQXJCLEVBQTZCO0FBQzNCLFlBQUksT0FBTyxjQUFQLENBQXNCLFFBQXRCLEtBQW1DLENBQUMsV0FBVyxRQUFYLENBQW9CLFFBQXBCLENBQXhDLEVBQXVFO0FBQ3JFLGdCQUFNLElBQUksT0FBTyxjQUFYLDBCQUFpRCxRQUFqRCxPQUFOO0FBQ0Q7QUFDRjs7QUFFRCxVQUFJLGlCQUFpQixFQUFDLFFBQVEsTUFBVCxFQUFpQixTQUFTLEVBQTFCLEVBQXJCOztBQUVBLGFBQU8sTUFBUCxDQUFjLGVBQWUsT0FBN0IsRUFBc0MsS0FBSyxPQUEzQzs7QUFFQSxVQUFJLE9BQUosRUFBYTtBQUNYLFlBQUksS0FBSyxRQUFMLEtBQWtCLGtCQUF0QixFQUEwQztBQUN4Qyx5QkFBZSxJQUFmLEdBQXNCLEtBQUssU0FBTCxDQUFlLFVBQWYsQ0FBdEI7QUFDQSx5QkFBZSxPQUFmLENBQXVCLGNBQXZCLElBQXlDLGtCQUF6QztBQUNELFNBSEQsTUFHTyxJQUFJLEtBQUssUUFBTCxLQUFrQixxQkFBdEIsRUFBNkM7QUFDbEQsY0FBSSxPQUFPLElBQUksS0FBSyxRQUFULEVBQVg7O0FBRUEsZUFBSyxJQUFJLFFBQVQsSUFBcUIsVUFBckIsRUFBaUM7QUFDL0IsaUJBQUssTUFBTCxDQUFZLFFBQVosRUFBc0IsV0FBVyxRQUFYLENBQXRCO0FBQ0Q7QUFDRCx5QkFBZSxJQUFmLEdBQXNCLElBQXRCO0FBQ0QsU0FQTSxNQU9BLElBQUksS0FBSyxRQUFMLEtBQWtCLG1DQUF0QixFQUEyRDtBQUNoRSxjQUFJLFdBQVcsRUFBZjtBQUNBLGVBQUssSUFBSSxTQUFULElBQXFCLFVBQXJCLEVBQWlDO0FBQy9CLGdCQUFNLGFBQWEsbUJBQW1CLFNBQW5CLENBQW5CO0FBQ0EsZ0JBQU0sZUFBZSxtQkFBbUIsV0FBVyxTQUFYLENBQW5CLENBQXJCO0FBQ0EscUJBQVMsSUFBVCxDQUFjLGFBQWEsR0FBYixHQUFtQixZQUFqQztBQUNEO0FBQ0QscUJBQVcsU0FBUyxJQUFULENBQWMsR0FBZCxDQUFYOztBQUVBLHlCQUFlLElBQWYsR0FBc0IsUUFBdEI7QUFDQSx5QkFBZSxPQUFmLENBQXVCLGNBQXZCLElBQXlDLG1DQUF6QztBQUNEO0FBQ0Y7O0FBRUQsVUFBSSxLQUFLLElBQVQsRUFBZTtBQUNiLHlCQUFpQixLQUFLLElBQUwsQ0FBVSxZQUFWLENBQXVCLGNBQXZCLENBQWpCO0FBQ0Q7O0FBRUQsVUFBSSxZQUFZLFlBQVksS0FBWixDQUFrQixLQUFLLEdBQXZCLENBQWhCO0FBQ0Esa0JBQVksVUFBVSxNQUFWLENBQWlCLFVBQWpCLENBQVo7QUFDQSxrQkFBWSxJQUFJLEdBQUosQ0FBUSxTQUFSLENBQVo7QUFDQSxnQkFBVSxHQUFWLENBQWMsT0FBZCxFQUF1QixXQUF2Qjs7QUFFQSxhQUFPO0FBQ0wsYUFBSyxVQUFVLFFBQVYsRUFEQTtBQUVMLGlCQUFTO0FBRkosT0FBUDtBQUlEOzs7MkJBRU8sSSxFQUFNLFEsRUFBdUI7QUFBQSxVQUFiLE1BQWEsdUVBQUosRUFBSTs7QUFDbkMsVUFBTSxtQkFBbUIsS0FBSyxnQkFBOUI7QUFDQSxVQUFNLFVBQVUsS0FBSyxZQUFMLENBQWtCLElBQWxCLEVBQXdCLFFBQXhCLEVBQWtDLE1BQWxDLENBQWhCOztBQUVBLFVBQUksS0FBSyxlQUFULEVBQTBCO0FBQ3hCLGFBQUssZUFBTCxDQUFxQixPQUFyQjtBQUNEOztBQUVELGFBQU8sS0FBSyxLQUFMLENBQVcsUUFBUSxHQUFuQixFQUF3QixRQUFRLE9BQWhDLEVBQ0osSUFESSxDQUNDLFVBQVUsUUFBVixFQUFvQjtBQUN4QixZQUFJLFNBQVMsTUFBVCxLQUFvQixHQUF4QixFQUE2QjtBQUMzQjtBQUNEO0FBQ0QsZUFBTyxjQUFjLFFBQWQsRUFBd0IsUUFBeEIsRUFBa0MsZ0JBQWxDLEVBQ0osSUFESSxDQUNDLFVBQVUsSUFBVixFQUFnQjtBQUNwQixjQUFJLFNBQVMsRUFBYixFQUFpQjtBQUNmLG1CQUFPLElBQVA7QUFDRCxXQUZELE1BRU87QUFDTCxnQkFBTSxRQUFRLFNBQVMsTUFBVCxHQUFrQixHQUFsQixHQUF3QixTQUFTLFVBQS9DO0FBQ0EsZ0JBQU0sUUFBUSxJQUFJLE9BQU8sWUFBWCxDQUF3QixLQUF4QixFQUErQixJQUEvQixDQUFkO0FBQ0EsbUJBQU8sUUFBUSxNQUFSLENBQWUsS0FBZixDQUFQO0FBQ0Q7QUFDRixTQVRJLENBQVA7QUFVRCxPQWZJLENBQVA7QUFnQkQ7Ozs7OztBQUdILE9BQU8sT0FBUCxHQUFpQjtBQUNmLGlCQUFlO0FBREEsQ0FBakI7Ozs7O0FDOUlBLElBQU0sT0FBTyxRQUFRLFFBQVIsQ0FBYjs7QUFFQSxPQUFPLE9BQVAsR0FBaUI7QUFDZixpQkFBZSxLQUFLO0FBREwsQ0FBakI7Ozs7O0FDRkEsSUFBTSxNQUFNLFFBQVEsV0FBUixDQUFaOztBQUVBLElBQU0scUJBQXFCLFNBQXJCLGtCQUFxQixDQUFVLFVBQVYsRUFBc0IsR0FBdEIsRUFBMkI7QUFDcEQsTUFBTSxZQUFZLElBQUksR0FBSixDQUFRLEdBQVIsQ0FBbEI7QUFDQSxNQUFNLFNBQVMsVUFBVSxRQUFWLENBQW1CLE9BQW5CLENBQTJCLEdBQTNCLEVBQWdDLEVBQWhDLENBQWY7O0FBRm9EO0FBQUE7QUFBQTs7QUFBQTtBQUlwRCx5QkFBc0IsVUFBdEIsOEhBQWtDO0FBQUEsVUFBekIsU0FBeUI7O0FBQ2hDLFVBQUksVUFBVSxPQUFWLENBQWtCLFFBQWxCLENBQTJCLE1BQTNCLENBQUosRUFBd0M7QUFDdEMsZUFBTyxTQUFQO0FBQ0Q7QUFDRjtBQVJtRDtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBOztBQVVwRCxRQUFNLHNDQUFvQyxHQUFwQyxDQUFOO0FBQ0QsQ0FYRDs7QUFhQSxJQUFNLG1CQUFtQixTQUFuQixnQkFBbUIsQ0FBVSxRQUFWLEVBQW9CLFdBQXBCLEVBQWlDO0FBQ3hELE1BQUksZ0JBQWdCLFNBQWhCLElBQTZCLGdCQUFnQixJQUFqRCxFQUF1RDtBQUNyRCxXQUFPLFNBQVMsQ0FBVCxDQUFQO0FBQ0Q7O0FBRUQsTUFBTSxXQUFXLFlBQVksV0FBWixHQUEwQixLQUExQixDQUFnQyxHQUFoQyxFQUFxQyxDQUFyQyxFQUF3QyxJQUF4QyxFQUFqQjtBQUNBLE1BQU0sV0FBVyxTQUFTLEtBQVQsQ0FBZSxHQUFmLEVBQW9CLENBQXBCLElBQXlCLElBQTFDO0FBQ0EsTUFBTSxlQUFlLEtBQXJCO0FBQ0EsTUFBTSxrQkFBa0IsQ0FBQyxRQUFELEVBQVcsUUFBWCxFQUFxQixZQUFyQixDQUF4Qjs7QUFSd0Q7QUFBQTtBQUFBOztBQUFBO0FBVXhELDBCQUFvQixRQUFwQixtSUFBOEI7QUFBQSxVQUFyQixPQUFxQjs7QUFDNUIsVUFBSSxnQkFBZ0IsUUFBaEIsQ0FBeUIsUUFBUSxTQUFqQyxDQUFKLEVBQWlEO0FBQy9DLGVBQU8sT0FBUDtBQUNEO0FBQ0Y7QUFkdUQ7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7QUFnQnhELFFBQU0scURBQW1ELFdBQW5ELENBQU47QUFDRCxDQWpCRDs7QUFtQkEsSUFBTSxpQkFBaUIsU0FBakIsY0FBaUIsQ0FBVSxNQUFWLEVBQWtCO0FBQ3ZDO0FBQ0EsU0FBUSw4QkFBNkIsSUFBN0IsQ0FBa0MsTUFBbEM7QUFBUjtBQUNELENBSEQ7O0FBS0EsT0FBTyxPQUFQLEdBQWlCO0FBQ2Ysc0JBQW9CLGtCQURMO0FBRWYsb0JBQWtCLGdCQUZIO0FBR2Ysa0JBQWdCO0FBSEQsQ0FBakI7OztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNyV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiY2xhc3MgQmFzaWNBdXRoZW50aWNhdGlvbiB7XG4gIGNvbnN0cnVjdG9yIChvcHRpb25zID0ge30pIHtcbiAgICBjb25zdCB1c2VybmFtZSA9IG9wdGlvbnMudXNlcm5hbWVcbiAgICBjb25zdCBwYXNzd29yZCA9IG9wdGlvbnMucGFzc3dvcmRcbiAgICBjb25zdCBoYXNoID0gd2luZG93LmJ0b2EodXNlcm5hbWUgKyAnOicgKyBwYXNzd29yZClcbiAgICB0aGlzLmF1dGggPSAnQmFzaWMgJyArIGhhc2hcbiAgfVxuXG4gIGF1dGhlbnRpY2F0ZSAob3B0aW9ucykge1xuICAgIG9wdGlvbnMuaGVhZGVyc1snQXV0aG9yaXphdGlvbiddID0gdGhpcy5hdXRoXG4gICAgcmV0dXJuIG9wdGlvbnNcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgQmFzaWNBdXRoZW50aWNhdGlvbjogQmFzaWNBdXRoZW50aWNhdGlvblxufVxuIiwiY29uc3QgYmFzaWMgPSByZXF1aXJlKCcuL2Jhc2ljJylcbmNvbnN0IHNlc3Npb24gPSByZXF1aXJlKCcuL3Nlc3Npb24nKVxuY29uc3QgdG9rZW4gPSByZXF1aXJlKCcuL3Rva2VuJylcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIEJhc2ljQXV0aGVudGljYXRpb246IGJhc2ljLkJhc2ljQXV0aGVudGljYXRpb24sXG4gIFNlc3Npb25BdXRoZW50aWNhdGlvbjogc2Vzc2lvbi5TZXNzaW9uQXV0aGVudGljYXRpb24sXG4gIFRva2VuQXV0aGVudGljYXRpb246IHRva2VuLlRva2VuQXV0aGVudGljYXRpb25cbn1cbiIsImNvbnN0IHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKVxuXG5mdW5jdGlvbiB0cmltIChzdHIpIHtcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzXFxzKi8sICcnKS5yZXBsYWNlKC9cXHNcXHMqJC8sICcnKVxufVxuXG5mdW5jdGlvbiBnZXRDb29raWUgKGNvb2tpZU5hbWUsIGNvb2tpZVN0cmluZykge1xuICBjb29raWVTdHJpbmcgPSBjb29raWVTdHJpbmcgfHwgd2luZG93LmRvY3VtZW50LmNvb2tpZVxuICBpZiAoY29va2llU3RyaW5nICYmIGNvb2tpZVN0cmluZyAhPT0gJycpIHtcbiAgICBjb25zdCBjb29raWVzID0gY29va2llU3RyaW5nLnNwbGl0KCc7JylcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvb2tpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNvb2tpZSA9IHRyaW0oY29va2llc1tpXSlcbiAgICAgIC8vIERvZXMgdGhpcyBjb29raWUgc3RyaW5nIGJlZ2luIHdpdGggdGhlIG5hbWUgd2Ugd2FudD9cbiAgICAgIGlmIChjb29raWUuc3Vic3RyaW5nKDAsIGNvb2tpZU5hbWUubGVuZ3RoICsgMSkgPT09IChjb29raWVOYW1lICsgJz0nKSkge1xuICAgICAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KGNvb2tpZS5zdWJzdHJpbmcoY29va2llTmFtZS5sZW5ndGggKyAxKSlcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGxcbn1cblxuY2xhc3MgU2Vzc2lvbkF1dGhlbnRpY2F0aW9uIHtcbiAgY29uc3RydWN0b3IgKG9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMuY3NyZlRva2VuID0gZ2V0Q29va2llKG9wdGlvbnMuY3NyZkNvb2tpZU5hbWUsIG9wdGlvbnMuY29va2llU3RyaW5nKVxuICAgIHRoaXMuY3NyZkhlYWRlck5hbWUgPSBvcHRpb25zLmNzcmZIZWFkZXJOYW1lXG4gIH1cblxuICBhdXRoZW50aWNhdGUgKG9wdGlvbnMpIHtcbiAgICBvcHRpb25zLmNyZWRlbnRpYWxzID0gJ3NhbWUtb3JpZ2luJ1xuICAgIGlmICh0aGlzLmNzcmZUb2tlbiAmJiAhdXRpbHMuY3NyZlNhZmVNZXRob2Qob3B0aW9ucy5tZXRob2QpKSB7XG4gICAgICBvcHRpb25zLmhlYWRlcnNbdGhpcy5jc3JmSGVhZGVyTmFtZV0gPSB0aGlzLmNzcmZUb2tlblxuICAgIH1cbiAgICByZXR1cm4gb3B0aW9uc1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBTZXNzaW9uQXV0aGVudGljYXRpb246IFNlc3Npb25BdXRoZW50aWNhdGlvblxufVxuIiwiY2xhc3MgVG9rZW5BdXRoZW50aWNhdGlvbiB7XG4gIGNvbnN0cnVjdG9yIChvcHRpb25zID0ge30pIHtcbiAgICB0aGlzLnRva2VuID0gb3B0aW9ucy50b2tlblxuICAgIHRoaXMuc2NoZW1lID0gb3B0aW9ucy5zY2hlbWUgfHwgJ0JlYXJlcidcbiAgfVxuXG4gIGF1dGhlbnRpY2F0ZSAob3B0aW9ucykge1xuICAgIG9wdGlvbnMuaGVhZGVyc1snQXV0aG9yaXphdGlvbiddID0gdGhpcy5zY2hlbWUgKyAnICcgKyB0aGlzLnRva2VuXG4gICAgcmV0dXJuIG9wdGlvbnNcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgVG9rZW5BdXRoZW50aWNhdGlvbjogVG9rZW5BdXRoZW50aWNhdGlvblxufVxuIiwiY29uc3QgZG9jdW1lbnQgPSByZXF1aXJlKCcuL2RvY3VtZW50JylcbmNvbnN0IGNvZGVjcyA9IHJlcXVpcmUoJy4vY29kZWNzJylcbmNvbnN0IGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJylcbmNvbnN0IHRyYW5zcG9ydHMgPSByZXF1aXJlKCcuL3RyYW5zcG9ydHMnKVxuY29uc3QgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJylcblxuZnVuY3Rpb24gbG9va3VwTGluayAobm9kZSwga2V5cykge1xuICBmb3IgKGxldCBrZXkgb2Yga2V5cykge1xuICAgIGlmIChub2RlIGluc3RhbmNlb2YgZG9jdW1lbnQuRG9jdW1lbnQpIHtcbiAgICAgIG5vZGUgPSBub2RlLmNvbnRlbnRba2V5XVxuICAgIH0gZWxzZSB7XG4gICAgICBub2RlID0gbm9kZVtrZXldXG4gICAgfVxuICAgIGlmIChub2RlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBlcnJvcnMuTGlua0xvb2t1cEVycm9yKGBJbnZhbGlkIGxpbmsgbG9va3VwOiAke0pTT04uc3RyaW5naWZ5KGtleXMpfWApXG4gICAgfVxuICB9XG4gIGlmICghKG5vZGUgaW5zdGFuY2VvZiBkb2N1bWVudC5MaW5rKSkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuTGlua0xvb2t1cEVycm9yKGBJbnZhbGlkIGxpbmsgbG9va3VwOiAke0pTT04uc3RyaW5naWZ5KGtleXMpfWApXG4gIH1cbiAgcmV0dXJuIG5vZGVcbn1cblxuY2xhc3MgQ2xpZW50IHtcbiAgY29uc3RydWN0b3IgKG9wdGlvbnMgPSB7fSkge1xuICAgIGNvbnN0IHRyYW5zcG9ydE9wdGlvbnMgPSB7XG4gICAgICBhdXRoOiBvcHRpb25zLmF1dGggfHwgbnVsbCxcbiAgICAgIGhlYWRlcnM6IG9wdGlvbnMuaGVhZGVycyB8fCB7fSxcbiAgICAgIHJlcXVlc3RDYWxsYmFjazogb3B0aW9ucy5yZXF1ZXN0Q2FsbGJhY2ssXG4gICAgICByZXNwb25zZUNhbGxiYWNrOiBvcHRpb25zLnJlc3BvbnNlQ2FsbGJhY2tcbiAgICB9XG5cbiAgICB0aGlzLmRlY29kZXJzID0gb3B0aW9ucy5kZWNvZGVycyB8fCBbbmV3IGNvZGVjcy5Db3JlSlNPTkNvZGVjKCksIG5ldyBjb2RlY3MuSlNPTkNvZGVjKCksIG5ldyBjb2RlY3MuVGV4dENvZGVjKCldXG4gICAgdGhpcy50cmFuc3BvcnRzID0gb3B0aW9ucy50cmFuc3BvcnRzIHx8IFtuZXcgdHJhbnNwb3J0cy5IVFRQVHJhbnNwb3J0KHRyYW5zcG9ydE9wdGlvbnMpXVxuICB9XG5cbiAgYWN0aW9uIChkb2N1bWVudCwga2V5cywgcGFyYW1zID0ge30pIHtcbiAgICBjb25zdCBsaW5rID0gbG9va3VwTGluayhkb2N1bWVudCwga2V5cylcbiAgICBjb25zdCB0cmFuc3BvcnQgPSB1dGlscy5kZXRlcm1pbmVUcmFuc3BvcnQodGhpcy50cmFuc3BvcnRzLCBsaW5rLnVybClcbiAgICByZXR1cm4gdHJhbnNwb3J0LmFjdGlvbihsaW5rLCB0aGlzLmRlY29kZXJzLCBwYXJhbXMpXG4gIH1cblxuICBnZXQgKHVybCkge1xuICAgIGNvbnN0IGxpbmsgPSBuZXcgZG9jdW1lbnQuTGluayh1cmwsICdnZXQnKVxuICAgIGNvbnN0IHRyYW5zcG9ydCA9IHV0aWxzLmRldGVybWluZVRyYW5zcG9ydCh0aGlzLnRyYW5zcG9ydHMsIHVybClcbiAgICByZXR1cm4gdHJhbnNwb3J0LmFjdGlvbihsaW5rLCB0aGlzLmRlY29kZXJzKVxuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBDbGllbnQ6IENsaWVudFxufVxuIiwiY29uc3QgZG9jdW1lbnQgPSByZXF1aXJlKCcuLi9kb2N1bWVudCcpXG5jb25zdCBVUkwgPSByZXF1aXJlKCd1cmwtcGFyc2UnKVxuXG5mdW5jdGlvbiB1bmVzY2FwZUtleSAoa2V5KSB7XG4gIGlmIChrZXkubWF0Y2goL19fKHR5cGV8bWV0YSkkLykpIHtcbiAgICByZXR1cm4ga2V5LnN1YnN0cmluZygxKVxuICB9XG4gIHJldHVybiBrZXlcbn1cblxuZnVuY3Rpb24gZ2V0U3RyaW5nIChvYmosIGtleSkge1xuICBjb25zdCB2YWx1ZSA9IG9ialtrZXldXG4gIGlmICh0eXBlb2YgKHZhbHVlKSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gdmFsdWVcbiAgfVxuICByZXR1cm4gJydcbn1cblxuZnVuY3Rpb24gZ2V0Qm9vbGVhbiAob2JqLCBrZXkpIHtcbiAgY29uc3QgdmFsdWUgPSBvYmpba2V5XVxuICBpZiAodHlwZW9mICh2YWx1ZSkgPT09ICdib29sZWFuJykge1xuICAgIHJldHVybiB2YWx1ZVxuICB9XG4gIHJldHVybiBmYWxzZVxufVxuXG5mdW5jdGlvbiBnZXRPYmplY3QgKG9iaiwga2V5KSB7XG4gIGNvbnN0IHZhbHVlID0gb2JqW2tleV1cbiAgaWYgKHR5cGVvZiAodmFsdWUpID09PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiB2YWx1ZVxuICB9XG4gIHJldHVybiB7fVxufVxuXG5mdW5jdGlvbiBnZXRBcnJheSAob2JqLCBrZXkpIHtcbiAgY29uc3QgdmFsdWUgPSBvYmpba2V5XVxuICBpZiAodmFsdWUgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgIHJldHVybiB2YWx1ZVxuICB9XG4gIHJldHVybiBbXVxufVxuXG5mdW5jdGlvbiBnZXRDb250ZW50IChkYXRhLCBiYXNlVXJsKSB7XG4gIGNvbnN0IGV4Y2x1ZGVkID0gWydfdHlwZScsICdfbWV0YSddXG4gIHZhciBjb250ZW50ID0ge31cbiAgZm9yICh2YXIgcHJvcGVydHkgaW4gZGF0YSkge1xuICAgIGlmIChkYXRhLmhhc093blByb3BlcnR5KHByb3BlcnR5KSAmJiAhZXhjbHVkZWQuaW5jbHVkZXMocHJvcGVydHkpKSB7XG4gICAgICBjb25zdCBrZXkgPSB1bmVzY2FwZUtleShwcm9wZXJ0eSlcbiAgICAgIGNvbnN0IHZhbHVlID0gcHJpbWl0aXZlVG9Ob2RlKGRhdGFbcHJvcGVydHldLCBiYXNlVXJsKVxuICAgICAgY29udGVudFtrZXldID0gdmFsdWVcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNvbnRlbnRcbn1cblxuZnVuY3Rpb24gcHJpbWl0aXZlVG9Ob2RlIChkYXRhLCBiYXNlVXJsKSB7XG4gIGNvbnN0IGlzT2JqZWN0ID0gZGF0YSBpbnN0YW5jZW9mIE9iamVjdCAmJiAhKGRhdGEgaW5zdGFuY2VvZiBBcnJheSlcblxuICBpZiAoaXNPYmplY3QgJiYgZGF0YS5fdHlwZSA9PT0gJ2RvY3VtZW50Jykge1xuICAgIC8vIERvY3VtZW50XG4gICAgY29uc3QgbWV0YSA9IGdldE9iamVjdChkYXRhLCAnX21ldGEnKVxuICAgIGNvbnN0IHJlbGF0aXZlVXJsID0gZ2V0U3RyaW5nKG1ldGEsICd1cmwnKVxuICAgIGNvbnN0IHVybCA9IHJlbGF0aXZlVXJsID8gVVJMKHJlbGF0aXZlVXJsLCBiYXNlVXJsKS50b1N0cmluZygpIDogJydcbiAgICBjb25zdCB0aXRsZSA9IGdldFN0cmluZyhtZXRhLCAndGl0bGUnKVxuICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gZ2V0U3RyaW5nKG1ldGEsICdkZXNjcmlwdGlvbicpXG4gICAgY29uc3QgY29udGVudCA9IGdldENvbnRlbnQoZGF0YSwgdXJsKVxuICAgIHJldHVybiBuZXcgZG9jdW1lbnQuRG9jdW1lbnQodXJsLCB0aXRsZSwgZGVzY3JpcHRpb24sIGNvbnRlbnQpXG4gIH0gZWxzZSBpZiAoaXNPYmplY3QgJiYgZGF0YS5fdHlwZSA9PT0gJ2xpbmsnKSB7XG4gICAgLy8gTGlua1xuICAgIGNvbnN0IHJlbGF0aXZlVXJsID0gZ2V0U3RyaW5nKGRhdGEsICd1cmwnKVxuICAgIGNvbnN0IHVybCA9IHJlbGF0aXZlVXJsID8gVVJMKHJlbGF0aXZlVXJsLCBiYXNlVXJsKS50b1N0cmluZygpIDogJydcbiAgICBjb25zdCBtZXRob2QgPSBnZXRTdHJpbmcoZGF0YSwgJ2FjdGlvbicpIHx8ICdnZXQnXG4gICAgY29uc3QgdGl0bGUgPSBnZXRTdHJpbmcoZGF0YSwgJ3RpdGxlJylcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IGdldFN0cmluZyhkYXRhLCAnZGVzY3JpcHRpb24nKVxuICAgIGNvbnN0IGZpZWxkc0RhdGEgPSBnZXRBcnJheShkYXRhLCAnZmllbGRzJylcbiAgICB2YXIgZmllbGRzID0gW11cbiAgICBmb3IgKGxldCBpZHggPSAwLCBsZW4gPSBmaWVsZHNEYXRhLmxlbmd0aDsgaWR4IDwgbGVuOyBpZHgrKykge1xuICAgICAgbGV0IHZhbHVlID0gZmllbGRzRGF0YVtpZHhdXG4gICAgICBsZXQgbmFtZSA9IGdldFN0cmluZyh2YWx1ZSwgJ25hbWUnKVxuICAgICAgbGV0IHJlcXVpcmVkID0gZ2V0Qm9vbGVhbih2YWx1ZSwgJ3JlcXVpcmVkJylcbiAgICAgIGxldCBsb2NhdGlvbiA9IGdldFN0cmluZyh2YWx1ZSwgJ2xvY2F0aW9uJylcbiAgICAgIGxldCBmaWVsZERlc2NyaXB0aW9uID0gZ2V0U3RyaW5nKHZhbHVlLCAnZmllbGREZXNjcmlwdGlvbicpXG4gICAgICBsZXQgZmllbGQgPSBuZXcgZG9jdW1lbnQuRmllbGQobmFtZSwgcmVxdWlyZWQsIGxvY2F0aW9uLCBmaWVsZERlc2NyaXB0aW9uKVxuICAgICAgZmllbGRzLnB1c2goZmllbGQpXG4gICAgfVxuICAgIHJldHVybiBuZXcgZG9jdW1lbnQuTGluayh1cmwsIG1ldGhvZCwgJ2FwcGxpY2F0aW9uL2pzb24nLCBmaWVsZHMsIHRpdGxlLCBkZXNjcmlwdGlvbilcbiAgfSBlbHNlIGlmIChpc09iamVjdCkge1xuICAgIC8vIE9iamVjdFxuICAgIGxldCBjb250ZW50ID0ge31cbiAgICBmb3IgKGxldCBrZXkgaW4gZGF0YSkge1xuICAgICAgaWYgKGRhdGEuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICBjb250ZW50W2tleV0gPSBwcmltaXRpdmVUb05vZGUoZGF0YVtrZXldLCBiYXNlVXJsKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY29udGVudFxuICB9IGVsc2UgaWYgKGRhdGEgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgIC8vIE9iamVjdFxuICAgIGxldCBjb250ZW50ID0gW11cbiAgICBmb3IgKGxldCBpZHggPSAwLCBsZW4gPSBkYXRhLmxlbmd0aDsgaWR4IDwgbGVuOyBpZHgrKykge1xuICAgICAgY29udGVudC5wdXNoKHByaW1pdGl2ZVRvTm9kZShkYXRhW2lkeF0sIGJhc2VVcmwpKVxuICAgIH1cbiAgICByZXR1cm4gY29udGVudFxuICB9XG4gIC8vIFByaW1pdGl2ZVxuICByZXR1cm4gZGF0YVxufVxuXG5jbGFzcyBDb3JlSlNPTkNvZGVjIHtcbiAgY29uc3RydWN0b3IgKCkge1xuICAgIHRoaXMubWVkaWFUeXBlID0gJ2FwcGxpY2F0aW9uL2NvcmVhcGkranNvbidcbiAgfVxuXG4gIGRlY29kZSAodGV4dCwgb3B0aW9ucyA9IHt9KSB7XG4gICAgbGV0IGRhdGEgPSB0ZXh0XG4gICAgaWYgKG9wdGlvbnMucHJlbG9hZGVkID09PSB1bmRlZmluZWQgfHwgIW9wdGlvbnMucHJlbG9hZGVkKSB7XG4gICAgICBkYXRhID0gSlNPTi5wYXJzZSh0ZXh0KVxuICAgIH1cbiAgICByZXR1cm4gcHJpbWl0aXZlVG9Ob2RlKGRhdGEsIG9wdGlvbnMudXJsKVxuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBDb3JlSlNPTkNvZGVjOiBDb3JlSlNPTkNvZGVjXG59XG4iLCJjb25zdCBjb3JlanNvbiA9IHJlcXVpcmUoJy4vY29yZWpzb24nKVxuY29uc3QganNvbiA9IHJlcXVpcmUoJy4vanNvbicpXG5jb25zdCB0ZXh0ID0gcmVxdWlyZSgnLi90ZXh0JylcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIENvcmVKU09OQ29kZWM6IGNvcmVqc29uLkNvcmVKU09OQ29kZWMsXG4gIEpTT05Db2RlYzoganNvbi5KU09OQ29kZWMsXG4gIFRleHRDb2RlYzogdGV4dC5UZXh0Q29kZWNcbn1cbiIsImNsYXNzIEpTT05Db2RlYyB7XG4gIGNvbnN0cnVjdG9yICgpIHtcbiAgICB0aGlzLm1lZGlhVHlwZSA9ICdhcHBsaWNhdGlvbi9qc29uJ1xuICB9XG5cbiAgZGVjb2RlICh0ZXh0LCBvcHRpb25zID0ge30pIHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZSh0ZXh0KVxuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBKU09OQ29kZWM6IEpTT05Db2RlY1xufVxuIiwiY2xhc3MgVGV4dENvZGVjIHtcbiAgY29uc3RydWN0b3IgKCkge1xuICAgIHRoaXMubWVkaWFUeXBlID0gJ3RleHQvKidcbiAgfVxuXG4gIGRlY29kZSAodGV4dCwgb3B0aW9ucyA9IHt9KSB7XG4gICAgcmV0dXJuIHRleHRcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgVGV4dENvZGVjOiBUZXh0Q29kZWNcbn1cbiIsImNsYXNzIERvY3VtZW50IHtcbiAgY29uc3RydWN0b3IgKHVybCA9ICcnLCB0aXRsZSA9ICcnLCBkZXNjcmlwdGlvbiA9ICcnLCBjb250ZW50ID0ge30pIHtcbiAgICB0aGlzLnVybCA9IHVybFxuICAgIHRoaXMudGl0bGUgPSB0aXRsZVxuICAgIHRoaXMuZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvblxuICAgIHRoaXMuY29udGVudCA9IGNvbnRlbnRcbiAgfVxufVxuXG5jbGFzcyBMaW5rIHtcbiAgY29uc3RydWN0b3IgKHVybCwgbWV0aG9kLCBlbmNvZGluZyA9ICdhcHBsaWNhdGlvbi9qc29uJywgZmllbGRzID0gW10sIHRpdGxlID0gJycsIGRlc2NyaXB0aW9uID0gJycpIHtcbiAgICBpZiAodXJsID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndXJsIGFyZ3VtZW50IGlzIHJlcXVpcmVkJylcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWV0aG9kIGFyZ3VtZW50IGlzIHJlcXVpcmVkJylcbiAgICB9XG5cbiAgICB0aGlzLnVybCA9IHVybFxuICAgIHRoaXMubWV0aG9kID0gbWV0aG9kXG4gICAgdGhpcy5lbmNvZGluZyA9IGVuY29kaW5nXG4gICAgdGhpcy5maWVsZHMgPSBmaWVsZHNcbiAgICB0aGlzLnRpdGxlID0gdGl0bGVcbiAgICB0aGlzLmRlc2NyaXB0aW9uID0gZGVzY3JpcHRpb25cbiAgfVxufVxuXG5jbGFzcyBGaWVsZCB7XG4gIGNvbnN0cnVjdG9yIChuYW1lLCByZXF1aXJlZCA9IGZhbHNlLCBsb2NhdGlvbiA9ICcnLCBkZXNjcmlwdGlvbiA9ICcnKSB7XG4gICAgaWYgKG5hbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCduYW1lIGFyZ3VtZW50IGlzIHJlcXVpcmVkJylcbiAgICB9XG5cbiAgICB0aGlzLm5hbWUgPSBuYW1lXG4gICAgdGhpcy5yZXF1aXJlZCA9IHJlcXVpcmVkXG4gICAgdGhpcy5sb2NhdGlvbiA9IGxvY2F0aW9uXG4gICAgdGhpcy5kZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uXG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIERvY3VtZW50OiBEb2N1bWVudCxcbiAgTGluazogTGluayxcbiAgRmllbGQ6IEZpZWxkXG59XG4iLCJjbGFzcyBQYXJhbWV0ZXJFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IgKG1lc3NhZ2UpIHtcbiAgICBzdXBlcihtZXNzYWdlKVxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2VcbiAgICB0aGlzLm5hbWUgPSAnUGFyYW1ldGVyRXJyb3InXG4gIH1cbn1cblxuY2xhc3MgTGlua0xvb2t1cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvciAobWVzc2FnZSkge1xuICAgIHN1cGVyKG1lc3NhZ2UpXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZVxuICAgIHRoaXMubmFtZSA9ICdMaW5rTG9va3VwRXJyb3InXG4gIH1cbn1cblxuY2xhc3MgRXJyb3JNZXNzYWdlIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvciAobWVzc2FnZSwgY29udGVudCkge1xuICAgIHN1cGVyKG1lc3NhZ2UpXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZVxuICAgIHRoaXMuY29udGVudCA9IGNvbnRlbnRcbiAgICB0aGlzLm5hbWUgPSAnRXJyb3JNZXNzYWdlJ1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBQYXJhbWV0ZXJFcnJvcjogUGFyYW1ldGVyRXJyb3IsXG4gIExpbmtMb29rdXBFcnJvcjogTGlua0xvb2t1cEVycm9yLFxuICBFcnJvck1lc3NhZ2U6IEVycm9yTWVzc2FnZVxufVxuIiwiY29uc3QgYXV0aCA9IHJlcXVpcmUoJy4vYXV0aCcpXG5jb25zdCBjbGllbnQgPSByZXF1aXJlKCcuL2NsaWVudCcpXG5jb25zdCBjb2RlY3MgPSByZXF1aXJlKCcuL2NvZGVjcycpXG5jb25zdCBkb2N1bWVudCA9IHJlcXVpcmUoJy4vZG9jdW1lbnQnKVxuY29uc3QgZXJyb3JzID0gcmVxdWlyZSgnLi9lcnJvcnMnKVxuY29uc3QgdHJhbnNwb3J0cyA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0cycpXG5jb25zdCB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMnKVxuXG5jb25zdCBjb3JlYXBpID0ge1xuICBDbGllbnQ6IGNsaWVudC5DbGllbnQsXG4gIERvY3VtZW50OiBkb2N1bWVudC5Eb2N1bWVudCxcbiAgTGluazogZG9jdW1lbnQuTGluayxcbiAgYXV0aDogYXV0aCxcbiAgY29kZWNzOiBjb2RlY3MsXG4gIGVycm9yczogZXJyb3JzLFxuICB0cmFuc3BvcnRzOiB0cmFuc3BvcnRzLFxuICB1dGlsczogdXRpbHNcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjb3JlYXBpXG4iLCJjb25zdCBmZXRjaCA9IHJlcXVpcmUoJ2lzb21vcnBoaWMtZmV0Y2gnKVxuY29uc3QgZXJyb3JzID0gcmVxdWlyZSgnLi4vZXJyb3JzJylcbmNvbnN0IHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKVxuY29uc3QgVVJMID0gcmVxdWlyZSgndXJsLXBhcnNlJylcbmNvbnN0IHVybFRlbXBsYXRlID0gcmVxdWlyZSgndXJsLXRlbXBsYXRlJylcblxuY29uc3QgcGFyc2VSZXNwb25zZSA9IChyZXNwb25zZSwgZGVjb2RlcnMsIHJlc3BvbnNlQ2FsbGJhY2spID0+IHtcbiAgcmV0dXJuIHJlc3BvbnNlLnRleHQoKS50aGVuKHRleHQgPT4ge1xuICAgIGlmIChyZXNwb25zZUNhbGxiYWNrKSB7XG4gICAgICByZXNwb25zZUNhbGxiYWNrKHJlc3BvbnNlLCB0ZXh0KVxuICAgIH1cbiAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdDb250ZW50LVR5cGUnKVxuICAgIGNvbnN0IGRlY29kZXIgPSB1dGlscy5uZWdvdGlhdGVEZWNvZGVyKGRlY29kZXJzLCBjb250ZW50VHlwZSlcbiAgICBjb25zdCBvcHRpb25zID0ge3VybDogcmVzcG9uc2UudXJsfVxuICAgIHJldHVybiBkZWNvZGVyLmRlY29kZSh0ZXh0LCBvcHRpb25zKVxuICB9KVxufVxuXG5jbGFzcyBIVFRQVHJhbnNwb3J0IHtcbiAgY29uc3RydWN0b3IgKG9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMuc2NoZW1lcyA9IFsnaHR0cCcsICdodHRwcyddXG4gICAgdGhpcy5hdXRoID0gb3B0aW9ucy5hdXRoIHx8IG51bGxcbiAgICB0aGlzLmhlYWRlcnMgPSBvcHRpb25zLmhlYWRlcnMgfHwge31cbiAgICB0aGlzLmZldGNoID0gb3B0aW9ucy5mZXRjaCB8fCBmZXRjaFxuICAgIHRoaXMuRm9ybURhdGEgPSBvcHRpb25zLkZvcm1EYXRhIHx8IHdpbmRvdy5Gb3JtRGF0YVxuICAgIHRoaXMucmVxdWVzdENhbGxiYWNrID0gb3B0aW9ucy5yZXF1ZXN0Q2FsbGJhY2tcbiAgICB0aGlzLnJlc3BvbnNlQ2FsbGJhY2sgPSBvcHRpb25zLnJlc3BvbnNlQ2FsbGJhY2tcbiAgfVxuXG4gIGJ1aWxkUmVxdWVzdCAobGluaywgZGVjb2RlcnMsIHBhcmFtcyA9IHt9KSB7XG4gICAgY29uc3QgZmllbGRzID0gbGluay5maWVsZHNcbiAgICBjb25zdCBtZXRob2QgPSBsaW5rLm1ldGhvZC50b1VwcGVyQ2FzZSgpXG4gICAgbGV0IHF1ZXJ5UGFyYW1zID0ge31cbiAgICBsZXQgcGF0aFBhcmFtcyA9IHt9XG4gICAgbGV0IGZvcm1QYXJhbXMgPSB7fVxuICAgIGxldCBmaWVsZE5hbWVzID0gW11cbiAgICBsZXQgaGFzQm9keSA9IGZhbHNlXG5cbiAgICBmb3IgKGxldCBpZHggPSAwLCBsZW4gPSBmaWVsZHMubGVuZ3RoOyBpZHggPCBsZW47IGlkeCsrKSB7XG4gICAgICBjb25zdCBmaWVsZCA9IGZpZWxkc1tpZHhdXG5cbiAgICAgIC8vIEVuc3VyZSBhbnkgcmVxdWlyZWQgZmllbGRzIGFyZSBpbmNsdWRlZFxuICAgICAgaWYgKCFwYXJhbXMuaGFzT3duUHJvcGVydHkoZmllbGQubmFtZSkpIHtcbiAgICAgICAgaWYgKGZpZWxkLnJlcXVpcmVkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IGVycm9ycy5QYXJhbWV0ZXJFcnJvcihgTWlzc2luZyByZXF1aXJlZCBmaWVsZDogXCIke2ZpZWxkLm5hbWV9XCJgKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZmllbGROYW1lcy5wdXNoKGZpZWxkLm5hbWUpXG4gICAgICBpZiAoZmllbGQubG9jYXRpb24gPT09ICdxdWVyeScpIHtcbiAgICAgICAgcXVlcnlQYXJhbXNbZmllbGQubmFtZV0gPSBwYXJhbXNbZmllbGQubmFtZV1cbiAgICAgIH0gZWxzZSBpZiAoZmllbGQubG9jYXRpb24gPT09ICdwYXRoJykge1xuICAgICAgICBwYXRoUGFyYW1zW2ZpZWxkLm5hbWVdID0gcGFyYW1zW2ZpZWxkLm5hbWVdXG4gICAgICB9IGVsc2UgaWYgKGZpZWxkLmxvY2F0aW9uID09PSAnZm9ybScpIHtcbiAgICAgICAgZm9ybVBhcmFtc1tmaWVsZC5uYW1lXSA9IHBhcmFtc1tmaWVsZC5uYW1lXVxuICAgICAgICBoYXNCb2R5ID0gdHJ1ZVxuICAgICAgfSBlbHNlIGlmIChmaWVsZC5sb2NhdGlvbiA9PT0gJ2JvZHknKSB7XG4gICAgICAgIGZvcm1QYXJhbXMgPSBwYXJhbXNbZmllbGQubmFtZV1cbiAgICAgICAgaGFzQm9keSA9IHRydWVcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgYW55IHBhcmFtZXRlcnMgdGhhdCBkaWQgbm90IGhhdmUgYSBtYXRjaGluZyBmaWVsZFxuICAgIGZvciAodmFyIHByb3BlcnR5IGluIHBhcmFtcykge1xuICAgICAgaWYgKHBhcmFtcy5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSkgJiYgIWZpZWxkTmFtZXMuaW5jbHVkZXMocHJvcGVydHkpKSB7XG4gICAgICAgIHRocm93IG5ldyBlcnJvcnMuUGFyYW1ldGVyRXJyb3IoYFVua25vd24gcGFyYW1ldGVyOiBcIiR7cHJvcGVydHl9XCJgKVxuICAgICAgfVxuICAgIH1cblxuICAgIGxldCByZXF1ZXN0T3B0aW9ucyA9IHttZXRob2Q6IG1ldGhvZCwgaGVhZGVyczoge319XG5cbiAgICBPYmplY3QuYXNzaWduKHJlcXVlc3RPcHRpb25zLmhlYWRlcnMsIHRoaXMuaGVhZGVycylcblxuICAgIGlmIChoYXNCb2R5KSB7XG4gICAgICBpZiAobGluay5lbmNvZGluZyA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmJvZHkgPSBKU09OLnN0cmluZ2lmeShmb3JtUGFyYW1zKVxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5oZWFkZXJzWydDb250ZW50LVR5cGUnXSA9ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgfSBlbHNlIGlmIChsaW5rLmVuY29kaW5nID09PSAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpIHtcbiAgICAgICAgbGV0IGZvcm0gPSBuZXcgdGhpcy5Gb3JtRGF0YSgpXG5cbiAgICAgICAgZm9yIChsZXQgcGFyYW1LZXkgaW4gZm9ybVBhcmFtcykge1xuICAgICAgICAgIGZvcm0uYXBwZW5kKHBhcmFtS2V5LCBmb3JtUGFyYW1zW3BhcmFtS2V5XSlcbiAgICAgICAgfVxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5ib2R5ID0gZm9ybVxuICAgICAgfSBlbHNlIGlmIChsaW5rLmVuY29kaW5nID09PSAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykge1xuICAgICAgICBsZXQgZm9ybUJvZHkgPSBbXVxuICAgICAgICBmb3IgKGxldCBwYXJhbUtleSBpbiBmb3JtUGFyYW1zKSB7XG4gICAgICAgICAgY29uc3QgZW5jb2RlZEtleSA9IGVuY29kZVVSSUNvbXBvbmVudChwYXJhbUtleSlcbiAgICAgICAgICBjb25zdCBlbmNvZGVkVmFsdWUgPSBlbmNvZGVVUklDb21wb25lbnQoZm9ybVBhcmFtc1twYXJhbUtleV0pXG4gICAgICAgICAgZm9ybUJvZHkucHVzaChlbmNvZGVkS2V5ICsgJz0nICsgZW5jb2RlZFZhbHVlKVxuICAgICAgICB9XG4gICAgICAgIGZvcm1Cb2R5ID0gZm9ybUJvZHkuam9pbignJicpXG5cbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuYm9keSA9IGZvcm1Cb2R5XG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddID0gJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCdcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodGhpcy5hdXRoKSB7XG4gICAgICByZXF1ZXN0T3B0aW9ucyA9IHRoaXMuYXV0aC5hdXRoZW50aWNhdGUocmVxdWVzdE9wdGlvbnMpXG4gICAgfVxuXG4gICAgbGV0IHBhcnNlZFVybCA9IHVybFRlbXBsYXRlLnBhcnNlKGxpbmsudXJsKVxuICAgIHBhcnNlZFVybCA9IHBhcnNlZFVybC5leHBhbmQocGF0aFBhcmFtcylcbiAgICBwYXJzZWRVcmwgPSBuZXcgVVJMKHBhcnNlZFVybClcbiAgICBwYXJzZWRVcmwuc2V0KCdxdWVyeScsIHF1ZXJ5UGFyYW1zKVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHVybDogcGFyc2VkVXJsLnRvU3RyaW5nKCksXG4gICAgICBvcHRpb25zOiByZXF1ZXN0T3B0aW9uc1xuICAgIH1cbiAgfVxuXG4gIGFjdGlvbiAobGluaywgZGVjb2RlcnMsIHBhcmFtcyA9IHt9KSB7XG4gICAgY29uc3QgcmVzcG9uc2VDYWxsYmFjayA9IHRoaXMucmVzcG9uc2VDYWxsYmFja1xuICAgIGNvbnN0IHJlcXVlc3QgPSB0aGlzLmJ1aWxkUmVxdWVzdChsaW5rLCBkZWNvZGVycywgcGFyYW1zKVxuXG4gICAgaWYgKHRoaXMucmVxdWVzdENhbGxiYWNrKSB7XG4gICAgICB0aGlzLnJlcXVlc3RDYWxsYmFjayhyZXF1ZXN0KVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmZldGNoKHJlcXVlc3QudXJsLCByZXF1ZXN0Lm9wdGlvbnMpXG4gICAgICAudGhlbihmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gMjA0KSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhcnNlUmVzcG9uc2UocmVzcG9uc2UsIGRlY29kZXJzLCByZXNwb25zZUNhbGxiYWNrKVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGRhdGFcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gcmVzcG9uc2Uuc3RhdHVzICsgJyAnICsgcmVzcG9uc2Uuc3RhdHVzVGV4dFxuICAgICAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBlcnJvcnMuRXJyb3JNZXNzYWdlKHRpdGxlLCBkYXRhKVxuICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgIH0pXG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIEhUVFBUcmFuc3BvcnQ6IEhUVFBUcmFuc3BvcnRcbn1cbiIsImNvbnN0IGh0dHAgPSByZXF1aXJlKCcuL2h0dHAnKVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgSFRUUFRyYW5zcG9ydDogaHR0cC5IVFRQVHJhbnNwb3J0XG59XG4iLCJjb25zdCBVUkwgPSByZXF1aXJlKCd1cmwtcGFyc2UnKVxuXG5jb25zdCBkZXRlcm1pbmVUcmFuc3BvcnQgPSBmdW5jdGlvbiAodHJhbnNwb3J0cywgdXJsKSB7XG4gIGNvbnN0IHBhcnNlZFVybCA9IG5ldyBVUkwodXJsKVxuICBjb25zdCBzY2hlbWUgPSBwYXJzZWRVcmwucHJvdG9jb2wucmVwbGFjZSgnOicsICcnKVxuXG4gIGZvciAobGV0IHRyYW5zcG9ydCBvZiB0cmFuc3BvcnRzKSB7XG4gICAgaWYgKHRyYW5zcG9ydC5zY2hlbWVzLmluY2x1ZGVzKHNjaGVtZSkpIHtcbiAgICAgIHJldHVybiB0cmFuc3BvcnRcbiAgICB9XG4gIH1cblxuICB0aHJvdyBFcnJvcihgVW5zdXBwb3J0ZWQgc2NoZW1lIGluIFVSTDogJHt1cmx9YClcbn1cblxuY29uc3QgbmVnb3RpYXRlRGVjb2RlciA9IGZ1bmN0aW9uIChkZWNvZGVycywgY29udGVudFR5cGUpIHtcbiAgaWYgKGNvbnRlbnRUeXBlID09PSB1bmRlZmluZWQgfHwgY29udGVudFR5cGUgPT09IG51bGwpIHtcbiAgICByZXR1cm4gZGVjb2RlcnNbMF1cbiAgfVxuXG4gIGNvbnN0IGZ1bGxUeXBlID0gY29udGVudFR5cGUudG9Mb3dlckNhc2UoKS5zcGxpdCgnOycpWzBdLnRyaW0oKVxuICBjb25zdCBtYWluVHlwZSA9IGZ1bGxUeXBlLnNwbGl0KCcvJylbMF0gKyAnLyonXG4gIGNvbnN0IHdpbGRjYXJkVHlwZSA9ICcqLyonXG4gIGNvbnN0IGFjY2VwdGFibGVUeXBlcyA9IFtmdWxsVHlwZSwgbWFpblR5cGUsIHdpbGRjYXJkVHlwZV1cblxuICBmb3IgKGxldCBkZWNvZGVyIG9mIGRlY29kZXJzKSB7XG4gICAgaWYgKGFjY2VwdGFibGVUeXBlcy5pbmNsdWRlcyhkZWNvZGVyLm1lZGlhVHlwZSkpIHtcbiAgICAgIHJldHVybiBkZWNvZGVyXG4gICAgfVxuICB9XG5cbiAgdGhyb3cgRXJyb3IoYFVuc3VwcG9ydGVkIG1lZGlhIGluIENvbnRlbnQtVHlwZSBoZWFkZXI6ICR7Y29udGVudFR5cGV9YClcbn1cblxuY29uc3QgY3NyZlNhZmVNZXRob2QgPSBmdW5jdGlvbiAobWV0aG9kKSB7XG4gIC8vIHRoZXNlIEhUVFAgbWV0aG9kcyBkbyBub3QgcmVxdWlyZSBDU1JGIHByb3RlY3Rpb25cbiAgcmV0dXJuICgvXihHRVR8SEVBRHxPUFRJT05TfFRSQUNFKSQvLnRlc3QobWV0aG9kKSlcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGRldGVybWluZVRyYW5zcG9ydDogZGV0ZXJtaW5lVHJhbnNwb3J0LFxuICBuZWdvdGlhdGVEZWNvZGVyOiBuZWdvdGlhdGVEZWNvZGVyLFxuICBjc3JmU2FmZU1ldGhvZDogY3NyZlNhZmVNZXRob2Rcbn1cbiIsIi8vIHRoZSB3aGF0d2ctZmV0Y2ggcG9seWZpbGwgaW5zdGFsbHMgdGhlIGZldGNoKCkgZnVuY3Rpb25cbi8vIG9uIHRoZSBnbG9iYWwgb2JqZWN0ICh3aW5kb3cgb3Igc2VsZilcbi8vXG4vLyBSZXR1cm4gdGhhdCBhcyB0aGUgZXhwb3J0IGZvciB1c2UgaW4gV2VicGFjaywgQnJvd3NlcmlmeSBldGMuXG5yZXF1aXJlKCd3aGF0d2ctZmV0Y2gnKTtcbm1vZHVsZS5leHBvcnRzID0gc2VsZi5mZXRjaC5iaW5kKHNlbGYpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaGFzID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuLyoqXG4gKiBTaW1wbGUgcXVlcnkgc3RyaW5nIHBhcnNlci5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcXVlcnkgVGhlIHF1ZXJ5IHN0cmluZyB0aGF0IG5lZWRzIHRvIGJlIHBhcnNlZC5cbiAqIEByZXR1cm5zIHtPYmplY3R9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5mdW5jdGlvbiBxdWVyeXN0cmluZyhxdWVyeSkge1xuICB2YXIgcGFyc2VyID0gLyhbXj0/Jl0rKT0/KFteJl0qKS9nXG4gICAgLCByZXN1bHQgPSB7fVxuICAgICwgcGFydDtcblxuICAvL1xuICAvLyBMaXR0bGUgbmlmdHkgcGFyc2luZyBoYWNrLCBsZXZlcmFnZSB0aGUgZmFjdCB0aGF0IFJlZ0V4cC5leGVjIGluY3JlbWVudHNcbiAgLy8gdGhlIGxhc3RJbmRleCBwcm9wZXJ0eSBzbyB3ZSBjYW4gY29udGludWUgZXhlY3V0aW5nIHRoaXMgbG9vcCB1bnRpbCB3ZSd2ZVxuICAvLyBwYXJzZWQgYWxsIHJlc3VsdHMuXG4gIC8vXG4gIGZvciAoO1xuICAgIHBhcnQgPSBwYXJzZXIuZXhlYyhxdWVyeSk7XG4gICAgcmVzdWx0W2RlY29kZVVSSUNvbXBvbmVudChwYXJ0WzFdKV0gPSBkZWNvZGVVUklDb21wb25lbnQocGFydFsyXSlcbiAgKTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIFRyYW5zZm9ybSBhIHF1ZXJ5IHN0cmluZyB0byBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iaiBPYmplY3QgdGhhdCBzaG91bGQgYmUgdHJhbnNmb3JtZWQuXG4gKiBAcGFyYW0ge1N0cmluZ30gcHJlZml4IE9wdGlvbmFsIHByZWZpeC5cbiAqIEByZXR1cm5zIHtTdHJpbmd9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5mdW5jdGlvbiBxdWVyeXN0cmluZ2lmeShvYmosIHByZWZpeCkge1xuICBwcmVmaXggPSBwcmVmaXggfHwgJyc7XG5cbiAgdmFyIHBhaXJzID0gW107XG5cbiAgLy9cbiAgLy8gT3B0aW9uYWxseSBwcmVmaXggd2l0aCBhICc/JyBpZiBuZWVkZWRcbiAgLy9cbiAgaWYgKCdzdHJpbmcnICE9PSB0eXBlb2YgcHJlZml4KSBwcmVmaXggPSAnPyc7XG5cbiAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgIGlmIChoYXMuY2FsbChvYmosIGtleSkpIHtcbiAgICAgIHBhaXJzLnB1c2goZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgKyc9JysgZW5jb2RlVVJJQ29tcG9uZW50KG9ialtrZXldKSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHBhaXJzLmxlbmd0aCA/IHByZWZpeCArIHBhaXJzLmpvaW4oJyYnKSA6ICcnO1xufVxuXG4vL1xuLy8gRXhwb3NlIHRoZSBtb2R1bGUuXG4vL1xuZXhwb3J0cy5zdHJpbmdpZnkgPSBxdWVyeXN0cmluZ2lmeTtcbmV4cG9ydHMucGFyc2UgPSBxdWVyeXN0cmluZztcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBDaGVjayBpZiB3ZSdyZSByZXF1aXJlZCB0byBhZGQgYSBwb3J0IG51bWJlci5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vdXJsLnNwZWMud2hhdHdnLm9yZy8jZGVmYXVsdC1wb3J0XG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd9IHBvcnQgUG9ydCBudW1iZXIgd2UgbmVlZCB0byBjaGVja1xuICogQHBhcmFtIHtTdHJpbmd9IHByb3RvY29sIFByb3RvY29sIHdlIG5lZWQgdG8gY2hlY2sgYWdhaW5zdC5cbiAqIEByZXR1cm5zIHtCb29sZWFufSBJcyBpdCBhIGRlZmF1bHQgcG9ydCBmb3IgdGhlIGdpdmVuIHByb3RvY29sXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiByZXF1aXJlZChwb3J0LCBwcm90b2NvbCkge1xuICBwcm90b2NvbCA9IHByb3RvY29sLnNwbGl0KCc6JylbMF07XG4gIHBvcnQgPSArcG9ydDtcblxuICBpZiAoIXBvcnQpIHJldHVybiBmYWxzZTtcblxuICBzd2l0Y2ggKHByb3RvY29sKSB7XG4gICAgY2FzZSAnaHR0cCc6XG4gICAgY2FzZSAnd3MnOlxuICAgIHJldHVybiBwb3J0ICE9PSA4MDtcblxuICAgIGNhc2UgJ2h0dHBzJzpcbiAgICBjYXNlICd3c3MnOlxuICAgIHJldHVybiBwb3J0ICE9PSA0NDM7XG5cbiAgICBjYXNlICdmdHAnOlxuICAgIHJldHVybiBwb3J0ICE9PSAyMTtcblxuICAgIGNhc2UgJ2dvcGhlcic6XG4gICAgcmV0dXJuIHBvcnQgIT09IDcwO1xuXG4gICAgY2FzZSAnZmlsZSc6XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIHBvcnQgIT09IDA7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcmVxdWlyZWQgPSByZXF1aXJlKCdyZXF1aXJlcy1wb3J0JylcbiAgLCBsb2xjYXRpb24gPSByZXF1aXJlKCcuL2xvbGNhdGlvbicpXG4gICwgcXMgPSByZXF1aXJlKCdxdWVyeXN0cmluZ2lmeScpXG4gICwgcHJvdG9jb2xyZSA9IC9eKFthLXpdW2EtejAtOS4rLV0qOik/KFxcL1xcLyk/KFtcXFNcXHNdKikvaTtcblxuLyoqXG4gKiBUaGVzZSBhcmUgdGhlIHBhcnNlIHJ1bGVzIGZvciB0aGUgVVJMIHBhcnNlciwgaXQgaW5mb3JtcyB0aGUgcGFyc2VyXG4gKiBhYm91dDpcbiAqXG4gKiAwLiBUaGUgY2hhciBpdCBOZWVkcyB0byBwYXJzZSwgaWYgaXQncyBhIHN0cmluZyBpdCBzaG91bGQgYmUgZG9uZSB1c2luZ1xuICogICAgaW5kZXhPZiwgUmVnRXhwIHVzaW5nIGV4ZWMgYW5kIE5hTiBtZWFucyBzZXQgYXMgY3VycmVudCB2YWx1ZS5cbiAqIDEuIFRoZSBwcm9wZXJ0eSB3ZSBzaG91bGQgc2V0IHdoZW4gcGFyc2luZyB0aGlzIHZhbHVlLlxuICogMi4gSW5kaWNhdGlvbiBpZiBpdCdzIGJhY2t3YXJkcyBvciBmb3J3YXJkIHBhcnNpbmcsIHdoZW4gc2V0IGFzIG51bWJlciBpdCdzXG4gKiAgICB0aGUgdmFsdWUgb2YgZXh0cmEgY2hhcnMgdGhhdCBzaG91bGQgYmUgc3BsaXQgb2ZmLlxuICogMy4gSW5oZXJpdCBmcm9tIGxvY2F0aW9uIGlmIG5vbiBleGlzdGluZyBpbiB0aGUgcGFyc2VyLlxuICogNC4gYHRvTG93ZXJDYXNlYCB0aGUgcmVzdWx0aW5nIHZhbHVlLlxuICovXG52YXIgcnVsZXMgPSBbXG4gIFsnIycsICdoYXNoJ10sICAgICAgICAgICAgICAgICAgICAgICAgLy8gRXh0cmFjdCBmcm9tIHRoZSBiYWNrLlxuICBbJz8nLCAncXVlcnknXSwgICAgICAgICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgZnJvbSB0aGUgYmFjay5cbiAgWycvJywgJ3BhdGhuYW1lJ10sICAgICAgICAgICAgICAgICAgICAvLyBFeHRyYWN0IGZyb20gdGhlIGJhY2suXG4gIFsnQCcsICdhdXRoJywgMV0sICAgICAgICAgICAgICAgICAgICAgLy8gRXh0cmFjdCBmcm9tIHRoZSBmcm9udC5cbiAgW05hTiwgJ2hvc3QnLCB1bmRlZmluZWQsIDEsIDFdLCAgICAgICAvLyBTZXQgbGVmdCBvdmVyIHZhbHVlLlxuICBbLzooXFxkKykkLywgJ3BvcnQnLCB1bmRlZmluZWQsIDFdLCAgICAvLyBSZWdFeHAgdGhlIGJhY2suXG4gIFtOYU4sICdob3N0bmFtZScsIHVuZGVmaW5lZCwgMSwgMV0gICAgLy8gU2V0IGxlZnQgb3Zlci5cbl07XG5cbi8qKlxuICogQHR5cGVkZWYgUHJvdG9jb2xFeHRyYWN0XG4gKiBAdHlwZSBPYmplY3RcbiAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBwcm90b2NvbCBQcm90b2NvbCBtYXRjaGVkIGluIHRoZSBVUkwsIGluIGxvd2VyY2FzZS5cbiAqIEBwcm9wZXJ0eSB7Qm9vbGVhbn0gc2xhc2hlcyBgdHJ1ZWAgaWYgcHJvdG9jb2wgaXMgZm9sbG93ZWQgYnkgXCIvL1wiLCBlbHNlIGBmYWxzZWAuXG4gKiBAcHJvcGVydHkge1N0cmluZ30gcmVzdCBSZXN0IG9mIHRoZSBVUkwgdGhhdCBpcyBub3QgcGFydCBvZiB0aGUgcHJvdG9jb2wuXG4gKi9cblxuLyoqXG4gKiBFeHRyYWN0IHByb3RvY29sIGluZm9ybWF0aW9uIGZyb20gYSBVUkwgd2l0aC93aXRob3V0IGRvdWJsZSBzbGFzaCAoXCIvL1wiKS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyBVUkwgd2Ugd2FudCB0byBleHRyYWN0IGZyb20uXG4gKiBAcmV0dXJuIHtQcm90b2NvbEV4dHJhY3R9IEV4dHJhY3RlZCBpbmZvcm1hdGlvbi5cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBleHRyYWN0UHJvdG9jb2woYWRkcmVzcykge1xuICB2YXIgbWF0Y2ggPSBwcm90b2NvbHJlLmV4ZWMoYWRkcmVzcyk7XG5cbiAgcmV0dXJuIHtcbiAgICBwcm90b2NvbDogbWF0Y2hbMV0gPyBtYXRjaFsxXS50b0xvd2VyQ2FzZSgpIDogJycsXG4gICAgc2xhc2hlczogISFtYXRjaFsyXSxcbiAgICByZXN0OiBtYXRjaFszXVxuICB9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSByZWxhdGl2ZSBVUkwgcGF0aG5hbWUgYWdhaW5zdCBhIGJhc2UgVVJMIHBhdGhuYW1lLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSByZWxhdGl2ZSBQYXRobmFtZSBvZiB0aGUgcmVsYXRpdmUgVVJMLlxuICogQHBhcmFtIHtTdHJpbmd9IGJhc2UgUGF0aG5hbWUgb2YgdGhlIGJhc2UgVVJMLlxuICogQHJldHVybiB7U3RyaW5nfSBSZXNvbHZlZCBwYXRobmFtZS5cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiByZXNvbHZlKHJlbGF0aXZlLCBiYXNlKSB7XG4gIHZhciBwYXRoID0gKGJhc2UgfHwgJy8nKS5zcGxpdCgnLycpLnNsaWNlKDAsIC0xKS5jb25jYXQocmVsYXRpdmUuc3BsaXQoJy8nKSlcbiAgICAsIGkgPSBwYXRoLmxlbmd0aFxuICAgICwgbGFzdCA9IHBhdGhbaSAtIDFdXG4gICAgLCB1bnNoaWZ0ID0gZmFsc2VcbiAgICAsIHVwID0gMDtcblxuICB3aGlsZSAoaS0tKSB7XG4gICAgaWYgKHBhdGhbaV0gPT09ICcuJykge1xuICAgICAgcGF0aC5zcGxpY2UoaSwgMSk7XG4gICAgfSBlbHNlIGlmIChwYXRoW2ldID09PSAnLi4nKSB7XG4gICAgICBwYXRoLnNwbGljZShpLCAxKTtcbiAgICAgIHVwKys7XG4gICAgfSBlbHNlIGlmICh1cCkge1xuICAgICAgaWYgKGkgPT09IDApIHVuc2hpZnQgPSB0cnVlO1xuICAgICAgcGF0aC5zcGxpY2UoaSwgMSk7XG4gICAgICB1cC0tO1xuICAgIH1cbiAgfVxuXG4gIGlmICh1bnNoaWZ0KSBwYXRoLnVuc2hpZnQoJycpO1xuICBpZiAobGFzdCA9PT0gJy4nIHx8IGxhc3QgPT09ICcuLicpIHBhdGgucHVzaCgnJyk7XG5cbiAgcmV0dXJuIHBhdGguam9pbignLycpO1xufVxuXG4vKipcbiAqIFRoZSBhY3R1YWwgVVJMIGluc3RhbmNlLiBJbnN0ZWFkIG9mIHJldHVybmluZyBhbiBvYmplY3Qgd2UndmUgb3B0ZWQtaW4gdG9cbiAqIGNyZWF0ZSBhbiBhY3R1YWwgY29uc3RydWN0b3IgYXMgaXQncyBtdWNoIG1vcmUgbWVtb3J5IGVmZmljaWVudCBhbmRcbiAqIGZhc3RlciBhbmQgaXQgcGxlYXNlcyBteSBPQ0QuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyBVUkwgd2Ugd2FudCB0byBwYXJzZS5cbiAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gbG9jYXRpb24gTG9jYXRpb24gZGVmYXVsdHMgZm9yIHJlbGF0aXZlIHBhdGhzLlxuICogQHBhcmFtIHtCb29sZWFufEZ1bmN0aW9ufSBwYXJzZXIgUGFyc2VyIGZvciB0aGUgcXVlcnkgc3RyaW5nLlxuICogQGFwaSBwdWJsaWNcbiAqL1xuZnVuY3Rpb24gVVJMKGFkZHJlc3MsIGxvY2F0aW9uLCBwYXJzZXIpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFVSTCkpIHtcbiAgICByZXR1cm4gbmV3IFVSTChhZGRyZXNzLCBsb2NhdGlvbiwgcGFyc2VyKTtcbiAgfVxuXG4gIHZhciByZWxhdGl2ZSwgZXh0cmFjdGVkLCBwYXJzZSwgaW5zdHJ1Y3Rpb24sIGluZGV4LCBrZXlcbiAgICAsIGluc3RydWN0aW9ucyA9IHJ1bGVzLnNsaWNlKClcbiAgICAsIHR5cGUgPSB0eXBlb2YgbG9jYXRpb25cbiAgICAsIHVybCA9IHRoaXNcbiAgICAsIGkgPSAwO1xuXG4gIC8vXG4gIC8vIFRoZSBmb2xsb3dpbmcgaWYgc3RhdGVtZW50cyBhbGxvd3MgdGhpcyBtb2R1bGUgdHdvIGhhdmUgY29tcGF0aWJpbGl0eSB3aXRoXG4gIC8vIDIgZGlmZmVyZW50IEFQSTpcbiAgLy9cbiAgLy8gMS4gTm9kZS5qcydzIGB1cmwucGFyc2VgIGFwaSB3aGljaCBhY2NlcHRzIGEgVVJMLCBib29sZWFuIGFzIGFyZ3VtZW50c1xuICAvLyAgICB3aGVyZSB0aGUgYm9vbGVhbiBpbmRpY2F0ZXMgdGhhdCB0aGUgcXVlcnkgc3RyaW5nIHNob3VsZCBhbHNvIGJlIHBhcnNlZC5cbiAgLy9cbiAgLy8gMi4gVGhlIGBVUkxgIGludGVyZmFjZSBvZiB0aGUgYnJvd3NlciB3aGljaCBhY2NlcHRzIGEgVVJMLCBvYmplY3QgYXNcbiAgLy8gICAgYXJndW1lbnRzLiBUaGUgc3VwcGxpZWQgb2JqZWN0IHdpbGwgYmUgdXNlZCBhcyBkZWZhdWx0IHZhbHVlcyAvIGZhbGwtYmFja1xuICAvLyAgICBmb3IgcmVsYXRpdmUgcGF0aHMuXG4gIC8vXG4gIGlmICgnb2JqZWN0JyAhPT0gdHlwZSAmJiAnc3RyaW5nJyAhPT0gdHlwZSkge1xuICAgIHBhcnNlciA9IGxvY2F0aW9uO1xuICAgIGxvY2F0aW9uID0gbnVsbDtcbiAgfVxuXG4gIGlmIChwYXJzZXIgJiYgJ2Z1bmN0aW9uJyAhPT0gdHlwZW9mIHBhcnNlcikgcGFyc2VyID0gcXMucGFyc2U7XG5cbiAgbG9jYXRpb24gPSBsb2xjYXRpb24obG9jYXRpb24pO1xuXG4gIC8vXG4gIC8vIEV4dHJhY3QgcHJvdG9jb2wgaW5mb3JtYXRpb24gYmVmb3JlIHJ1bm5pbmcgdGhlIGluc3RydWN0aW9ucy5cbiAgLy9cbiAgZXh0cmFjdGVkID0gZXh0cmFjdFByb3RvY29sKGFkZHJlc3MgfHwgJycpO1xuICByZWxhdGl2ZSA9ICFleHRyYWN0ZWQucHJvdG9jb2wgJiYgIWV4dHJhY3RlZC5zbGFzaGVzO1xuICB1cmwuc2xhc2hlcyA9IGV4dHJhY3RlZC5zbGFzaGVzIHx8IHJlbGF0aXZlICYmIGxvY2F0aW9uLnNsYXNoZXM7XG4gIHVybC5wcm90b2NvbCA9IGV4dHJhY3RlZC5wcm90b2NvbCB8fCBsb2NhdGlvbi5wcm90b2NvbCB8fCAnJztcbiAgYWRkcmVzcyA9IGV4dHJhY3RlZC5yZXN0O1xuXG4gIC8vXG4gIC8vIFdoZW4gdGhlIGF1dGhvcml0eSBjb21wb25lbnQgaXMgYWJzZW50IHRoZSBVUkwgc3RhcnRzIHdpdGggYSBwYXRoXG4gIC8vIGNvbXBvbmVudC5cbiAgLy9cbiAgaWYgKCFleHRyYWN0ZWQuc2xhc2hlcykgaW5zdHJ1Y3Rpb25zWzJdID0gWy8oLiopLywgJ3BhdGhuYW1lJ107XG5cbiAgZm9yICg7IGkgPCBpbnN0cnVjdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICBpbnN0cnVjdGlvbiA9IGluc3RydWN0aW9uc1tpXTtcbiAgICBwYXJzZSA9IGluc3RydWN0aW9uWzBdO1xuICAgIGtleSA9IGluc3RydWN0aW9uWzFdO1xuXG4gICAgaWYgKHBhcnNlICE9PSBwYXJzZSkge1xuICAgICAgdXJsW2tleV0gPSBhZGRyZXNzO1xuICAgIH0gZWxzZSBpZiAoJ3N0cmluZycgPT09IHR5cGVvZiBwYXJzZSkge1xuICAgICAgaWYgKH4oaW5kZXggPSBhZGRyZXNzLmluZGV4T2YocGFyc2UpKSkge1xuICAgICAgICBpZiAoJ251bWJlcicgPT09IHR5cGVvZiBpbnN0cnVjdGlvblsyXSkge1xuICAgICAgICAgIHVybFtrZXldID0gYWRkcmVzcy5zbGljZSgwLCBpbmRleCk7XG4gICAgICAgICAgYWRkcmVzcyA9IGFkZHJlc3Muc2xpY2UoaW5kZXggKyBpbnN0cnVjdGlvblsyXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdXJsW2tleV0gPSBhZGRyZXNzLnNsaWNlKGluZGV4KTtcbiAgICAgICAgICBhZGRyZXNzID0gYWRkcmVzcy5zbGljZSgwLCBpbmRleCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGluZGV4ID0gcGFyc2UuZXhlYyhhZGRyZXNzKSkge1xuICAgICAgdXJsW2tleV0gPSBpbmRleFsxXTtcbiAgICAgIGFkZHJlc3MgPSBhZGRyZXNzLnNsaWNlKDAsIGluZGV4LmluZGV4KTtcbiAgICB9XG5cbiAgICB1cmxba2V5XSA9IHVybFtrZXldIHx8IChcbiAgICAgIHJlbGF0aXZlICYmIGluc3RydWN0aW9uWzNdID8gbG9jYXRpb25ba2V5XSB8fCAnJyA6ICcnXG4gICAgKTtcblxuICAgIC8vXG4gICAgLy8gSG9zdG5hbWUsIGhvc3QgYW5kIHByb3RvY29sIHNob3VsZCBiZSBsb3dlcmNhc2VkIHNvIHRoZXkgY2FuIGJlIHVzZWQgdG9cbiAgICAvLyBjcmVhdGUgYSBwcm9wZXIgYG9yaWdpbmAuXG4gICAgLy9cbiAgICBpZiAoaW5zdHJ1Y3Rpb25bNF0pIHVybFtrZXldID0gdXJsW2tleV0udG9Mb3dlckNhc2UoKTtcbiAgfVxuXG4gIC8vXG4gIC8vIEFsc28gcGFyc2UgdGhlIHN1cHBsaWVkIHF1ZXJ5IHN0cmluZyBpbiB0byBhbiBvYmplY3QuIElmIHdlJ3JlIHN1cHBsaWVkXG4gIC8vIHdpdGggYSBjdXN0b20gcGFyc2VyIGFzIGZ1bmN0aW9uIHVzZSB0aGF0IGluc3RlYWQgb2YgdGhlIGRlZmF1bHQgYnVpbGQtaW5cbiAgLy8gcGFyc2VyLlxuICAvL1xuICBpZiAocGFyc2VyKSB1cmwucXVlcnkgPSBwYXJzZXIodXJsLnF1ZXJ5KTtcblxuICAvL1xuICAvLyBJZiB0aGUgVVJMIGlzIHJlbGF0aXZlLCByZXNvbHZlIHRoZSBwYXRobmFtZSBhZ2FpbnN0IHRoZSBiYXNlIFVSTC5cbiAgLy9cbiAgaWYgKFxuICAgICAgcmVsYXRpdmVcbiAgICAmJiBsb2NhdGlvbi5zbGFzaGVzXG4gICAgJiYgdXJsLnBhdGhuYW1lLmNoYXJBdCgwKSAhPT0gJy8nXG4gICAgJiYgKHVybC5wYXRobmFtZSAhPT0gJycgfHwgbG9jYXRpb24ucGF0aG5hbWUgIT09ICcnKVxuICApIHtcbiAgICB1cmwucGF0aG5hbWUgPSByZXNvbHZlKHVybC5wYXRobmFtZSwgbG9jYXRpb24ucGF0aG5hbWUpO1xuICB9XG5cbiAgLy9cbiAgLy8gV2Ugc2hvdWxkIG5vdCBhZGQgcG9ydCBudW1iZXJzIGlmIHRoZXkgYXJlIGFscmVhZHkgdGhlIGRlZmF1bHQgcG9ydCBudW1iZXJcbiAgLy8gZm9yIGEgZ2l2ZW4gcHJvdG9jb2wuIEFzIHRoZSBob3N0IGFsc28gY29udGFpbnMgdGhlIHBvcnQgbnVtYmVyIHdlJ3JlIGdvaW5nXG4gIC8vIG92ZXJyaWRlIGl0IHdpdGggdGhlIGhvc3RuYW1lIHdoaWNoIGNvbnRhaW5zIG5vIHBvcnQgbnVtYmVyLlxuICAvL1xuICBpZiAoIXJlcXVpcmVkKHVybC5wb3J0LCB1cmwucHJvdG9jb2wpKSB7XG4gICAgdXJsLmhvc3QgPSB1cmwuaG9zdG5hbWU7XG4gICAgdXJsLnBvcnQgPSAnJztcbiAgfVxuXG4gIC8vXG4gIC8vIFBhcnNlIGRvd24gdGhlIGBhdXRoYCBmb3IgdGhlIHVzZXJuYW1lIGFuZCBwYXNzd29yZC5cbiAgLy9cbiAgdXJsLnVzZXJuYW1lID0gdXJsLnBhc3N3b3JkID0gJyc7XG4gIGlmICh1cmwuYXV0aCkge1xuICAgIGluc3RydWN0aW9uID0gdXJsLmF1dGguc3BsaXQoJzonKTtcbiAgICB1cmwudXNlcm5hbWUgPSBpbnN0cnVjdGlvblswXSB8fCAnJztcbiAgICB1cmwucGFzc3dvcmQgPSBpbnN0cnVjdGlvblsxXSB8fCAnJztcbiAgfVxuXG4gIHVybC5vcmlnaW4gPSB1cmwucHJvdG9jb2wgJiYgdXJsLmhvc3QgJiYgdXJsLnByb3RvY29sICE9PSAnZmlsZTonXG4gICAgPyB1cmwucHJvdG9jb2wgKycvLycrIHVybC5ob3N0XG4gICAgOiAnbnVsbCc7XG5cbiAgLy9cbiAgLy8gVGhlIGhyZWYgaXMganVzdCB0aGUgY29tcGlsZWQgcmVzdWx0LlxuICAvL1xuICB1cmwuaHJlZiA9IHVybC50b1N0cmluZygpO1xufVxuXG4vKipcbiAqIFRoaXMgaXMgY29udmVuaWVuY2UgbWV0aG9kIGZvciBjaGFuZ2luZyBwcm9wZXJ0aWVzIGluIHRoZSBVUkwgaW5zdGFuY2UgdG9cbiAqIGluc3VyZSB0aGF0IHRoZXkgYWxsIHByb3BhZ2F0ZSBjb3JyZWN0bHkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBhcnQgICAgICAgICAgUHJvcGVydHkgd2UgbmVlZCB0byBhZGp1c3QuXG4gKiBAcGFyYW0ge01peGVkfSB2YWx1ZSAgICAgICAgICBUaGUgbmV3bHkgYXNzaWduZWQgdmFsdWUuXG4gKiBAcGFyYW0ge0Jvb2xlYW58RnVuY3Rpb259IGZuICBXaGVuIHNldHRpbmcgdGhlIHF1ZXJ5LCBpdCB3aWxsIGJlIHRoZSBmdW5jdGlvblxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlZCB0byBwYXJzZSB0aGUgcXVlcnkuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXaGVuIHNldHRpbmcgdGhlIHByb3RvY29sLCBkb3VibGUgc2xhc2ggd2lsbCBiZVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlZCBmcm9tIHRoZSBmaW5hbCB1cmwgaWYgaXQgaXMgdHJ1ZS5cbiAqIEByZXR1cm5zIHtVUkx9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5VUkwucHJvdG90eXBlLnNldCA9IGZ1bmN0aW9uIHNldChwYXJ0LCB2YWx1ZSwgZm4pIHtcbiAgdmFyIHVybCA9IHRoaXM7XG5cbiAgc3dpdGNoIChwYXJ0KSB7XG4gICAgY2FzZSAncXVlcnknOlxuICAgICAgaWYgKCdzdHJpbmcnID09PSB0eXBlb2YgdmFsdWUgJiYgdmFsdWUubGVuZ3RoKSB7XG4gICAgICAgIHZhbHVlID0gKGZuIHx8IHFzLnBhcnNlKSh2YWx1ZSk7XG4gICAgICB9XG5cbiAgICAgIHVybFtwYXJ0XSA9IHZhbHVlO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdwb3J0JzpcbiAgICAgIHVybFtwYXJ0XSA9IHZhbHVlO1xuXG4gICAgICBpZiAoIXJlcXVpcmVkKHZhbHVlLCB1cmwucHJvdG9jb2wpKSB7XG4gICAgICAgIHVybC5ob3N0ID0gdXJsLmhvc3RuYW1lO1xuICAgICAgICB1cmxbcGFydF0gPSAnJztcbiAgICAgIH0gZWxzZSBpZiAodmFsdWUpIHtcbiAgICAgICAgdXJsLmhvc3QgPSB1cmwuaG9zdG5hbWUgKyc6JysgdmFsdWU7XG4gICAgICB9XG5cbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAnaG9zdG5hbWUnOlxuICAgICAgdXJsW3BhcnRdID0gdmFsdWU7XG5cbiAgICAgIGlmICh1cmwucG9ydCkgdmFsdWUgKz0gJzonKyB1cmwucG9ydDtcbiAgICAgIHVybC5ob3N0ID0gdmFsdWU7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ2hvc3QnOlxuICAgICAgdXJsW3BhcnRdID0gdmFsdWU7XG5cbiAgICAgIGlmICgvOlxcZCskLy50ZXN0KHZhbHVlKSkge1xuICAgICAgICB2YWx1ZSA9IHZhbHVlLnNwbGl0KCc6Jyk7XG4gICAgICAgIHVybC5wb3J0ID0gdmFsdWUucG9wKCk7XG4gICAgICAgIHVybC5ob3N0bmFtZSA9IHZhbHVlLmpvaW4oJzonKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHVybC5ob3N0bmFtZSA9IHZhbHVlO1xuICAgICAgICB1cmwucG9ydCA9ICcnO1xuICAgICAgfVxuXG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3Byb3RvY29sJzpcbiAgICAgIHVybC5wcm90b2NvbCA9IHZhbHVlLnRvTG93ZXJDYXNlKCk7XG4gICAgICB1cmwuc2xhc2hlcyA9ICFmbjtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAncGF0aG5hbWUnOlxuICAgICAgdXJsLnBhdGhuYW1lID0gdmFsdWUubGVuZ3RoICYmIHZhbHVlLmNoYXJBdCgwKSAhPT0gJy8nID8gJy8nICsgdmFsdWUgOiB2YWx1ZTtcblxuICAgICAgYnJlYWs7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgdXJsW3BhcnRdID0gdmFsdWU7XG4gIH1cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHJ1bGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGlucyA9IHJ1bGVzW2ldO1xuXG4gICAgaWYgKGluc1s0XSkgdXJsW2luc1sxXV0gPSB1cmxbaW5zWzFdXS50b0xvd2VyQ2FzZSgpO1xuICB9XG5cbiAgdXJsLm9yaWdpbiA9IHVybC5wcm90b2NvbCAmJiB1cmwuaG9zdCAmJiB1cmwucHJvdG9jb2wgIT09ICdmaWxlOidcbiAgICA/IHVybC5wcm90b2NvbCArJy8vJysgdXJsLmhvc3RcbiAgICA6ICdudWxsJztcblxuICB1cmwuaHJlZiA9IHVybC50b1N0cmluZygpO1xuXG4gIHJldHVybiB1cmw7XG59O1xuXG4vKipcbiAqIFRyYW5zZm9ybSB0aGUgcHJvcGVydGllcyBiYWNrIGluIHRvIGEgdmFsaWQgYW5kIGZ1bGwgVVJMIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdHJpbmdpZnkgT3B0aW9uYWwgcXVlcnkgc3RyaW5naWZ5IGZ1bmN0aW9uLlxuICogQHJldHVybnMge1N0cmluZ31cbiAqIEBhcGkgcHVibGljXG4gKi9cblVSTC5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyhzdHJpbmdpZnkpIHtcbiAgaWYgKCFzdHJpbmdpZnkgfHwgJ2Z1bmN0aW9uJyAhPT0gdHlwZW9mIHN0cmluZ2lmeSkgc3RyaW5naWZ5ID0gcXMuc3RyaW5naWZ5O1xuXG4gIHZhciBxdWVyeVxuICAgICwgdXJsID0gdGhpc1xuICAgICwgcHJvdG9jb2wgPSB1cmwucHJvdG9jb2w7XG5cbiAgaWYgKHByb3RvY29sICYmIHByb3RvY29sLmNoYXJBdChwcm90b2NvbC5sZW5ndGggLSAxKSAhPT0gJzonKSBwcm90b2NvbCArPSAnOic7XG5cbiAgdmFyIHJlc3VsdCA9IHByb3RvY29sICsgKHVybC5zbGFzaGVzID8gJy8vJyA6ICcnKTtcblxuICBpZiAodXJsLnVzZXJuYW1lKSB7XG4gICAgcmVzdWx0ICs9IHVybC51c2VybmFtZTtcbiAgICBpZiAodXJsLnBhc3N3b3JkKSByZXN1bHQgKz0gJzonKyB1cmwucGFzc3dvcmQ7XG4gICAgcmVzdWx0ICs9ICdAJztcbiAgfVxuXG4gIHJlc3VsdCArPSB1cmwuaG9zdCArIHVybC5wYXRobmFtZTtcblxuICBxdWVyeSA9ICdvYmplY3QnID09PSB0eXBlb2YgdXJsLnF1ZXJ5ID8gc3RyaW5naWZ5KHVybC5xdWVyeSkgOiB1cmwucXVlcnk7XG4gIGlmIChxdWVyeSkgcmVzdWx0ICs9ICc/JyAhPT0gcXVlcnkuY2hhckF0KDApID8gJz8nKyBxdWVyeSA6IHF1ZXJ5O1xuXG4gIGlmICh1cmwuaGFzaCkgcmVzdWx0ICs9IHVybC5oYXNoO1xuXG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBVUkwgcGFyc2VyIGFuZCBzb21lIGFkZGl0aW9uYWwgcHJvcGVydGllcyB0aGF0IG1pZ2h0IGJlIHVzZWZ1bCBmb3Jcbi8vIG90aGVycyBvciB0ZXN0aW5nLlxuLy9cblVSTC5leHRyYWN0UHJvdG9jb2wgPSBleHRyYWN0UHJvdG9jb2w7XG5VUkwubG9jYXRpb24gPSBsb2xjYXRpb247XG5VUkwucXMgPSBxcztcblxubW9kdWxlLmV4cG9ydHMgPSBVUkw7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBzbGFzaGVzID0gL15bQS1aYS16XVtBLVphLXowLTkrLS5dKjpcXC9cXC8vO1xuXG4vKipcbiAqIFRoZXNlIHByb3BlcnRpZXMgc2hvdWxkIG5vdCBiZSBjb3BpZWQgb3IgaW5oZXJpdGVkIGZyb20uIFRoaXMgaXMgb25seSBuZWVkZWRcbiAqIGZvciBhbGwgbm9uIGJsb2IgVVJMJ3MgYXMgYSBibG9iIFVSTCBkb2VzIG5vdCBpbmNsdWRlIGEgaGFzaCwgb25seSB0aGVcbiAqIG9yaWdpbi5cbiAqXG4gKiBAdHlwZSB7T2JqZWN0fVxuICogQHByaXZhdGVcbiAqL1xudmFyIGlnbm9yZSA9IHsgaGFzaDogMSwgcXVlcnk6IDEgfVxuICAsIFVSTDtcblxuLyoqXG4gKiBUaGUgbG9jYXRpb24gb2JqZWN0IGRpZmZlcnMgd2hlbiB5b3VyIGNvZGUgaXMgbG9hZGVkIHRocm91Z2ggYSBub3JtYWwgcGFnZSxcbiAqIFdvcmtlciBvciB0aHJvdWdoIGEgd29ya2VyIHVzaW5nIGEgYmxvYi4gQW5kIHdpdGggdGhlIGJsb2JibGUgYmVnaW5zIHRoZVxuICogdHJvdWJsZSBhcyB0aGUgbG9jYXRpb24gb2JqZWN0IHdpbGwgY29udGFpbiB0aGUgVVJMIG9mIHRoZSBibG9iLCBub3QgdGhlXG4gKiBsb2NhdGlvbiBvZiB0aGUgcGFnZSB3aGVyZSBvdXIgY29kZSBpcyBsb2FkZWQgaW4uIFRoZSBhY3R1YWwgb3JpZ2luIGlzXG4gKiBlbmNvZGVkIGluIHRoZSBgcGF0aG5hbWVgIHNvIHdlIGNhbiB0aGFua2Z1bGx5IGdlbmVyYXRlIGEgZ29vZCBcImRlZmF1bHRcIlxuICogbG9jYXRpb24gZnJvbSBpdCBzbyB3ZSBjYW4gZ2VuZXJhdGUgcHJvcGVyIHJlbGF0aXZlIFVSTCdzIGFnYWluLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gbG9jIE9wdGlvbmFsIGRlZmF1bHQgbG9jYXRpb24gb2JqZWN0LlxuICogQHJldHVybnMge09iamVjdH0gbG9sY2F0aW9uIG9iamVjdC5cbiAqIEBhcGkgcHVibGljXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gbG9sY2F0aW9uKGxvYykge1xuICBsb2MgPSBsb2MgfHwgZ2xvYmFsLmxvY2F0aW9uIHx8IHt9O1xuICBVUkwgPSBVUkwgfHwgcmVxdWlyZSgnLi8nKTtcblxuICB2YXIgZmluYWxkZXN0aW5hdGlvbiA9IHt9XG4gICAgLCB0eXBlID0gdHlwZW9mIGxvY1xuICAgICwga2V5O1xuXG4gIGlmICgnYmxvYjonID09PSBsb2MucHJvdG9jb2wpIHtcbiAgICBmaW5hbGRlc3RpbmF0aW9uID0gbmV3IFVSTCh1bmVzY2FwZShsb2MucGF0aG5hbWUpLCB7fSk7XG4gIH0gZWxzZSBpZiAoJ3N0cmluZycgPT09IHR5cGUpIHtcbiAgICBmaW5hbGRlc3RpbmF0aW9uID0gbmV3IFVSTChsb2MsIHt9KTtcbiAgICBmb3IgKGtleSBpbiBpZ25vcmUpIGRlbGV0ZSBmaW5hbGRlc3RpbmF0aW9uW2tleV07XG4gIH0gZWxzZSBpZiAoJ29iamVjdCcgPT09IHR5cGUpIHtcbiAgICBmb3IgKGtleSBpbiBsb2MpIHtcbiAgICAgIGlmIChrZXkgaW4gaWdub3JlKSBjb250aW51ZTtcbiAgICAgIGZpbmFsZGVzdGluYXRpb25ba2V5XSA9IGxvY1trZXldO1xuICAgIH1cblxuICAgIGlmIChmaW5hbGRlc3RpbmF0aW9uLnNsYXNoZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgZmluYWxkZXN0aW5hdGlvbi5zbGFzaGVzID0gc2xhc2hlcy50ZXN0KGxvYy5ocmVmKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmluYWxkZXN0aW5hdGlvbjtcbn07XG4iLCIoZnVuY3Rpb24gKHJvb3QsIGZhY3RvcnkpIHtcbiAgICBpZiAodHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgICAgIGRlZmluZShbXSwgZmFjdG9yeSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcm9vdC51cmx0ZW1wbGF0ZSA9IGZhY3RvcnkoKTtcbiAgICB9XG59KHRoaXMsIGZ1bmN0aW9uICgpIHtcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKi9cbiAgZnVuY3Rpb24gVXJsVGVtcGxhdGUoKSB7XG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0clxuICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAqL1xuICBVcmxUZW1wbGF0ZS5wcm90b3R5cGUuZW5jb2RlUmVzZXJ2ZWQgPSBmdW5jdGlvbiAoc3RyKSB7XG4gICAgcmV0dXJuIHN0ci5zcGxpdCgvKCVbMC05QS1GYS1mXXsyfSkvZykubWFwKGZ1bmN0aW9uIChwYXJ0KSB7XG4gICAgICBpZiAoIS8lWzAtOUEtRmEtZl0vLnRlc3QocGFydCkpIHtcbiAgICAgICAgcGFydCA9IGVuY29kZVVSSShwYXJ0KS5yZXBsYWNlKC8lNUIvZywgJ1snKS5yZXBsYWNlKC8lNUQvZywgJ10nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwYXJ0O1xuICAgIH0pLmpvaW4oJycpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyXG4gICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICovXG4gIFVybFRlbXBsYXRlLnByb3RvdHlwZS5lbmNvZGVVbnJlc2VydmVkID0gZnVuY3Rpb24gKHN0cikge1xuICAgIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQoc3RyKS5yZXBsYWNlKC9bIScoKSpdL2csIGZ1bmN0aW9uIChjKSB7XG4gICAgICByZXR1cm4gJyUnICsgYy5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBvcGVyYXRvclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAqL1xuICBVcmxUZW1wbGF0ZS5wcm90b3R5cGUuZW5jb2RlVmFsdWUgPSBmdW5jdGlvbiAob3BlcmF0b3IsIHZhbHVlLCBrZXkpIHtcbiAgICB2YWx1ZSA9IChvcGVyYXRvciA9PT0gJysnIHx8IG9wZXJhdG9yID09PSAnIycpID8gdGhpcy5lbmNvZGVSZXNlcnZlZCh2YWx1ZSkgOiB0aGlzLmVuY29kZVVucmVzZXJ2ZWQodmFsdWUpO1xuXG4gICAgaWYgKGtleSkge1xuICAgICAgcmV0dXJuIHRoaXMuZW5jb2RlVW5yZXNlcnZlZChrZXkpICsgJz0nICsgdmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWVcbiAgICogQHJldHVybiB7Ym9vbGVhbn1cbiAgICovXG4gIFVybFRlbXBsYXRlLnByb3RvdHlwZS5pc0RlZmluZWQgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZSAhPT0gbnVsbDtcbiAgfTtcblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59XG4gICAqL1xuICBVcmxUZW1wbGF0ZS5wcm90b3R5cGUuaXNLZXlPcGVyYXRvciA9IGZ1bmN0aW9uIChvcGVyYXRvcikge1xuICAgIHJldHVybiBvcGVyYXRvciA9PT0gJzsnIHx8IG9wZXJhdG9yID09PSAnJicgfHwgb3BlcmF0b3IgPT09ICc/JztcbiAgfTtcblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9wZXJhdG9yXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1vZGlmaWVyXG4gICAqL1xuICBVcmxUZW1wbGF0ZS5wcm90b3R5cGUuZ2V0VmFsdWVzID0gZnVuY3Rpb24gKGNvbnRleHQsIG9wZXJhdG9yLCBrZXksIG1vZGlmaWVyKSB7XG4gICAgdmFyIHZhbHVlID0gY29udGV4dFtrZXldLFxuICAgICAgICByZXN1bHQgPSBbXTtcblxuICAgIGlmICh0aGlzLmlzRGVmaW5lZCh2YWx1ZSkgJiYgdmFsdWUgIT09ICcnKSB7XG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgIHZhbHVlID0gdmFsdWUudG9TdHJpbmcoKTtcblxuICAgICAgICBpZiAobW9kaWZpZXIgJiYgbW9kaWZpZXIgIT09ICcqJykge1xuICAgICAgICAgIHZhbHVlID0gdmFsdWUuc3Vic3RyaW5nKDAsIHBhcnNlSW50KG1vZGlmaWVyLCAxMCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0LnB1c2godGhpcy5lbmNvZGVWYWx1ZShvcGVyYXRvciwgdmFsdWUsIHRoaXMuaXNLZXlPcGVyYXRvcihvcGVyYXRvcikgPyBrZXkgOiBudWxsKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAobW9kaWZpZXIgPT09ICcqJykge1xuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgdmFsdWUuZmlsdGVyKHRoaXMuaXNEZWZpbmVkKS5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgICByZXN1bHQucHVzaCh0aGlzLmVuY29kZVZhbHVlKG9wZXJhdG9yLCB2YWx1ZSwgdGhpcy5pc0tleU9wZXJhdG9yKG9wZXJhdG9yKSA/IGtleSA6IG51bGwpKTtcbiAgICAgICAgICAgIH0sIHRoaXMpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh2YWx1ZSkuZm9yRWFjaChmdW5jdGlvbiAoaykge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc0RlZmluZWQodmFsdWVba10pKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0LnB1c2godGhpcy5lbmNvZGVWYWx1ZShvcGVyYXRvciwgdmFsdWVba10sIGspKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciB0bXAgPSBbXTtcblxuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgdmFsdWUuZmlsdGVyKHRoaXMuaXNEZWZpbmVkKS5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgICB0bXAucHVzaCh0aGlzLmVuY29kZVZhbHVlKG9wZXJhdG9yLCB2YWx1ZSkpO1xuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHZhbHVlKS5mb3JFYWNoKGZ1bmN0aW9uIChrKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLmlzRGVmaW5lZCh2YWx1ZVtrXSkpIHtcbiAgICAgICAgICAgICAgICB0bXAucHVzaCh0aGlzLmVuY29kZVVucmVzZXJ2ZWQoaykpO1xuICAgICAgICAgICAgICAgIHRtcC5wdXNoKHRoaXMuZW5jb2RlVmFsdWUob3BlcmF0b3IsIHZhbHVlW2tdLnRvU3RyaW5nKCkpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHRoaXMuaXNLZXlPcGVyYXRvcihvcGVyYXRvcikpIHtcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHRoaXMuZW5jb2RlVW5yZXNlcnZlZChrZXkpICsgJz0nICsgdG1wLmpvaW4oJywnKSk7XG4gICAgICAgICAgfSBlbHNlIGlmICh0bXAubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICByZXN1bHQucHVzaCh0bXAuam9pbignLCcpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKG9wZXJhdG9yID09PSAnOycpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNEZWZpbmVkKHZhbHVlKSkge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHRoaXMuZW5jb2RlVW5yZXNlcnZlZChrZXkpKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gJycgJiYgKG9wZXJhdG9yID09PSAnJicgfHwgb3BlcmF0b3IgPT09ICc/JykpIHtcbiAgICAgICAgcmVzdWx0LnB1c2godGhpcy5lbmNvZGVVbnJlc2VydmVkKGtleSkgKyAnPScpO1xuICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gJycpIHtcbiAgICAgICAgcmVzdWx0LnB1c2goJycpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGVtcGxhdGVcbiAgICogQHJldHVybiB7ZnVuY3Rpb24oT2JqZWN0KTpzdHJpbmd9XG4gICAqL1xuICBVcmxUZW1wbGF0ZS5wcm90b3R5cGUucGFyc2UgPSBmdW5jdGlvbiAodGVtcGxhdGUpIHtcbiAgICB2YXIgdGhhdCA9IHRoaXM7XG4gICAgdmFyIG9wZXJhdG9ycyA9IFsnKycsICcjJywgJy4nLCAnLycsICc7JywgJz8nLCAnJiddO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGV4cGFuZDogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHRlbXBsYXRlLnJlcGxhY2UoL1xceyhbXlxce1xcfV0rKVxcfXwoW15cXHtcXH1dKykvZywgZnVuY3Rpb24gKF8sIGV4cHJlc3Npb24sIGxpdGVyYWwpIHtcbiAgICAgICAgICBpZiAoZXhwcmVzc2lvbikge1xuICAgICAgICAgICAgdmFyIG9wZXJhdG9yID0gbnVsbCxcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSBbXTtcblxuICAgICAgICAgICAgaWYgKG9wZXJhdG9ycy5pbmRleE9mKGV4cHJlc3Npb24uY2hhckF0KDApKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgb3BlcmF0b3IgPSBleHByZXNzaW9uLmNoYXJBdCgwKTtcbiAgICAgICAgICAgICAgZXhwcmVzc2lvbiA9IGV4cHJlc3Npb24uc3Vic3RyKDEpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBleHByZXNzaW9uLnNwbGl0KC8sL2cpLmZvckVhY2goZnVuY3Rpb24gKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgIHZhciB0bXAgPSAvKFteOlxcKl0qKSg/OjooXFxkKyl8KFxcKikpPy8uZXhlYyh2YXJpYWJsZSk7XG4gICAgICAgICAgICAgIHZhbHVlcy5wdXNoLmFwcGx5KHZhbHVlcywgdGhhdC5nZXRWYWx1ZXMoY29udGV4dCwgb3BlcmF0b3IsIHRtcFsxXSwgdG1wWzJdIHx8IHRtcFszXSkpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmIChvcGVyYXRvciAmJiBvcGVyYXRvciAhPT0gJysnKSB7XG4gICAgICAgICAgICAgIHZhciBzZXBhcmF0b3IgPSAnLCc7XG5cbiAgICAgICAgICAgICAgaWYgKG9wZXJhdG9yID09PSAnPycpIHtcbiAgICAgICAgICAgICAgICBzZXBhcmF0b3IgPSAnJic7XG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAob3BlcmF0b3IgIT09ICcjJykge1xuICAgICAgICAgICAgICAgIHNlcGFyYXRvciA9IG9wZXJhdG9yO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiAodmFsdWVzLmxlbmd0aCAhPT0gMCA/IG9wZXJhdG9yIDogJycpICsgdmFsdWVzLmpvaW4oc2VwYXJhdG9yKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZXMuam9pbignLCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhhdC5lbmNvZGVSZXNlcnZlZChsaXRlcmFsKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgcmV0dXJuIG5ldyBVcmxUZW1wbGF0ZSgpO1xufSkpO1xuIiwiKGZ1bmN0aW9uKHNlbGYpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIGlmIChzZWxmLmZldGNoKSB7XG4gICAgcmV0dXJuXG4gIH1cblxuICB2YXIgc3VwcG9ydCA9IHtcbiAgICBzZWFyY2hQYXJhbXM6ICdVUkxTZWFyY2hQYXJhbXMnIGluIHNlbGYsXG4gICAgaXRlcmFibGU6ICdTeW1ib2wnIGluIHNlbGYgJiYgJ2l0ZXJhdG9yJyBpbiBTeW1ib2wsXG4gICAgYmxvYjogJ0ZpbGVSZWFkZXInIGluIHNlbGYgJiYgJ0Jsb2InIGluIHNlbGYgJiYgKGZ1bmN0aW9uKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbmV3IEJsb2IoKVxuICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgfSBjYXRjaChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgfVxuICAgIH0pKCksXG4gICAgZm9ybURhdGE6ICdGb3JtRGF0YScgaW4gc2VsZixcbiAgICBhcnJheUJ1ZmZlcjogJ0FycmF5QnVmZmVyJyBpbiBzZWxmXG4gIH1cblxuICBpZiAoc3VwcG9ydC5hcnJheUJ1ZmZlcikge1xuICAgIHZhciB2aWV3Q2xhc3NlcyA9IFtcbiAgICAgICdbb2JqZWN0IEludDhBcnJheV0nLFxuICAgICAgJ1tvYmplY3QgVWludDhBcnJheV0nLFxuICAgICAgJ1tvYmplY3QgVWludDhDbGFtcGVkQXJyYXldJyxcbiAgICAgICdbb2JqZWN0IEludDE2QXJyYXldJyxcbiAgICAgICdbb2JqZWN0IFVpbnQxNkFycmF5XScsXG4gICAgICAnW29iamVjdCBJbnQzMkFycmF5XScsXG4gICAgICAnW29iamVjdCBVaW50MzJBcnJheV0nLFxuICAgICAgJ1tvYmplY3QgRmxvYXQzMkFycmF5XScsXG4gICAgICAnW29iamVjdCBGbG9hdDY0QXJyYXldJ1xuICAgIF1cblxuICAgIHZhciBpc0RhdGFWaWV3ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gb2JqICYmIERhdGFWaWV3LnByb3RvdHlwZS5pc1Byb3RvdHlwZU9mKG9iailcbiAgICB9XG5cbiAgICB2YXIgaXNBcnJheUJ1ZmZlclZpZXcgPSBBcnJheUJ1ZmZlci5pc1ZpZXcgfHwgZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gb2JqICYmIHZpZXdDbGFzc2VzLmluZGV4T2YoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikpID4gLTFcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBub3JtYWxpemVOYW1lKG5hbWUpIHtcbiAgICBpZiAodHlwZW9mIG5hbWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICBuYW1lID0gU3RyaW5nKG5hbWUpXG4gICAgfVxuICAgIGlmICgvW15hLXowLTlcXC0jJCUmJyorLlxcXl9gfH5dL2kudGVzdChuYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSW52YWxpZCBjaGFyYWN0ZXIgaW4gaGVhZGVyIGZpZWxkIG5hbWUnKVxuICAgIH1cbiAgICByZXR1cm4gbmFtZS50b0xvd2VyQ2FzZSgpXG4gIH1cblxuICBmdW5jdGlvbiBub3JtYWxpemVWYWx1ZSh2YWx1ZSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICB2YWx1ZSA9IFN0cmluZyh2YWx1ZSlcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlXG4gIH1cblxuICAvLyBCdWlsZCBhIGRlc3RydWN0aXZlIGl0ZXJhdG9yIGZvciB0aGUgdmFsdWUgbGlzdFxuICBmdW5jdGlvbiBpdGVyYXRvckZvcihpdGVtcykge1xuICAgIHZhciBpdGVyYXRvciA9IHtcbiAgICAgIG5leHQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBpdGVtcy5zaGlmdCgpXG4gICAgICAgIHJldHVybiB7ZG9uZTogdmFsdWUgPT09IHVuZGVmaW5lZCwgdmFsdWU6IHZhbHVlfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChzdXBwb3J0Lml0ZXJhYmxlKSB7XG4gICAgICBpdGVyYXRvcltTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBpdGVyYXRvclxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBpdGVyYXRvclxuICB9XG5cbiAgZnVuY3Rpb24gSGVhZGVycyhoZWFkZXJzKSB7XG4gICAgdGhpcy5tYXAgPSB7fVxuXG4gICAgaWYgKGhlYWRlcnMgaW5zdGFuY2VvZiBIZWFkZXJzKSB7XG4gICAgICBoZWFkZXJzLmZvckVhY2goZnVuY3Rpb24odmFsdWUsIG5hbWUpIHtcbiAgICAgICAgdGhpcy5hcHBlbmQobmFtZSwgdmFsdWUpXG4gICAgICB9LCB0aGlzKVxuXG4gICAgfSBlbHNlIGlmIChoZWFkZXJzKSB7XG4gICAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhoZWFkZXJzKS5mb3JFYWNoKGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgICAgdGhpcy5hcHBlbmQobmFtZSwgaGVhZGVyc1tuYW1lXSlcbiAgICAgIH0sIHRoaXMpXG4gICAgfVxuICB9XG5cbiAgSGVhZGVycy5wcm90b3R5cGUuYXBwZW5kID0gZnVuY3Rpb24obmFtZSwgdmFsdWUpIHtcbiAgICBuYW1lID0gbm9ybWFsaXplTmFtZShuYW1lKVxuICAgIHZhbHVlID0gbm9ybWFsaXplVmFsdWUodmFsdWUpXG4gICAgdmFyIG9sZFZhbHVlID0gdGhpcy5tYXBbbmFtZV1cbiAgICB0aGlzLm1hcFtuYW1lXSA9IG9sZFZhbHVlID8gb2xkVmFsdWUrJywnK3ZhbHVlIDogdmFsdWVcbiAgfVxuXG4gIEhlYWRlcnMucHJvdG90eXBlWydkZWxldGUnXSA9IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICBkZWxldGUgdGhpcy5tYXBbbm9ybWFsaXplTmFtZShuYW1lKV1cbiAgfVxuXG4gIEhlYWRlcnMucHJvdG90eXBlLmdldCA9IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICBuYW1lID0gbm9ybWFsaXplTmFtZShuYW1lKVxuICAgIHJldHVybiB0aGlzLmhhcyhuYW1lKSA/IHRoaXMubWFwW25hbWVdIDogbnVsbFxuICB9XG5cbiAgSGVhZGVycy5wcm90b3R5cGUuaGFzID0gZnVuY3Rpb24obmFtZSkge1xuICAgIHJldHVybiB0aGlzLm1hcC5oYXNPd25Qcm9wZXJ0eShub3JtYWxpemVOYW1lKG5hbWUpKVxuICB9XG5cbiAgSGVhZGVycy5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24obmFtZSwgdmFsdWUpIHtcbiAgICB0aGlzLm1hcFtub3JtYWxpemVOYW1lKG5hbWUpXSA9IG5vcm1hbGl6ZVZhbHVlKHZhbHVlKVxuICB9XG5cbiAgSGVhZGVycy5wcm90b3R5cGUuZm9yRWFjaCA9IGZ1bmN0aW9uKGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgZm9yICh2YXIgbmFtZSBpbiB0aGlzLm1hcCkge1xuICAgICAgaWYgKHRoaXMubWFwLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdGhpcy5tYXBbbmFtZV0sIG5hbWUsIHRoaXMpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgSGVhZGVycy5wcm90b3R5cGUua2V5cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBpdGVtcyA9IFtdXG4gICAgdGhpcy5mb3JFYWNoKGZ1bmN0aW9uKHZhbHVlLCBuYW1lKSB7IGl0ZW1zLnB1c2gobmFtZSkgfSlcbiAgICByZXR1cm4gaXRlcmF0b3JGb3IoaXRlbXMpXG4gIH1cblxuICBIZWFkZXJzLnByb3RvdHlwZS52YWx1ZXMgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgaXRlbXMgPSBbXVxuICAgIHRoaXMuZm9yRWFjaChmdW5jdGlvbih2YWx1ZSkgeyBpdGVtcy5wdXNoKHZhbHVlKSB9KVxuICAgIHJldHVybiBpdGVyYXRvckZvcihpdGVtcylcbiAgfVxuXG4gIEhlYWRlcnMucHJvdG90eXBlLmVudHJpZXMgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgaXRlbXMgPSBbXVxuICAgIHRoaXMuZm9yRWFjaChmdW5jdGlvbih2YWx1ZSwgbmFtZSkgeyBpdGVtcy5wdXNoKFtuYW1lLCB2YWx1ZV0pIH0pXG4gICAgcmV0dXJuIGl0ZXJhdG9yRm9yKGl0ZW1zKVxuICB9XG5cbiAgaWYgKHN1cHBvcnQuaXRlcmFibGUpIHtcbiAgICBIZWFkZXJzLnByb3RvdHlwZVtTeW1ib2wuaXRlcmF0b3JdID0gSGVhZGVycy5wcm90b3R5cGUuZW50cmllc1xuICB9XG5cbiAgZnVuY3Rpb24gY29uc3VtZWQoYm9keSkge1xuICAgIGlmIChib2R5LmJvZHlVc2VkKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IFR5cGVFcnJvcignQWxyZWFkeSByZWFkJykpXG4gICAgfVxuICAgIGJvZHkuYm9keVVzZWQgPSB0cnVlXG4gIH1cblxuICBmdW5jdGlvbiBmaWxlUmVhZGVyUmVhZHkocmVhZGVyKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgcmVhZGVyLm9ubG9hZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXNvbHZlKHJlYWRlci5yZXN1bHQpXG4gICAgICB9XG4gICAgICByZWFkZXIub25lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZWplY3QocmVhZGVyLmVycm9yKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBmdW5jdGlvbiByZWFkQmxvYkFzQXJyYXlCdWZmZXIoYmxvYikge1xuICAgIHZhciByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpXG4gICAgdmFyIHByb21pc2UgPSBmaWxlUmVhZGVyUmVhZHkocmVhZGVyKVxuICAgIHJlYWRlci5yZWFkQXNBcnJheUJ1ZmZlcihibG9iKVxuICAgIHJldHVybiBwcm9taXNlXG4gIH1cblxuICBmdW5jdGlvbiByZWFkQmxvYkFzVGV4dChibG9iKSB7XG4gICAgdmFyIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKClcbiAgICB2YXIgcHJvbWlzZSA9IGZpbGVSZWFkZXJSZWFkeShyZWFkZXIpXG4gICAgcmVhZGVyLnJlYWRBc1RleHQoYmxvYilcbiAgICByZXR1cm4gcHJvbWlzZVxuICB9XG5cbiAgZnVuY3Rpb24gYnVmZmVyQ2xvbmUoYnVmKSB7XG4gICAgaWYgKGJ1Zi5zbGljZSkge1xuICAgICAgcmV0dXJuIGJ1Zi5zbGljZSgwKVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgdmlldyA9IG5ldyBVaW50OEFycmF5KGJ1Zi5ieXRlTGVuZ3RoKVxuICAgICAgdmlldy5zZXQobmV3IFVpbnQ4QXJyYXkoYnVmKSlcbiAgICAgIHJldHVybiB2aWV3LmJ1ZmZlclxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIEJvZHkoKSB7XG4gICAgdGhpcy5ib2R5VXNlZCA9IGZhbHNlXG5cbiAgICB0aGlzLl9pbml0Qm9keSA9IGZ1bmN0aW9uKGJvZHkpIHtcbiAgICAgIHRoaXMuX2JvZHlJbml0ID0gYm9keVxuICAgICAgaWYgKCFib2R5KSB7XG4gICAgICAgIHRoaXMuX2JvZHlUZXh0ID0gJydcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGJvZHkgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHRoaXMuX2JvZHlUZXh0ID0gYm9keVxuICAgICAgfSBlbHNlIGlmIChzdXBwb3J0LmJsb2IgJiYgQmxvYi5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihib2R5KSkge1xuICAgICAgICB0aGlzLl9ib2R5QmxvYiA9IGJvZHlcbiAgICAgIH0gZWxzZSBpZiAoc3VwcG9ydC5mb3JtRGF0YSAmJiBGb3JtRGF0YS5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihib2R5KSkge1xuICAgICAgICB0aGlzLl9ib2R5Rm9ybURhdGEgPSBib2R5XG4gICAgICB9IGVsc2UgaWYgKHN1cHBvcnQuc2VhcmNoUGFyYW1zICYmIFVSTFNlYXJjaFBhcmFtcy5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihib2R5KSkge1xuICAgICAgICB0aGlzLl9ib2R5VGV4dCA9IGJvZHkudG9TdHJpbmcoKVxuICAgICAgfSBlbHNlIGlmIChzdXBwb3J0LmFycmF5QnVmZmVyICYmIHN1cHBvcnQuYmxvYiAmJiBpc0RhdGFWaWV3KGJvZHkpKSB7XG4gICAgICAgIHRoaXMuX2JvZHlBcnJheUJ1ZmZlciA9IGJ1ZmZlckNsb25lKGJvZHkuYnVmZmVyKVxuICAgICAgICAvLyBJRSAxMC0xMSBjYW4ndCBoYW5kbGUgYSBEYXRhVmlldyBib2R5LlxuICAgICAgICB0aGlzLl9ib2R5SW5pdCA9IG5ldyBCbG9iKFt0aGlzLl9ib2R5QXJyYXlCdWZmZXJdKVxuICAgICAgfSBlbHNlIGlmIChzdXBwb3J0LmFycmF5QnVmZmVyICYmIChBcnJheUJ1ZmZlci5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihib2R5KSB8fCBpc0FycmF5QnVmZmVyVmlldyhib2R5KSkpIHtcbiAgICAgICAgdGhpcy5fYm9keUFycmF5QnVmZmVyID0gYnVmZmVyQ2xvbmUoYm9keSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndW5zdXBwb3J0ZWQgQm9keUluaXQgdHlwZScpXG4gICAgICB9XG5cbiAgICAgIGlmICghdGhpcy5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJykpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBib2R5ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIHRoaXMuaGVhZGVycy5zZXQoJ2NvbnRlbnQtdHlwZScsICd0ZXh0L3BsYWluO2NoYXJzZXQ9VVRGLTgnKVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2JvZHlCbG9iICYmIHRoaXMuX2JvZHlCbG9iLnR5cGUpIHtcbiAgICAgICAgICB0aGlzLmhlYWRlcnMuc2V0KCdjb250ZW50LXR5cGUnLCB0aGlzLl9ib2R5QmxvYi50eXBlKVxuICAgICAgICB9IGVsc2UgaWYgKHN1cHBvcnQuc2VhcmNoUGFyYW1zICYmIFVSTFNlYXJjaFBhcmFtcy5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihib2R5KSkge1xuICAgICAgICAgIHRoaXMuaGVhZGVycy5zZXQoJ2NvbnRlbnQtdHlwZScsICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD1VVEYtOCcpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc3VwcG9ydC5ibG9iKSB7XG4gICAgICB0aGlzLmJsb2IgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlamVjdGVkID0gY29uc3VtZWQodGhpcylcbiAgICAgICAgaWYgKHJlamVjdGVkKSB7XG4gICAgICAgICAgcmV0dXJuIHJlamVjdGVkXG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fYm9keUJsb2IpIHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuX2JvZHlCbG9iKVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2JvZHlBcnJheUJ1ZmZlcikge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobmV3IEJsb2IoW3RoaXMuX2JvZHlBcnJheUJ1ZmZlcl0pKVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2JvZHlGb3JtRGF0YSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignY291bGQgbm90IHJlYWQgRm9ybURhdGEgYm9keSBhcyBibG9iJylcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5ldyBCbG9iKFt0aGlzLl9ib2R5VGV4dF0pKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy50ZXh0ID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgcmVqZWN0ZWQgPSBjb25zdW1lZCh0aGlzKVxuICAgICAgaWYgKHJlamVjdGVkKSB7XG4gICAgICAgIHJldHVybiByZWplY3RlZFxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5fYm9keUJsb2IpIHtcbiAgICAgICAgcmV0dXJuIHJlYWRCbG9iQXNUZXh0KHRoaXMuX2JvZHlCbG9iKVxuICAgICAgfSBlbHNlIGlmICh0aGlzLl9ib2R5QXJyYXlCdWZmZXIpIHtcbiAgICAgICAgdmFyIHZpZXcgPSBuZXcgVWludDhBcnJheSh0aGlzLl9ib2R5QXJyYXlCdWZmZXIpXG4gICAgICAgIHZhciBzdHIgPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIHZpZXcpXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoc3RyKVxuICAgICAgfSBlbHNlIGlmICh0aGlzLl9ib2R5Rm9ybURhdGEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjb3VsZCBub3QgcmVhZCBGb3JtRGF0YSBib2R5IGFzIHRleHQnKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLl9ib2R5VGV4dClcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc3VwcG9ydC5hcnJheUJ1ZmZlcikge1xuICAgICAgdGhpcy5hcnJheUJ1ZmZlciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAodGhpcy5fYm9keUFycmF5QnVmZmVyKSB7XG4gICAgICAgICAgcmV0dXJuIGNvbnN1bWVkKHRoaXMpIHx8IFByb21pc2UucmVzb2x2ZSh0aGlzLl9ib2R5QXJyYXlCdWZmZXIpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuYmxvYigpLnRoZW4ocmVhZEJsb2JBc0FycmF5QnVmZmVyKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHN1cHBvcnQuZm9ybURhdGEpIHtcbiAgICAgIHRoaXMuZm9ybURhdGEgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGV4dCgpLnRoZW4oZGVjb2RlKVxuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuanNvbiA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHRoaXMudGV4dCgpLnRoZW4oSlNPTi5wYXJzZSlcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLy8gSFRUUCBtZXRob2RzIHdob3NlIGNhcGl0YWxpemF0aW9uIHNob3VsZCBiZSBub3JtYWxpemVkXG4gIHZhciBtZXRob2RzID0gWydERUxFVEUnLCAnR0VUJywgJ0hFQUQnLCAnT1BUSU9OUycsICdQT1NUJywgJ1BVVCddXG5cbiAgZnVuY3Rpb24gbm9ybWFsaXplTWV0aG9kKG1ldGhvZCkge1xuICAgIHZhciB1cGNhc2VkID0gbWV0aG9kLnRvVXBwZXJDYXNlKClcbiAgICByZXR1cm4gKG1ldGhvZHMuaW5kZXhPZih1cGNhc2VkKSA+IC0xKSA/IHVwY2FzZWQgOiBtZXRob2RcbiAgfVxuXG4gIGZ1bmN0aW9uIFJlcXVlc3QoaW5wdXQsIG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fVxuICAgIHZhciBib2R5ID0gb3B0aW9ucy5ib2R5XG5cbiAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgdGhpcy51cmwgPSBpbnB1dFxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoaW5wdXQuYm9keVVzZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQWxyZWFkeSByZWFkJylcbiAgICAgIH1cbiAgICAgIHRoaXMudXJsID0gaW5wdXQudXJsXG4gICAgICB0aGlzLmNyZWRlbnRpYWxzID0gaW5wdXQuY3JlZGVudGlhbHNcbiAgICAgIGlmICghb3B0aW9ucy5oZWFkZXJzKSB7XG4gICAgICAgIHRoaXMuaGVhZGVycyA9IG5ldyBIZWFkZXJzKGlucHV0LmhlYWRlcnMpXG4gICAgICB9XG4gICAgICB0aGlzLm1ldGhvZCA9IGlucHV0Lm1ldGhvZFxuICAgICAgdGhpcy5tb2RlID0gaW5wdXQubW9kZVxuICAgICAgaWYgKCFib2R5ICYmIGlucHV0Ll9ib2R5SW5pdCAhPSBudWxsKSB7XG4gICAgICAgIGJvZHkgPSBpbnB1dC5fYm9keUluaXRcbiAgICAgICAgaW5wdXQuYm9keVVzZWQgPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jcmVkZW50aWFscyA9IG9wdGlvbnMuY3JlZGVudGlhbHMgfHwgdGhpcy5jcmVkZW50aWFscyB8fCAnb21pdCdcbiAgICBpZiAob3B0aW9ucy5oZWFkZXJzIHx8ICF0aGlzLmhlYWRlcnMpIHtcbiAgICAgIHRoaXMuaGVhZGVycyA9IG5ldyBIZWFkZXJzKG9wdGlvbnMuaGVhZGVycylcbiAgICB9XG4gICAgdGhpcy5tZXRob2QgPSBub3JtYWxpemVNZXRob2Qob3B0aW9ucy5tZXRob2QgfHwgdGhpcy5tZXRob2QgfHwgJ0dFVCcpXG4gICAgdGhpcy5tb2RlID0gb3B0aW9ucy5tb2RlIHx8IHRoaXMubW9kZSB8fCBudWxsXG4gICAgdGhpcy5yZWZlcnJlciA9IG51bGxcblxuICAgIGlmICgodGhpcy5tZXRob2QgPT09ICdHRVQnIHx8IHRoaXMubWV0aG9kID09PSAnSEVBRCcpICYmIGJvZHkpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0JvZHkgbm90IGFsbG93ZWQgZm9yIEdFVCBvciBIRUFEIHJlcXVlc3RzJylcbiAgICB9XG4gICAgdGhpcy5faW5pdEJvZHkoYm9keSlcbiAgfVxuXG4gIFJlcXVlc3QucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIG5ldyBSZXF1ZXN0KHRoaXMsIHsgYm9keTogdGhpcy5fYm9keUluaXQgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGRlY29kZShib2R5KSB7XG4gICAgdmFyIGZvcm0gPSBuZXcgRm9ybURhdGEoKVxuICAgIGJvZHkudHJpbSgpLnNwbGl0KCcmJykuZm9yRWFjaChmdW5jdGlvbihieXRlcykge1xuICAgICAgaWYgKGJ5dGVzKSB7XG4gICAgICAgIHZhciBzcGxpdCA9IGJ5dGVzLnNwbGl0KCc9JylcbiAgICAgICAgdmFyIG5hbWUgPSBzcGxpdC5zaGlmdCgpLnJlcGxhY2UoL1xcKy9nLCAnICcpXG4gICAgICAgIHZhciB2YWx1ZSA9IHNwbGl0LmpvaW4oJz0nKS5yZXBsYWNlKC9cXCsvZywgJyAnKVxuICAgICAgICBmb3JtLmFwcGVuZChkZWNvZGVVUklDb21wb25lbnQobmFtZSksIGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkpXG4gICAgICB9XG4gICAgfSlcbiAgICByZXR1cm4gZm9ybVxuICB9XG5cbiAgZnVuY3Rpb24gcGFyc2VIZWFkZXJzKHJhd0hlYWRlcnMpIHtcbiAgICB2YXIgaGVhZGVycyA9IG5ldyBIZWFkZXJzKClcbiAgICByYXdIZWFkZXJzLnNwbGl0KCdcXHJcXG4nKS5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3BsaXQoJzonKVxuICAgICAgdmFyIGtleSA9IHBhcnRzLnNoaWZ0KCkudHJpbSgpXG4gICAgICBpZiAoa2V5KSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IHBhcnRzLmpvaW4oJzonKS50cmltKClcbiAgICAgICAgaGVhZGVycy5hcHBlbmQoa2V5LCB2YWx1ZSlcbiAgICAgIH1cbiAgICB9KVxuICAgIHJldHVybiBoZWFkZXJzXG4gIH1cblxuICBCb2R5LmNhbGwoUmVxdWVzdC5wcm90b3R5cGUpXG5cbiAgZnVuY3Rpb24gUmVzcG9uc2UoYm9keUluaXQsIG9wdGlvbnMpIHtcbiAgICBpZiAoIW9wdGlvbnMpIHtcbiAgICAgIG9wdGlvbnMgPSB7fVxuICAgIH1cblxuICAgIHRoaXMudHlwZSA9ICdkZWZhdWx0J1xuICAgIHRoaXMuc3RhdHVzID0gJ3N0YXR1cycgaW4gb3B0aW9ucyA/IG9wdGlvbnMuc3RhdHVzIDogMjAwXG4gICAgdGhpcy5vayA9IHRoaXMuc3RhdHVzID49IDIwMCAmJiB0aGlzLnN0YXR1cyA8IDMwMFxuICAgIHRoaXMuc3RhdHVzVGV4dCA9ICdzdGF0dXNUZXh0JyBpbiBvcHRpb25zID8gb3B0aW9ucy5zdGF0dXNUZXh0IDogJ09LJ1xuICAgIHRoaXMuaGVhZGVycyA9IG5ldyBIZWFkZXJzKG9wdGlvbnMuaGVhZGVycylcbiAgICB0aGlzLnVybCA9IG9wdGlvbnMudXJsIHx8ICcnXG4gICAgdGhpcy5faW5pdEJvZHkoYm9keUluaXQpXG4gIH1cblxuICBCb2R5LmNhbGwoUmVzcG9uc2UucHJvdG90eXBlKVxuXG4gIFJlc3BvbnNlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBuZXcgUmVzcG9uc2UodGhpcy5fYm9keUluaXQsIHtcbiAgICAgIHN0YXR1czogdGhpcy5zdGF0dXMsXG4gICAgICBzdGF0dXNUZXh0OiB0aGlzLnN0YXR1c1RleHQsXG4gICAgICBoZWFkZXJzOiBuZXcgSGVhZGVycyh0aGlzLmhlYWRlcnMpLFxuICAgICAgdXJsOiB0aGlzLnVybFxuICAgIH0pXG4gIH1cblxuICBSZXNwb25zZS5lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciByZXNwb25zZSA9IG5ldyBSZXNwb25zZShudWxsLCB7c3RhdHVzOiAwLCBzdGF0dXNUZXh0OiAnJ30pXG4gICAgcmVzcG9uc2UudHlwZSA9ICdlcnJvcidcbiAgICByZXR1cm4gcmVzcG9uc2VcbiAgfVxuXG4gIHZhciByZWRpcmVjdFN0YXR1c2VzID0gWzMwMSwgMzAyLCAzMDMsIDMwNywgMzA4XVxuXG4gIFJlc3BvbnNlLnJlZGlyZWN0ID0gZnVuY3Rpb24odXJsLCBzdGF0dXMpIHtcbiAgICBpZiAocmVkaXJlY3RTdGF0dXNlcy5pbmRleE9mKHN0YXR1cykgPT09IC0xKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW52YWxpZCBzdGF0dXMgY29kZScpXG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBSZXNwb25zZShudWxsLCB7c3RhdHVzOiBzdGF0dXMsIGhlYWRlcnM6IHtsb2NhdGlvbjogdXJsfX0pXG4gIH1cblxuICBzZWxmLkhlYWRlcnMgPSBIZWFkZXJzXG4gIHNlbGYuUmVxdWVzdCA9IFJlcXVlc3RcbiAgc2VsZi5SZXNwb25zZSA9IFJlc3BvbnNlXG5cbiAgc2VsZi5mZXRjaCA9IGZ1bmN0aW9uKGlucHV0LCBpbml0KSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgdmFyIHJlcXVlc3QgPSBuZXcgUmVxdWVzdChpbnB1dCwgaW5pdClcbiAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKVxuXG4gICAgICB4aHIub25sb2FkID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBvcHRpb25zID0ge1xuICAgICAgICAgIHN0YXR1czogeGhyLnN0YXR1cyxcbiAgICAgICAgICBzdGF0dXNUZXh0OiB4aHIuc3RhdHVzVGV4dCxcbiAgICAgICAgICBoZWFkZXJzOiBwYXJzZUhlYWRlcnMoeGhyLmdldEFsbFJlc3BvbnNlSGVhZGVycygpIHx8ICcnKVxuICAgICAgICB9XG4gICAgICAgIG9wdGlvbnMudXJsID0gJ3Jlc3BvbnNlVVJMJyBpbiB4aHIgPyB4aHIucmVzcG9uc2VVUkwgOiBvcHRpb25zLmhlYWRlcnMuZ2V0KCdYLVJlcXVlc3QtVVJMJylcbiAgICAgICAgdmFyIGJvZHkgPSAncmVzcG9uc2UnIGluIHhociA/IHhoci5yZXNwb25zZSA6IHhoci5yZXNwb25zZVRleHRcbiAgICAgICAgcmVzb2x2ZShuZXcgUmVzcG9uc2UoYm9keSwgb3B0aW9ucykpXG4gICAgICB9XG5cbiAgICAgIHhoci5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJlamVjdChuZXcgVHlwZUVycm9yKCdOZXR3b3JrIHJlcXVlc3QgZmFpbGVkJykpXG4gICAgICB9XG5cbiAgICAgIHhoci5vbnRpbWVvdXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmVqZWN0KG5ldyBUeXBlRXJyb3IoJ05ldHdvcmsgcmVxdWVzdCBmYWlsZWQnKSlcbiAgICAgIH1cblxuICAgICAgeGhyLm9wZW4ocmVxdWVzdC5tZXRob2QsIHJlcXVlc3QudXJsLCB0cnVlKVxuXG4gICAgICBpZiAocmVxdWVzdC5jcmVkZW50aWFscyA9PT0gJ2luY2x1ZGUnKSB7XG4gICAgICAgIHhoci53aXRoQ3JlZGVudGlhbHMgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIGlmICgncmVzcG9uc2VUeXBlJyBpbiB4aHIgJiYgc3VwcG9ydC5ibG9iKSB7XG4gICAgICAgIHhoci5yZXNwb25zZVR5cGUgPSAnYmxvYidcbiAgICAgIH1cblxuICAgICAgcmVxdWVzdC5oZWFkZXJzLmZvckVhY2goZnVuY3Rpb24odmFsdWUsIG5hbWUpIHtcbiAgICAgICAgeGhyLnNldFJlcXVlc3RIZWFkZXIobmFtZSwgdmFsdWUpXG4gICAgICB9KVxuXG4gICAgICB4aHIuc2VuZCh0eXBlb2YgcmVxdWVzdC5fYm9keUluaXQgPT09ICd1bmRlZmluZWQnID8gbnVsbCA6IHJlcXVlc3QuX2JvZHlJbml0KVxuICAgIH0pXG4gIH1cbiAgc2VsZi5mZXRjaC5wb2x5ZmlsbCA9IHRydWVcbn0pKHR5cGVvZiBzZWxmICE9PSAndW5kZWZpbmVkJyA/IHNlbGYgOiB0aGlzKTtcbiJdfQ== \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/csrf.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/csrf.js new file mode 100644 index 0000000000000000000000000000000000000000..6e4bf39a7902965f4b4c04b60bdbae48944aef30 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/csrf.js @@ -0,0 +1,52 @@ +function getCookie(name) { + var cookieValue = null; + + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + + return cookieValue; +} + +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} + +function sameOrigin(url) { + // test that a given url is a same-origin URL + // url could be relative or scheme relative or absolute + var host = document.location.host; // host + port + var protocol = document.location.protocol; + var sr_origin = '//' + host; + var origin = protocol + sr_origin; + + // Allow absolute or scheme relative URLs to same origin + return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || + (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || + // or any other URL that isn't scheme relative or absolute i.e relative. + !(/^(\/\/|http:|https:).*/.test(url)); +} + +var csrftoken = window.drf.csrfToken; + +$.ajaxSetup({ + beforeSend: function(xhr, settings) { + if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { + // Send the token to same-origin, relative URLs only. + // Send the token only if the method warrants CSRF protection + // Using the CSRFToken value acquired earlier + xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken); + } + } +}); diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/default.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/default.js new file mode 100644 index 0000000000000000000000000000000000000000..bec2e4f9eb69a0f873dc411f240275be115d2291 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/default.js @@ -0,0 +1,47 @@ +$(document).ready(function() { + // JSON highlighting. + prettyPrint(); + + // Bootstrap tooltips. + $('.js-tooltip').tooltip({ + delay: 1000, + container: 'body' + }); + + // Deal with rounded tab styling after tab clicks. + $('a[data-toggle="tab"]:first').on('shown', function(e) { + $(e.target).parents('.tabbable').addClass('first-tab-active'); + }); + + $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) { + $(e.target).parents('.tabbable').removeClass('first-tab-active'); + }); + + $('a[data-toggle="tab"]').click(function() { + document.cookie = "tabstyle=" + this.name + "; path=/"; + }); + + // Store tab preference in cookies & display appropriate tab on load. + var selectedTab = null; + var selectedTabName = getCookie('tabstyle'); + + if (selectedTabName) { + selectedTabName = selectedTabName.replace(/[^a-z-]/g, ''); + } + + if (selectedTabName) { + selectedTab = $('.form-switcher a[name=' + selectedTabName + ']'); + } + + if (selectedTab && selectedTab.length > 0) { + // Display whichever tab is selected. + selectedTab.tab('show'); + } else { + // If no tab selected, display rightmost tab. + $('.form-switcher a:first').tab('show'); + } + + $(window).on('load', function() { + $('#errorModal').modal('show'); + }); +}); diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/jquery-3.5.1.min.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/jquery-3.5.1.min.js new file mode 100644 index 0000000000000000000000000000000000000000..b0614034ad3a95e4ae9f53c2b015eeb3e8d68bde --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/jquery-3.5.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S}); diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/prettify-min.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/prettify-min.js new file mode 100644 index 0000000000000000000000000000000000000000..eef5ad7e6a07676b3919146d583d1c190bf1e163 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/static/rest_framework/js/prettify-min.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c< +f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&& +(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r= +{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length, +t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b=== +"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value", +m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m= +a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue= +j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m, +250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit", +PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})(); diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/status.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/status.py new file mode 100644 index 0000000000000000000000000000000000000000..7df26b388cd17ff26cc7606dc250ecfc6b52f6b1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/status.py @@ -0,0 +1,93 @@ +""" +Descriptive HTTP status codes, for code readability. + +See RFC 2616 - https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +And RFC 6585 - https://tools.ietf.org/html/rfc6585 +And RFC 4918 - https://tools.ietf.org/html/rfc4918 +""" + + +def is_informational(code): + return 100 <= code <= 199 + + +def is_success(code): + return 200 <= code <= 299 + + +def is_redirect(code): + return 300 <= code <= 399 + + +def is_client_error(code): + return 400 <= code <= 499 + + +def is_server_error(code): + return 500 <= code <= 599 + + +HTTP_100_CONTINUE = 100 +HTTP_101_SWITCHING_PROTOCOLS = 101 +HTTP_102_PROCESSING = 102 +HTTP_103_EARLY_HINTS = 103 +HTTP_200_OK = 200 +HTTP_201_CREATED = 201 +HTTP_202_ACCEPTED = 202 +HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 +HTTP_204_NO_CONTENT = 204 +HTTP_205_RESET_CONTENT = 205 +HTTP_206_PARTIAL_CONTENT = 206 +HTTP_207_MULTI_STATUS = 207 +HTTP_208_ALREADY_REPORTED = 208 +HTTP_226_IM_USED = 226 +HTTP_300_MULTIPLE_CHOICES = 300 +HTTP_301_MOVED_PERMANENTLY = 301 +HTTP_302_FOUND = 302 +HTTP_303_SEE_OTHER = 303 +HTTP_304_NOT_MODIFIED = 304 +HTTP_305_USE_PROXY = 305 +HTTP_306_RESERVED = 306 +HTTP_307_TEMPORARY_REDIRECT = 307 +HTTP_308_PERMANENT_REDIRECT = 308 +HTTP_400_BAD_REQUEST = 400 +HTTP_401_UNAUTHORIZED = 401 +HTTP_402_PAYMENT_REQUIRED = 402 +HTTP_403_FORBIDDEN = 403 +HTTP_404_NOT_FOUND = 404 +HTTP_405_METHOD_NOT_ALLOWED = 405 +HTTP_406_NOT_ACCEPTABLE = 406 +HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 +HTTP_408_REQUEST_TIMEOUT = 408 +HTTP_409_CONFLICT = 409 +HTTP_410_GONE = 410 +HTTP_411_LENGTH_REQUIRED = 411 +HTTP_412_PRECONDITION_FAILED = 412 +HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413 +HTTP_414_REQUEST_URI_TOO_LONG = 414 +HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 +HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416 +HTTP_417_EXPECTATION_FAILED = 417 +HTTP_418_IM_A_TEAPOT = 418 +HTTP_421_MISDIRECTED_REQUEST = 421 +HTTP_422_UNPROCESSABLE_ENTITY = 422 +HTTP_423_LOCKED = 423 +HTTP_424_FAILED_DEPENDENCY = 424 +HTTP_425_TOO_EARLY = 425 +HTTP_426_UPGRADE_REQUIRED = 426 +HTTP_428_PRECONDITION_REQUIRED = 428 +HTTP_429_TOO_MANY_REQUESTS = 429 +HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 +HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 +HTTP_500_INTERNAL_SERVER_ERROR = 500 +HTTP_501_NOT_IMPLEMENTED = 501 +HTTP_502_BAD_GATEWAY = 502 +HTTP_503_SERVICE_UNAVAILABLE = 503 +HTTP_504_GATEWAY_TIMEOUT = 504 +HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 +HTTP_506_VARIANT_ALSO_NEGOTIATES = 506 +HTTP_507_INSUFFICIENT_STORAGE = 507 +HTTP_508_LOOP_DETECTED = 508 +HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509 +HTTP_510_NOT_EXTENDED = 510 +HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin.html new file mode 100644 index 0000000000000000000000000000000000000000..1281220b2832992c62b3a1648aff266298311202 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin.html @@ -0,0 +1,267 @@ +{% load static %} +{% load i18n %} +{% load rest_framework %} + +<!DOCTYPE html> +<html> + <head> + {% block head %} + + {% block meta %} + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta name="robots" content="NONE,NOARCHIVE" /> + {% endblock %} + + <title>{% block title %}Django REST framework{% endblock %}</title> + + {% block style %} + {% block bootstrap_theme %} + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/> + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/> + {% endblock %} + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/prettify.css" %}"/> + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/> + {% endblock %} + + {% endblock %} + </head> + + {% block body %} + <body class="{% block bodyclass %}{% endblock %}"> + <div class="wrapper"> + {% block navbar %} + <div class="navbar navbar-static-top {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}"> + <div class="container"> + <span> + {% block branding %} + <a class='navbar-brand' rel="nofollow" href='https://www.django-rest-framework.org/'> + Django REST framework + </a> + {% endblock %} + </span> + <ul class="nav navbar-nav pull-right"> + {% block userlinks %} + {% if user.is_authenticated %} + {% optional_logout request user %} + {% else %} + {% optional_login request %} + {% endif %} + {% endblock %} + </ul> + </div> + </div> + {% endblock %} + + <div class="container"> + {% block breadcrumbs %} + <ul class="breadcrumb"> + {% for breadcrumb_name, breadcrumb_url in breadcrumblist %} + {% if forloop.last %} + <li class="active"><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li> + {% else %} + <li><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li> + {% endif %} + {% endfor %} + </ul> + {% endblock %} + + <!-- Content --> + <div id="content"> + {% if 'GET' in allowed_methods %} + <form id="get-form" class="pull-right"> + <fieldset> + <div class="btn-group format-selection"> + <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown"> + Format <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + {% for format in available_formats %} + <li> + <a class="format-option" + href='{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}' + rel="nofollow"> + {{ format }} + </a> + </li> + {% endfor %} + </ul> + </div> + </fieldset> + </form> + {% endif %} + + {% if post_form %} + <button type="button" class="button-form btn btn-primary" data-toggle="modal" data-target="#createModal"> + <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Create + </button> + {% endif %} + + {% if put_form %} + <button type="button" class="button-form btn btn-primary" data-toggle="modal" data-target="#editModal"> + <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit + </button> + {% endif %} + + {% if delete_form %} + <form class="button-form" action="{{ request.get_full_path }}" data-method="DELETE"> + <button class="btn btn-danger"> + <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Delete + </button> + </form> + {% endif %} + + {% if extra_actions %} + <div class="dropdown" style="float: right; margin-right: 10px"> + <button class="btn btn-default" id="extra-actions-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + {% trans "Extra Actions" %} + <span class="caret"></span> + </button> + <ul class="dropdown-menu" aria-labelledby="extra-actions-menu"> + {% for action_name, url in extra_actions|items %} + <li><a href="{{ url }}">{{ action_name }}</a></li> + {% endfor %} + </ul> + </div> + {% endif %} + + {% if filter_form %} + <button style="float: right; margin-right: 10px" data-toggle="modal" data-target="#filtersModal" class="btn btn-default"> + <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> + {% trans "Filters" %} + </button> + {% endif %} + + <div class="content-main"> + <div class="page-header"> + <h1>{{ name }}</h1> + </div> + + <div style="float:left"> + {% block description %} + {{ description }} + {% endblock %} + </div> + + {% if paginator %} + <nav style="float: right"> + {% get_pagination_html paginator %} + </nav> + {% endif %} + + <div class="request-info" style="clear: both" > + {% if style == 'list' %} + {% include "rest_framework/admin/list.html" %} + {% else %} + {% include "rest_framework/admin/detail.html" %} + {% endif %} + </div> + + {% if paginator %} + <nav style="float: right"> + {% get_pagination_html paginator %} + </nav> + {% endif %} + </div> + </div> + <!-- END Content --> + </div><!-- /.container --> + </div><!-- ./wrapper --> + + <!-- Create Modal --> + <div class="modal fade" id="createModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel">Create</h4> + </div> + <form action="{{ request.get_full_path }}" method="POST" enctype="multipart/form-data" class="form-horizontal" novalidate> + <div class="modal-body"> + <fieldset> + {% csrf_token %} + {{ post_form }} + </fieldset> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Save</button> + </div> + </form> + </div> + </div> + </div> + + <!-- Edit Modal --> + <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel">Edit</h4> + </div> + <form action="{{ request.get_full_path }}" data-method="PUT" enctype="multipart/form-data" class="form-horizontal" novalidate> + <div class="modal-body"> + <fieldset> + {{ put_form }} + </fieldset> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Save</button> + </div> + </form> + </div> + </div> + </div> + + {% if error_form %} + <!-- Errors Modal --> + <div class="modal" id="errorModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="myModalLabel">{{ error_title }}</h4> + </div> + <form action="{{ request.get_full_path }}" data-method="{{ request.method }}" enctype="multipart/form-data" class="form-horizontal" novalidate> + <div class="modal-body"> + <fieldset> + {{ error_form }} + </fieldset> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Save</button> + </div> + </form> + </div> + </div> + </div> + {% endif %} + + {% if filter_form %} + {{ filter_form }} + {% endif %} + + {% block script %} + <script> + window.drf = { + csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}", + csrfToken: "{{ csrf_token }}" + }; + </script> + <script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script> + <script src="{% static "rest_framework/js/ajax-form.js" %}"></script> + <script src="{% static "rest_framework/js/csrf.js" %}"></script> + <script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script> + <script src="{% static "rest_framework/js/prettify-min.js" %}"></script> + <script src="{% static "rest_framework/js/default.js" %}"></script> + <script> + $(document).ready(function() { + $('form').ajaxForm(); + }); + </script> + {% endblock %} + </body> + {% endblock %} +</html> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/detail.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/detail.html new file mode 100644 index 0000000000000000000000000000000000000000..42cd1a36de77870442bb6cd8283214ef20ee8bd5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/detail.html @@ -0,0 +1,10 @@ +{% load rest_framework %} +<table class="table table-striped"> + <tbody> + {% for key, value in results|items %} + {% if key in details %} + <tr><th>{{ key|capfirst }}</th><td {{ value|add_nested_class }}>{{ value|format_value }}</td></tr> + {% endif %} + {% endfor %} + </tbody> +</table> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/dict_value.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/dict_value.html new file mode 100644 index 0000000000000000000000000000000000000000..ef47b72281d43401360ced838726218bc261726c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/dict_value.html @@ -0,0 +1,11 @@ +{% load rest_framework %} +<table class="table table-striped"> + <tbody> + {% for k, v in value|items %} + <tr> + <th>{{ k|format_value }}</th> + <td>{{ v|format_value }}</td> + </tr> + {% endfor %} + </tbody> +</table> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list.html new file mode 100644 index 0000000000000000000000000000000000000000..ab3e84d1725844e43dad77fa1697ae94de07298c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list.html @@ -0,0 +1,26 @@ +{% load rest_framework %} +<table class="table table-striped"> + <thead> + <tr>{% for column in columns%}<th>{{ column|capfirst }}</th>{% endfor %}<th class="col-xs-1"></th></tr> + </thead> + <tbody> + {% for row in results %} + <tr> + {% for key, value in row|items %} + {% if key in columns %} + <td {{ value|add_nested_class }} > + {{ value|format_value }} + </td> + {% endif %} + {% endfor %} + <td> + {% if row.url %} + <a href="{{ row.url }}"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span></a> + {% else %} + <span class="glyphicon glyphicon-chevron-right text-muted" aria-hidden="true"></span> + {% endif %} + </td> + </tr> + {% endfor %} + </tbody> +</table> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list_value.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list_value.html new file mode 100644 index 0000000000000000000000000000000000000000..5bab6b57a5a800d78d969f67dc86cff3aa18dfc1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/list_value.html @@ -0,0 +1,11 @@ +{% load rest_framework %} +<table class="table table-striped"> + <tbody> + {% for item in value %} + <tr> + <th>{{ forloop.counter0 }}</th> + <td>{{ item|format_value }}</td> + </tr> + {% endfor %} + </tbody> +</table> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/simple_list_value.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/simple_list_value.html new file mode 100644 index 0000000000000000000000000000000000000000..e378a36b63ac8f1e6f410630472c751c3cfea7f1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/admin/simple_list_value.html @@ -0,0 +1,2 @@ +{% load rest_framework %} +{% for item in value %}{% if not forloop.first%},{% endif %} {{item|format_value}}{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/api.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/api.html new file mode 100644 index 0000000000000000000000000000000000000000..81d277e96721f306dce79e7dc15325ad2e002de5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/api.html @@ -0,0 +1,3 @@ +{% extends "rest_framework/base.html" %} + +{# Override this template in your own templates directory to customize #} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/base.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/base.html new file mode 100644 index 0000000000000000000000000000000000000000..a88e1591c63adb43a604a6cfd677a08bf08d11de --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/base.html @@ -0,0 +1,311 @@ +{% load static %} +{% load i18n %} +{% load rest_framework %} + +<!DOCTYPE html> +<html> + <head> + {% block head %} + + {% block meta %} + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta name="robots" content="NONE,NOARCHIVE" /> + {% endblock %} + + <title>{% block title %}{% if name %}{{ name }} – {% endif %}Django REST framework{% endblock %}</title> + + {% block style %} + {% block bootstrap_theme %} + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/> + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/> + {% endblock %} + + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/prettify.css" %}"/> + <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/> + {% if code_style %}<style>{{ code_style }}</style>{% endif %} + {% endblock %} + + {% endblock %} + </head> + + {% block body %} + <body class="{% block bodyclass %}{% endblock %}"> + + <div class="wrapper"> + {% block navbar %} + <div class="navbar navbar-static-top {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}" + role="navigation" aria-label="{% trans "navbar" %}"> + <div class="container"> + <span> + {% block branding %} + <a class='navbar-brand' rel="nofollow" href='https://www.django-rest-framework.org/'> + Django REST framework + </a> + {% endblock %} + </span> + <ul class="nav navbar-nav pull-right"> + {% block userlinks %} + {% if user.is_authenticated %} + {% optional_logout request user %} + {% else %} + {% optional_login request %} + {% endif %} + {% endblock %} + </ul> + </div> + </div> + {% endblock %} + + <div class="container"> + {% block breadcrumbs %} + <ul class="breadcrumb"> + {% for breadcrumb_name, breadcrumb_url in breadcrumblist %} + {% if forloop.last %} + <li class="active"><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li> + {% else %} + <li><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li> + {% endif %} + {% empty %} + {% block breadcrumbs_empty %} {% endblock breadcrumbs_empty %} + {% endfor %} + </ul> + {% endblock %} + + <!-- Content --> + <div id="content" role="main" aria-label="{% trans "content" %}"> + {% block content %} + + <div class="region" aria-label="{% trans "request form" %}"> + {% block request_forms %} + + {% if 'GET' in allowed_methods %} + <form id="get-form" class="pull-right"> + <fieldset> + {% if api_settings.URL_FORMAT_OVERRIDE %} + <div class="btn-group format-selection"> + <a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a> + + <button class="btn btn-primary dropdown-toggle js-tooltip" data-toggle="dropdown" title="Specify a format for the GET request"> + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + {% for format in available_formats %} + <li> + <a class="js-tooltip format-option" href="{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}" rel="nofollow" title="Make a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a> + </li> + {% endfor %} + </ul> + </div> + {% else %} + <a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a> + {% endif %} + </fieldset> + </form> + {% endif %} + + {% if options_form %} + <form class="button-form" action="{{ request.get_full_path }}" data-method="OPTIONS"> + <button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button> + </form> + {% endif %} + + {% if delete_form %} + <button class="btn btn-danger button-form js-tooltip" title="Make a DELETE request on the {{ name }} resource" data-toggle="modal" data-target="#deleteModal">DELETE</button> + + <!-- Delete Modal --> + <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-body"> + <h4 class="text-center">Are you sure you want to delete this {{ name }}?</h4> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <form class="button-form" action="{{ request.get_full_path }}" data-method="DELETE"> + <button class="btn btn-danger">Delete</button> + </form> + </div> + </div> + </div> + </div> + {% endif %} + + {% if extra_actions %} + <div class="dropdown" style="float: right; margin-right: 10px"> + <button class="btn btn-default" id="extra-actions-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + {% trans "Extra Actions" %} + <span class="caret"></span> + </button> + <ul class="dropdown-menu" aria-labelledby="extra-actions-menu"> + {% for action_name, url in extra_actions|items %} + <li><a href="{{ url }}">{{ action_name }}</a></li> + {% endfor %} + </ul> + </div> + {% endif %} + + {% if filter_form %} + <button style="float: right; margin-right: 10px" data-toggle="modal" data-target="#filtersModal" class="btn btn-default"> + <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> + {% trans "Filters" %} + </button> + {% endif %} + + {% endblock request_forms %} + </div> + + <div class="content-main" role="main" aria-label="{% trans "main content" %}"> + <div class="page-header"> + <h1>{{ name }}</h1> + </div> + <div style="float:left"> + {% block description %} + {{ description }} + {% endblock %} + </div> + + {% if paginator %} + <nav style="float: right"> + {% get_pagination_html paginator %} + </nav> + {% endif %} + + <div class="request-info" style="clear: both" aria-label="{% trans "request info" %}"> + <pre class="prettyprint"><b>{{ request.method }}</b> {{ request.get_full_path }}</pre> + </div> + + <div class="response-info" aria-label="{% trans "response info" %}"> + <pre class="prettyprint"><span class="meta nocode"><b>HTTP {{ response.status_code }} {{ response.status_text }}</b>{% for key, val in response_headers|items %} +<b>{{ key }}:</b> <span class="lit">{{ val|break_long_headers|urlize }}</span>{% endfor %} + +</span>{{ content|urlize }}</pre> + </div> + </div> + + {% if display_edit_forms %} + {% if post_form or raw_data_post_form %} + <div {% if post_form %}class="tabbable"{% endif %}> + {% if post_form %} + <ul class="nav nav-tabs form-switcher"> + <li> + <a name='html-tab' href="#post-object-form" data-toggle="tab">HTML form</a> + </li> + <li> + <a name='raw-tab' href="#post-generic-content-form" data-toggle="tab">Raw data</a> + </li> + </ul> + {% endif %} + + <div class="well tab-content"> + {% if post_form %} + <div class="tab-pane" id="post-object-form"> + {% with form=post_form %} + <form action="{{ request.get_full_path }}" method="POST" enctype="multipart/form-data" class="form-horizontal" novalidate> + <fieldset> + {% csrf_token %} + {{ post_form }} + <div class="form-actions"> + <button class="btn btn-primary js-tooltip" title="Make a POST request on the {{ name }} resource">POST</button> + </div> + </fieldset> + </form> + {% endwith %} + </div> + {% endif %} + + <div {% if post_form %}class="tab-pane"{% endif %} id="post-generic-content-form"> + {% with form=raw_data_post_form %} + <form action="{{ request.get_full_path }}" method="POST" class="form-horizontal"> + <fieldset> + {% include "rest_framework/raw_data_form.html" %} + <div class="form-actions"> + <button class="btn btn-primary js-tooltip" title="Make a POST request on the {{ name }} resource">POST</button> + </div> + </fieldset> + </form> + {% endwith %} + </div> + </div> + </div> + {% endif %} + + {% if put_form or raw_data_put_form or raw_data_patch_form %} + <div {% if put_form %}class="tabbable"{% endif %}> + {% if put_form %} + <ul class="nav nav-tabs form-switcher"> + <li> + <a name='html-tab' href="#put-object-form" data-toggle="tab">HTML form</a> + </li> + <li> + <a name='raw-tab' href="#put-generic-content-form" data-toggle="tab">Raw data</a> + </li> + </ul> + {% endif %} + + <div class="well tab-content"> + {% if put_form %} + <div class="tab-pane" id="put-object-form"> + <form action="{{ request.get_full_path }}" data-method="PUT" enctype="multipart/form-data" class="form-horizontal" novalidate> + <fieldset> + {{ put_form }} + <div class="form-actions"> + <button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button> + </div> + </fieldset> + </form> + </div> + {% endif %} + + <div {% if put_form %}class="tab-pane"{% endif %} id="put-generic-content-form"> + {% with form=raw_data_put_or_patch_form %} + <form action="{{ request.get_full_path }}" data-method="PUT" class="form-horizontal"> + <fieldset> + {% include "rest_framework/raw_data_form.html" %} + <div class="form-actions"> + {% if raw_data_put_form %} + <button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button> + {% endif %} + {% if raw_data_patch_form %} + <button data-method="PATCH" class="btn btn-primary js-tooltip" title="Make a PATCH request on the {{ name }} resource">PATCH</button> + {% endif %} + </div> + </fieldset> + </form> + {% endwith %} + </div> + </div> + </div> + {% endif %} + {% endif %} + {% endblock content %} + </div><!-- /.content --> + </div><!-- /.container --> + </div><!-- ./wrapper --> + + {% if filter_form %} + {{ filter_form }} + {% endif %} + + {% block script %} + <script> + window.drf = { + csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}", + csrfToken: "{% if request %}{{ csrf_token }}{% endif %}" + }; + </script> + <script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script> + <script src="{% static "rest_framework/js/ajax-form.js" %}"></script> + <script src="{% static "rest_framework/js/csrf.js" %}"></script> + <script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script> + <script src="{% static "rest_framework/js/prettify-min.js" %}"></script> + <script src="{% static "rest_framework/js/default.js" %}"></script> + <script> + $(document).ready(function() { + $('form').ajaxForm(); + }); + </script> + {% endblock %} + + </body> + {% endblock %} +</html> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/basic.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/basic.html new file mode 100644 index 0000000000000000000000000000000000000000..16fc672448cd8ce4412205e7d452093d97c117cc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/basic.html @@ -0,0 +1,38 @@ +{% load rest_framework %} + +<!-- Modal --> +<div class="modal fade auth-modal auth-basic" id="auth_basic_modal" tabindex="-1" role="dialog" aria-labelledby="basic authentication modal"> +<div class="modal-dialog modal-md" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="modal-title"><i class="fa fa-key"></i> Basic Authentication</h3> + </div> + + <form class="form-horizontal authentication-basic-form"> + <div class="modal-body"> + <div class="form-group"> + <label for="authorization" class="col-sm-2 control-label">Username:</label> + + <div class="col-sm-10"> + <input type="text" class="form-control" id="username" required> + </div> + </div> + + <div class="form-group"> + <label for="authorization" class="col-sm-2 control-label">Password:</label> + + <div class="col-sm-10"> + <input type="password" class="form-control" id="password" required> + </div> + </div> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Use Basic Authentication</button> + </div> + </form> + + </div> +</div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/session.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/session.html new file mode 100644 index 0000000000000000000000000000000000000000..59430d95e10d51ec886ade8edf9ac6bea6bf2f01 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/session.html @@ -0,0 +1,35 @@ +{% load rest_framework %} + +<!-- Modal --> +<div class="modal fade auth-modal auth-session" id="auth_session_modal" tabindex="-1" role="dialog" aria-labelledby="session authentication modal"> +<div class="modal-dialog modal-md" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="modal-title"><i class="fa fa-key"></i> Session Authentication</h3> + </div> + + <form class="form-horizontal authentication-session-form"> + <div class="modal-body"> + + {% if user.is_authenticated %} + <h4 class="text-center">You are logged in as {{ user.get_username }}.</h4> + {% else %} + + <div class="text-center"> + <h4 class="text-center">You need to {% optional_docs_login request %} to enable Session Authentication.</h4> + </div> + {% endif %} + + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + {% if user.is_authenticated %} + <button type="submit" class="btn btn-primary">Use Session Authentication</button> + {% endif %} + </div> + </form> + + </div> +</div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/token.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/token.html new file mode 100644 index 0000000000000000000000000000000000000000..ce781b8424723ff2d190cd5eb02561dfeaeb7b03 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/auth/token.html @@ -0,0 +1,36 @@ +{% load rest_framework %} + +<!-- Modal --> +<div class="modal fade auth-modal auth-token" id="auth_token_modal" tabindex="-1" role="dialog" aria-labelledby="token authentication modal"> +<div class="modal-dialog modal-md" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="modal-title"><i class="fa fa-key"></i> Token Authentication</h3> + </div> + + <form class="form-horizontal authentication-token-form"> + <div class="modal-body"> + <div class="form-group"> + <label for="prefix" class="col-sm-2 control-label">Scheme:</label> + <div class="col-sm-10"> + <input type="text" class="form-control" id="scheme" placeholder="Bearer" aria-describedby="schemeHelpBlock" required> + <span id="schemeHelpBlock" class="help-block">Either a registered authentication scheme such as <code>Bearer</code>, or a custom schema such as <code>Token</code> or <code>JWT</code>.</span> + </div> + </div> + <div class="form-group"> + <label for="token" class="col-sm-2 control-label">Token:</label> + <div class="col-sm-10"> + <input type="text" class="form-control" id="token" placeholder="XXXX-XXXX-XXXX-XXXX" aria-describedby="helpBlock" required> + <span id="tokenHelpBlock" class="help-block">A valid API token.</span> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Use Token Authentication</button> + </div> + </form> + + </div> +</div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/document.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/document.html new file mode 100644 index 0000000000000000000000000000000000000000..9aecb40e085508d70be87876dd29fd4a3d6ed71b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/document.html @@ -0,0 +1,31 @@ +{% load rest_framework %} + +<div class="row intro"> +<div class="col-md-6 intro-title"> + <h1>{{ document.title }}</h1> + {% if document.description %} + <p>{% render_markdown document.description %}</p> + {% endif %} +</div> +<div class="col-md-6 intro-code"> + {% for html in lang_intro_htmls %} + {% include html %} + {% endfor %} +</div> +</div> +{% if document|data %} +{% for section_key, section in document|data|items %} +{% if section_key %} + <h2 id="{{ section_key }}" class="coredocs-section-title">{{ section_key }} <a href="#{{ section_key }}"><i class="fa fa-link" aria-hidden="true"></i> +</a></h2> +{% endif %} + + {% for link_key, link in section|schema_links|items %} + {% include "rest_framework/docs/link.html" %} + {% endfor %} +{% endfor %} + +{% for link_key, link in document.links|items %} + {% include "rest_framework/docs/link.html" %} +{% endfor %} +{% endif %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/error.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/error.html new file mode 100644 index 0000000000000000000000000000000000000000..694f88a150616ba780d790f1c6c22078e84ab3bf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/error.html @@ -0,0 +1,71 @@ +{% load static %} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + + <title>Error Rendering Schema</title> + </head> + <body> + + + +<h1>Error</h1> + +<pre> +{{ data }} +</pre> + + +{% if debug is True %} +<hr /> +<h2>Additional Information</h2> +<p>Note: You are seeing this message because <code>DEBUG==True</code>.</p> + +<p>Seeing this page is <em>usually</em> a configuration error: are your +<code>DEFAULT_AUTHENTICATION_CLASSES</code> or <code>DEFAULT_PERMISSION_CLASSES</code> +being applied unexpectedly?</p> + +<p>Your response status code is: <code>{{ response.status_code }}</code></p> + +<h3>401 Unauthorised.</h3> +<ul> + <li>Do you have SessionAuthentication enabled?</li> + <li>Are you logged in?</li> +</ul> + + +<h3>403 Forbidden.</h3> +<ul> + <li>Do you have sufficient permissions to access this view?</li> + <li>Is you schema non-empty? (An empty schema will lead to a permission denied error being raised.)</li> +</ul> + + +<p>Most commonly the intended solution is to disable authentication and permissions +when including the docs urls:</p> + +<pre> + path('docs/', include_docs_urls(title='Your API', + authentication_classes=[], + permission_classes=[])), +</pre> + + +<h2>Overriding this template</h2> + +<p>If you wish access to your docs to be authenticated you may override this template +at <code>rest_framework/docs/error.html</code>.</p> + +<p>The available context is: <code>data</code> the error dict above, <code>request</code>, +<code>response</code> and the <code>debug</code> flag.</p> + +{% endif %} + + + + <script src="{% static 'rest_framework/js/jquery-3.5.1.min.js' %}"></script> + </body> +</html> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/index.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/index.html new file mode 100644 index 0000000000000000000000000000000000000000..dfd363772a44cb1a294471f32a2412032c9552da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/index.html @@ -0,0 +1,57 @@ +{% load static %} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + + <title>{{ document.title }}</title> + + <link href="{% static 'rest_framework/css/bootstrap.min.css' %}" rel="stylesheet"> + <link href="{% static 'rest_framework/css/bootstrap-theme.min.css' %}" rel="stylesheet"> + <link href="{% static 'rest_framework/css/font-awesome-4.0.3.css' %}" rel="stylesheet"> + <link href="{% static 'rest_framework/docs/css/base.css' %}" rel="stylesheet"> + <link href="{% static 'rest_framework/docs/css/jquery.json-view.min.css' %}" rel="stylesheet"> + + <link href="{% static 'rest_framework/docs/img/favicon.ico' %}" rel="shortcut icon"> + + {% if code_style %}<style>{{ code_style }}</style>{% endif %} + <script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"></script> + <script src="{% url 'api-docs:schema-js' %}"></script> + + </head> + + <body data-spy="scroll" data-target="#sidebar-nav" data-offset="50"> + + {% include "rest_framework/docs/sidebar.html" %} + + <div class="container" id="main"> + <div class="row"> + <div class="col-md-12 main-container"> + {% include "rest_framework/docs/document.html" %} + </div> + </div> + </div> + + {% include "rest_framework/docs/auth/token.html" %} + {% include "rest_framework/docs/auth/basic.html" %} + {% include "rest_framework/docs/auth/session.html" %} + + <script src="{% static 'rest_framework/js/jquery-3.5.1.min.js' %}"></script> + <script src="{% static 'rest_framework/js/bootstrap.min.js' %}"></script> + <script src="{% static 'rest_framework/docs/js/jquery.json-view.min.js' %}"></script> + <script src="{% static 'rest_framework/docs/js/api.js' %}"></script> + <script> + {% if user.is_authenticated %} + window.auth = { + 'type': 'session', + }; + $('#selected-authentication').text('session'); + $('#auth-control').children().removeClass('active'); + $('#auth-control').find("[data-auth='session']").closest('li').addClass('active'); + {% endif %} + $('pre.highlight').filter('[data-language="{{ langs | first }}"]').removeClass('hide'); + </script> + </body> +</html> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/interact.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/interact.html new file mode 100644 index 0000000000000000000000000000000000000000..60771ba20c0a05cc676cdfdefd9b7c445d23fb59 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/interact.html @@ -0,0 +1,51 @@ +{% load rest_framework %} + +<!-- Modal --> +<div class="modal fade api-modal" id="{{ section_key }}_{{ link_key|slugify }}_modal" tabindex="-1" role="dialog" aria-labelledby="api explorer modal"> +<div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <div class="toggle-view hide"> + <div class="btn-group" role="group"> + <button type="button" data-display-toggle="data" class="btn btn-sm btn-info">Data</button> + <button type="button" data-display-toggle="raw" class="btn btn-sm">Raw</button> + </div> + </div> + + <h3 class="modal-title"><i class="fa fa-exchange"></i> {{ link.title|default:link_key }}</h3> + + </div> + + <form data-key='["{{ section_key }}", "{{ link_key }}"]' class="api-interaction"> + <div class="modal-body"> + <div class="row"> + <div class="col-lg-6 request"> + {% form_for_link link %} + </div> + + <hr class="hidden-lg hidden-xl" /> + + <div class="col-lg-6 response" id="response"> + <div class="request-awaiting">Awaiting request</div> + + <div class="meta hide"> + <span class="label label-primary request-method"></span> + <code class="request-url"></code> + <label class="label label-lg response-status-code pull-right"></label> + </div> + + <pre class="well response-data hide"></pre> + <pre class="well response-raw hide"><div class="response-raw-request"></div><div class="response-raw-response"></div></pre> + </div> + </div> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="submit" class="btn btn-primary">Send Request</button> + </div> + </form> + + </div> +</div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript-intro.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript-intro.html new file mode 100644 index 0000000000000000000000000000000000000000..a6938fc45d04bdf4914c93863577c9fd32207d06 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript-intro.html @@ -0,0 +1,5 @@ +{% load rest_framework %} +{% load static %} +<pre class="highlight javascript hide" data-language="javascript"><code>{% code html %}<!-- Load the JavaScript client library --> +<script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"></script> +<script src="{% url 'api-docs:schema-js' %}"></script>{% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript.html new file mode 100644 index 0000000000000000000000000000000000000000..4a51a32fd545178089a0b9a0c270988884bcb652 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/javascript.html @@ -0,0 +1,15 @@ +{% load rest_framework %} +<pre class="highlight javascript hide" data-language="javascript"><code>{% code javascript %}var coreapi = window.coreapi // Loaded by `coreapi.js` +var schema = window.schema // Loaded by `schema.js` + +// Initialize a client +var client = new coreapi.Client() + +// Interact with the API endpoint +var action = [{% if section_key %}"{{ section_key }}", {% endif %}"{{ link_key }}"] +{% if link.fields %}var params = { +{% for field in link.fields %} {{ field.name }}: ...{% if not loop.last %},{% endif %} +{% endfor %}} +{% endif %}client.action(schema, action{% if link.fields %}, params{% endif %}).then(function(result) { + // Return value is in 'result' +}){% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python-intro.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python-intro.html new file mode 100644 index 0000000000000000000000000000000000000000..c2e0bcb33e6da7708d3632620afe8573d8fa1d89 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python-intro.html @@ -0,0 +1,3 @@ +{% load rest_framework %} +<pre class="highlight python hide" data-language="python"><code>{% code bash %}# Install the Python client library +$ pip install coreapi{% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python.html new file mode 100644 index 0000000000000000000000000000000000000000..f944daaffd9dedba3fc318b0547734039d58922d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/python.html @@ -0,0 +1,13 @@ +{% load rest_framework %} +<pre class="highlight python hide" data-language="python"><code>{% code python %}import coreapi + +# Initialize a client & load the schema document +client = coreapi.Client() +schema = client.get("{{ document.url }}"{% if schema_format %}, format="{{ schema_format }}"{% endif %}) + +# Interact with the API endpoint +action = [{% if section_key %}"{{ section_key }}", {% endif %}"{{ link_key }}"] +{% if link.fields %}params = { +{% for field in link.fields %} "{{ field.name }}": ...{% if not loop.last %},{% endif %} +{% endfor %}} +{% endif %}result = client.action(schema, action{% if link.fields %}, params=params{% endif %}){% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell-intro.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell-intro.html new file mode 100644 index 0000000000000000000000000000000000000000..2320ddfa9471c0e431ca31391c439b7e4dac0393 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell-intro.html @@ -0,0 +1,3 @@ +{% load rest_framework %} +<pre class="highlight shell hide" data-language="shell"><code>{% code bash %}# Install the command line client +$ pip install coreapi-cli{% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell.html new file mode 100644 index 0000000000000000000000000000000000000000..e5f2a03221de859f13cfeed5ba58a05daf2be1f7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/langs/shell.html @@ -0,0 +1,6 @@ +{% load rest_framework %} +<pre class="highlight shell hide" data-language="shell"><code>{% code bash %}# Load the schema document +$ coreapi get {{ document.url }}{% if schema_format %} --format {{ schema_format }}{% endif %} + +# Interact with the API endpoint +$ coreapi action {% if section_key %}{{ section_key }} {% endif %}{{ link_key|cut:"> " }}{% for field in link.fields %} -p {{ field.name }}=...{% endfor %}{% endcode %}</code></pre> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/link.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/link.html new file mode 100644 index 0000000000000000000000000000000000000000..0f92a8873010221b91ede614b42faa673d7004cf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/link.html @@ -0,0 +1,102 @@ +{% load rest_framework %} +<div class="row coredocs-link"> + +<div class="col-md-6 docs-content"> + <button + class="btn btn-sm btn-success" + style="float: right; margin-top: 20px" + data-toggle="modal" + data-target="#{{ section_key }}_{{ link_key|slugify }}_modal"> + <i class="fa fa-exchange"></i> Interact + </button> + + <h3 id="{{ section_key }}-{{ link_key|slugify }}" class="coredocs-link-title">{{ link.title|default:link_key }} <a href="#{{ section_key }}-{{ link_key|slugify }}"><i class="fa fa-link" aria-hidden="true"></i> +</a></h3> + + <div class="meta"> + <span class="label label-primary">{{ link.action|upper }}</span> + <code>{{ link.url }}</code> + </div> + + <p>{% render_markdown link.description %}</p> + +{% if link.fields|with_location:'path' %} + <h4>Path Parameters</h4> + <p>The following parameters should be included in the URL path.</p> + <table class="parameters table table-bordered table-striped"> + <thead> + <tr><th>Parameter</th><th>Description</th></tr> + </thead> + <tbody> + {% for field in link.fields|with_location:'path' %} + <tr><td class="parameter-name"><code>{{ field.name }}</code>{% if field.required %} <span class="label label-warning">required</span>{% endif %}</td><td>{% if field.schema.description %}{{ field.schema.description|safe }}{% endif %}</td></tr> + {% endfor %} + </tbody> + </table> +{% endif %} +{% if link.fields|with_location:'query' %} + <h4>Query Parameters</h4> + <p>The following parameters should be included as part of a URL query string.</p> + <table class="parameters table table-bordered table-striped"> + <thead> + <tr><th>Parameter</th><th>Description</th></tr> + </thead> + <tbody> + {% for field in link.fields|with_location:'query' %} + <tr><td class="parameter-name"><code>{{ field.name }}</code>{% if field.required %} <span class="label label-warning">required</span>{% endif %}</td><td>{% if field.schema.description %}{{ field.schema.description|safe }}{% endif %}</td></tr> + {% endfor %} + </tbody> + </table> +{% endif %} +{% if link.fields|with_location:'header' %} + <h4>Header Parameters</h4> + <p>The following parameters should be included as HTTP headers.</p> + <table class="parameters table table-bordered table-striped"> + <thead> + <tr><th>Parameter</th><th>Description</th></tr> + </thead> + <tbody> + {% for field in link.fields|with_location:'header' %} + <tr><td class="parameter-name"><code>{{ field.name }}</code>{% if field.required %} <span class="label label-warning">required</span>{% endif %}</td><td>{% if field.schema.description %}{{ field.schema.description|safe }}{% endif %}</td></tr> + {% endfor %} + </tbody> + </table> +{% endif %} +{% if link.fields|with_location:'body' %} + <h4>Request Body</h4> + <p>The request body should be <code>"{{ link.encoding }}"</code> encoded, and should contain a single item.</p> + <table class="parameters table table-bordered table-striped"> + <thead> + <tr><th>Parameter</th><th>Description</th></tr> + </thead> + <tbody> + {% for field in link.fields|with_location:'body' %} + <tr><td class="parameter-name"><code>{{ field.name }}</code>{% if field.required %} <span class="label label-warning">required</span>{% endif %}</td><td>{% if field.schema.description %}{{ field.schema.description|safe }}{% endif %}</td></tr> + {% endfor %} + </tbody> + </table> +{% elif link.fields|with_location:'form' %} + <h4>Request Body</h4> + <p>The request body should be a <code>"{{ link.encoding }}"</code> encoded object, containing the following items.</p> + <table class="parameters table table-bordered table-striped"> + <thead> + <tr><th>Parameter</th><th>Description</th></tr> + </thead> + <tbody> + {% for field in link.fields|with_location:'form' %} + <tr><td class="parameter-name"><code>{{ field.name }}</code>{% if field.required %} <span class="label label-warning">required</span>{% endif %}</td><td>{% if field.schema.description %}{{ field.schema.description|safe }}{% endif %}</td></tr> + {% endfor %} + </tbody> + </table> +{% endif %} + +</div> + + <div class="col-md-6 code-samples"> + {% for html in lang_htmls %} + {% include html %} + {% endfor %} + </div> +</div> + +{% include "rest_framework/docs/interact.html" with link=link %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/sidebar.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/sidebar.html new file mode 100644 index 0000000000000000000000000000000000000000..c318789f6808d205d457c4f0840e9ce5bf08dc42 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/docs/sidebar.html @@ -0,0 +1,44 @@ +{% load rest_framework %} +<div class="sidebar"> + <h3 class="brand"><a href="#">{{ document.title }}</a></h3> + + <i class="fa fa-bars fa-2x toggle-btn" data-toggle="collapse" data-target="#menu-content"></i> + <div class="menu-list"> + <ul id="menu-content" class="menu-content collapse out"> + {% if document|data %} + {% for section_key, section in document|data|items %} + <li data-toggle="collapse" data-target="#{{ section_key }}-dropdown" class="collapsed"> + <a><i class="fa fa-dot-circle-o fa-lg"></i> {% if section_key %}{{ section_key }}{% else %}API Endpoints{% endif %} <span class="arrow"></span></a> + <ul class="sub-menu {% if section_key %}collapse{% endif %}" id="{{ section_key }}-dropdown"> + {% for link_key, link in section|schema_links|items %} + <li><a href="#{{ section_key }}-{{ link_key|slugify }}">{{ link.title|default:link_key }}</a></li> + {% endfor %} + </ul> + </li> + {% endfor %} + {% endif %} + </ul> + + <ul class="menu-list menu-list-bottom"> + <li data-toggle="collapse" data-target="#auth-control" class="collapsed"> + <a><i class="fa fa-user fa-lg"></i> Authentication</a> <span id="selected-authentication">{% if user.is_authenticated %}session{% else %}none{% endif %}</span> + </li> + <ul class="sub-menu collapse out" id="auth-control"> + <li {% if not user.is_authenticated %}class="active"{% endif %}><a data-auth="none" href="#">none</a></li> + <li><a data-auth="token" data-toggle="modal" data-target="#auth_token_modal" href="#">token</a></li> + <li><a data-auth="basic" data-toggle="modal" data-target="#auth_basic_modal" href="#">basic</a></li> + <li {% if user.is_authenticated %}class="active"{% endif %}><a data-auth="session" data-toggle="modal" data-target="#auth_session_modal" href="#">session</a></li> + </ul> + + <li data-toggle="collapse" data-target="#language-control" class="collapsed"> + <a><i class="fa fa-code fa-lg"></i> Source Code</a> <span id="selected-language">{{ langs | first }}</span> + </li> + <ul class="sub-menu collapse out" id="language-control"> + {% for lang in langs %} + <li{% if loop.first %} class="active"{% endif %}><a href="#" data-language="{{ lang }}">{{ lang }}</a></li> + {% endfor %} + </ul> + </ul> + + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/base.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/base.html new file mode 100644 index 0000000000000000000000000000000000000000..f830e16baa16ff532b50c6a9ceca17087a28086e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/base.html @@ -0,0 +1,16 @@ +<div class="modal fade" id="filtersModal" tabindex="-1" role="dialog" aria-labelledby="filters" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title">Filters</h4> + </div> + <div class="modal-body"> + {% for element in elements %} + {% if not forloop.first %}<hr/>{% endif %} + {{ element }} + {% endfor %} + </div> + </div> + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/ordering.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/ordering.html new file mode 100644 index 0000000000000000000000000000000000000000..b71b2a5bf1e2bc0c24008365facfbd637ddaec4a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/ordering.html @@ -0,0 +1,14 @@ +{% load rest_framework %} +{% load i18n %} +<h2>{% trans "Ordering" %}</h2> +<div class="list-group"> + {% for key, label in options %} + {% if key == current %} + <a href="{% add_query_param request param key %}" class="list-group-item active"> + <span class="glyphicon glyphicon-ok" style="float: right" aria-hidden="true"></span> {{ label }} + </a> + {% else %} + <a href="{% add_query_param request param key %}" class="list-group-item">{{ label }}</a> + {% endif %} + {% endfor %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/search.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/search.html new file mode 100644 index 0000000000000000000000000000000000000000..065c3889ac2ee54dccabb5c32a127f497768e097 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/filters/search.html @@ -0,0 +1,12 @@ +{% load i18n %} +<h2>{% trans "Search" %}</h2> +<form class="form-inline"> + <div class="form-group"> + <div class="input-group"> + <input type="text" class="form-control" style="width: 350px" name="{{ param }}" value="{{ term }}"> + <span class="input-group-btn"> + <button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> {% trans "Search" %}</button> + </span> + </div> + </div> +</form> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox.html new file mode 100644 index 0000000000000000000000000000000000000000..faaebb8836a43345ba8a99de9f9fede10cbeba71 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox.html @@ -0,0 +1,21 @@ +<div class="form-group horizontal-checkbox {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <input type="checkbox" name="{{ field.name }}" value="true" {% if field.value %}checked{% endif %}> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..42b47a428600569c1716da3caaf6c64c7c346518 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/checkbox_multiple.html @@ -0,0 +1,39 @@ +{% load rest_framework %} + +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + {% if style.inline %} + {% for key, text in field.choices|items %} + <label class="checkbox-inline"> + <input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}> + {{ text }} + </label> + {% endfor %} + {% else %} + {% for key, text in field.choices|items %} + <div class="checkbox"> + <label> + <input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}> + {{ text }} + </label> + </div> + {% endfor %} + {% endif %} + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/dict_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/dict_field.html new file mode 100644 index 0000000000000000000000000000000000000000..7c7414bc4ba1854b4ad51d3edbcd66f294f72ae2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/dict_field.html @@ -0,0 +1,11 @@ +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <p class="form-control-static">Dictionaries are not currently supported in HTML input.</p> + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..1747d25536157985099d3da934f161cf20b5d064 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/fieldset.html @@ -0,0 +1,16 @@ +{% load rest_framework %} +<fieldset> + {% if field.label %} + <div class="form-group" style="border-bottom: 1px solid #e5e5e5"> + <legend class="control-label col-sm-2 {% if style.hide_label %}sr-only{% endif %}" style="border-bottom: 0"> + {{ field.label }} + </legend> + </div> + {% endif %} + + {% for nested_field in field %} + {% if not nested_field.read_only %} + {% render_field nested_field style=style %} + {% endif %} + {% endfor %} +</fieldset> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/form.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/form.html new file mode 100644 index 0000000000000000000000000000000000000000..13fc807eb45e9d069391fe2ad57884aeff872b26 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/form.html @@ -0,0 +1,6 @@ +{% load rest_framework %} +{% for field in form %} + {% if not field.read_only %} + {% render_field field style=style %} + {% endif %} +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/input.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/input.html new file mode 100644 index 0000000000000000000000000000000000000000..b9081000819c732e1de42548c9aa6d79266e6970 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/input.html @@ -0,0 +1,21 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value is not None %}value="{{ field.value }}"{% endif %} {% if style.autofocus and style.input_type != "hidden" %}autofocus{% endif %}> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_field.html new file mode 100644 index 0000000000000000000000000000000000000000..46a9b7ecdf6c9812a1e72e90ce7239840c2705de --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_field.html @@ -0,0 +1,11 @@ +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <p class="form-control-static">Lists are not currently supported in HTML input.</p> + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..962c333c0a76a1f9eae4fa9956dfd73f5db90f29 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/list_fieldset.html @@ -0,0 +1,13 @@ +{% load rest_framework %} + +<fieldset> + {% if field.label %} + <div class="form-group" style="border-bottom: 1px solid #e5e5e5"> + <legend class="control-label col-sm-2 {% if style.hide_label %}sr-only{% endif %}" style="border-bottom: 0"> + {{ field.label }} + </legend> + </div> + {% endif %} + + <p>Lists are not currently supported in HTML input.</p> +</fieldset> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/radio.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/radio.html new file mode 100644 index 0000000000000000000000000000000000000000..17104733828bcf1226f3d72e610826b5c7bd9f97 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/radio.html @@ -0,0 +1,57 @@ +{% load i18n %} +{% load rest_framework %} + +{% trans "None" as none_choice %} + +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + {% if style.inline %} + {% if field.allow_null or field.allow_blank %} + <label class="radio-inline"> + <input type="radio" name="{{ field.name }}" value="" {% if not field.value %}checked{% endif %} /> + {{ none_choice }} + </label> + {% endif %} + + {% for key, text in field.choices|items %} + <label class="radio-inline"> + <input type="radio" name="{{ field.name }}" value="{{ key }}" {% if key|as_string == field.value|as_string %}checked{% endif %} /> + {{ text }} + </label> + {% endfor %} + {% else %} + {% if field.allow_null or field.allow_blank %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="" {% if not field.value %}checked{% endif %} /> + {{ none_choice }} + </label> + </div> + {% endif %} + {% for key, text in field.choices|items %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="{{ key }}" {% if key|as_string == field.value|as_string %}checked{% endif %} /> + {{ text }} + </label> + </div> + {% endfor %} + {% endif %} + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select.html new file mode 100644 index 0000000000000000000000000000000000000000..7a3db2db808a793b1faf41c48ed348f34ea9480d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select.html @@ -0,0 +1,36 @@ +{% load rest_framework %} + +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <select class="form-control" name="{{ field.name }}"> + {% if field.allow_null or field.allow_blank %} + <option value="" {% if not field.value %}selected{% endif %}>--------</option> + {% endif %} + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string == field.value|as_string %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% endfor %} + </select> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..36ff9fd0dc8f8705f6813216ce1c9250fea3f32f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/select_multiple.html @@ -0,0 +1,38 @@ +{% load i18n %} +{% load rest_framework %} + +{% trans "No items to select." as no_items %} + +<div class="form-group"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <select multiple {{ field.choices|yesno:",disabled" }} class="form-control" name="{{ field.name }}"> + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string in field.value|as_list_of_strings %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% empty %} + <option>{{ no_items }}</option> + {% endfor %} + </select> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/textarea.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/textarea.html new file mode 100644 index 0000000000000000000000000000000000000000..b279a2f681d94510e2523bd8055291db76c49cb0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/horizontal/textarea.html @@ -0,0 +1,21 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}"> + {{ field.label }} + </label> + {% endif %} + + <div class="col-sm-10"> + <textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.value %}{{ field.value }}{% endif %}</textarea> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox.html new file mode 100644 index 0000000000000000000000000000000000000000..665249a524e667a77e37fab767427ee73c511718 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox.html @@ -0,0 +1,8 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + <div class="checkbox"> + <label> + <input type="checkbox" name="{{ field.name }}" value="true" {% if field.value %}checked{% endif %}> + {% if field.label %}{{ field.label }}{% endif %} + </label> + </div> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..e95c46d872944fc684107c086108f53fbd072749 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/checkbox_multiple.html @@ -0,0 +1,16 @@ +{% load rest_framework %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only">{{ field.label }}</label> + {% endif %} + + {% for key, text in field.choices|items %} + <div class="checkbox"> + <label> + <input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}> + {{ text }} + </label> + </div> + {% endfor %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/dict_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/dict_field.html new file mode 100644 index 0000000000000000000000000000000000000000..1301452b90e9ee3f2a054cd58db0b1415ac02a54 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/dict_field.html @@ -0,0 +1,9 @@ +<div class="form-group"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <p class="form-control-static">Dictionaries are not currently supported in HTML input.</p> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..44feef889e3ef8832b562d27f747b4c2e9f09082 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/fieldset.html @@ -0,0 +1,6 @@ +{% load rest_framework %} +{% for nested_field in field %} + {% if not nested_field.read_only %} + {% render_field nested_field style=style %} + {% endif %} +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/form.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/form.html new file mode 100644 index 0000000000000000000000000000000000000000..13fc807eb45e9d069391fe2ad57884aeff872b26 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/form.html @@ -0,0 +1,6 @@ +{% load rest_framework %} +{% for field in form %} + {% if not field.read_only %} + {% render_field field style=style %} + {% endif %} +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/input.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/input.html new file mode 100644 index 0000000000000000000000000000000000000000..26cdcb70c02ecae68fa7e4ce7acd4e09cc3287f0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/input.html @@ -0,0 +1,9 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value is not None %}value="{{ field.value }}"{% endif %} {% if style.autofocus and style.input_type != "hidden" %}autofocus{% endif %}> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_field.html new file mode 100644 index 0000000000000000000000000000000000000000..321d01bd1d20424e4bb89ab125f0f47507efed86 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_field.html @@ -0,0 +1,9 @@ +<div class="form-group"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <p class="form-control-static">Lists are not currently supported in HTML input.</p> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..2ae56d7cd952445099d44fb4bd9b096c874dc316 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/list_fieldset.html @@ -0,0 +1 @@ +<span>Lists are not currently supported in HTML input.</span> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/radio.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/radio.html new file mode 100644 index 0000000000000000000000000000000000000000..38fac449ba4ddc7e8264fe58b4b8a6bbe6c513bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/radio.html @@ -0,0 +1,29 @@ +{% load i18n %} +{% load rest_framework %} +{% trans "None" as none_choice %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + {% if field.allow_null or field.allow_blank %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="" {% if not field.value %}checked{% endif %}> + {{ none_choice }} + </label> + </div> + {% endif %} + + {% for key, text in field.choices|items %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="{{ key }}" {% if key|as_string == field.value|as_string %}checked{% endif %}> + {{ text }} + </label> + </div> + {% endfor %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select.html new file mode 100644 index 0000000000000000000000000000000000000000..5023c220383a45cac4430d0b68eabcd0e33cd92c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select.html @@ -0,0 +1,24 @@ +{% load rest_framework %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <select class="form-control" name="{{ field.name }}"> + {% if field.allow_null or field.allow_blank %} + <option value="" {% if not field.value %}selected{% endif %}>--------</option> + {% endif %} + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string == field.value|as_string %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% endfor %} + </select> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..b5fd46f8b4c1bb8a01ee4c4d29a8fbe8861e8e75 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/select_multiple.html @@ -0,0 +1,25 @@ +{% load i18n %} +{% load rest_framework %} +{% trans "No items to select." as no_items %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <select multiple {{ field.choices|yesno:",disabled" }} class="form-control" name="{{ field.name }}"> + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string in field.value|as_list_of_strings %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% empty %} + <option>{{ no_items }}</option> + {% endfor %} + </select> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/textarea.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/textarea.html new file mode 100644 index 0000000000000000000000000000000000000000..bce427faa93ac848dfc4be15f2cbcd795253b203 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/inline/textarea.html @@ -0,0 +1,9 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label class="sr-only"> + {{ field.label }} + </label> + {% endif %} + + <input name="{{ field.name }}" type="text" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login.html new file mode 100644 index 0000000000000000000000000000000000000000..b76293279a5c27ffa5b08602e26ee3a7830fd2e6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login.html @@ -0,0 +1,3 @@ +{% extends "rest_framework/login_base.html" %} + +{# Override this template in your own templates directory to customize #} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login_base.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login_base.html new file mode 100644 index 0000000000000000000000000000000000000000..ba48917088e72d6ff236630bc823e9ceecde0edd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/login_base.html @@ -0,0 +1,65 @@ +{% extends "rest_framework/base.html" %} +{% load rest_framework %} + +{% block body %} +<body class="container"> + <div class="container-fluid" style="margin-top: 30px"> + <div class="row-fluid"> + <div class="well" style="width: 320px; margin-left: auto; margin-right: auto"> + <div class="row-fluid"> + <div> + {% block branding %}<h3 style="margin: 0 0 20px;">Django REST framework</h3>{% endblock %} + </div> + </div><!-- /row fluid --> + + <div class="row-fluid"> + <div> + <form action="{% url 'rest_framework:login' %}" role="form" method="post"> + {% csrf_token %} + <input type="hidden" name="next" value="{{ next }}" /> + + <div id="div_id_username" class="clearfix control-group {% if form.username.errors %}error{% endif %}"> + <div class="form-group"> + <label for="id_username">{{ form.username.label }}:</label> + <input type="text" name="username" maxlength="100" + autocapitalize="off" + autocorrect="off" class="form-control textinput textInput" + id="id_username" required autofocus + {% if form.username.value %}value="{{ form.username.value }}"{% endif %}> + {% if form.username.errors %} + <p class="text-error"> + {{ form.username.errors|striptags }} + </p> + {% endif %} + </div> + </div> + + <div id="div_id_password" class="clearfix control-group {% if form.password.errors %}error{% endif %}"> + <div class="form-group"> + <label for="id_password">{{ form.password.label }}:</label> + <input type="password" name="password" maxlength="100" autocapitalize="off" autocorrect="off" class="form-control textinput textInput" id="id_password" required> + {% if form.password.errors %} + <p class="text-error"> + {{ form.password.errors|striptags }} + </p> + {% endif %} + </div> + </div> + + {% if form.non_field_errors %} + {% for error in form.non_field_errors %} + <div class="well well-small text-error" style="border: none">{{ error }}</div> + {% endfor %} + {% endif %} + + <div class="form-actions-no-box"> + <input type="submit" name="submit" value="Log in" class="btn btn-primary form-control" id="submit-id-submit"> + </div> + </form> + </div> + </div><!-- /.row-fluid --> + </div><!--/.well--> + </div><!-- /.row-fluid --> + </div><!-- /.container-fluid --> +</body> +{% endblock %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/numbers.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/numbers.html new file mode 100644 index 0000000000000000000000000000000000000000..4ff9385f69478584917009b317256d5ad5a458ce --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/numbers.html @@ -0,0 +1,47 @@ +<ul class="pagination" style="margin: 5px 0 10px 0"> + {% if previous_url %} + <li> + <a href="{{ previous_url }}" aria-label="Previous"> + <span aria-hidden="true">«</span> + </a> + </li> + {% else %} + <li class="disabled"> + <a href="#" aria-label="Previous"> + <span aria-hidden="true">«</span> + </a> + </li> + {% endif %} + + {% for page_link in page_links %} + {% if page_link.is_break %} + <li class="disabled"> + <a href="#"><span aria-hidden="true">…</span></a> + </li> + {% else %} + {% if page_link.is_active %} + <li class="active"> + <a href="{{ page_link.url }}">{{ page_link.number }}</a> + </li> + {% else %} + <li> + <a href="{{ page_link.url }}">{{ page_link.number }}</a> + </li> + {% endif %} + {% endif %} + {% endfor %} + + {% if next_url %} + <li> + <a href="{{ next_url }}" aria-label="Next"> + <span aria-hidden="true">»</span> + </a> + </li> + {% else %} + <li class="disabled"> + <a href="#" aria-label="Next"> + <span aria-hidden="true">»</span> + </a> + </li> + {% endif %} +</ul> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/previous_and_next.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/previous_and_next.html new file mode 100644 index 0000000000000000000000000000000000000000..5563c4b67acec70eabd526819d17041a613c6f57 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/pagination/previous_and_next.html @@ -0,0 +1,21 @@ +<ul class="pager"> + {% if previous_url %} + <li class="previous"> + <a href="{{ previous_url }}">« Previous</a> + </li> + {% else %} + <li class="previous disabled"> + <a href="#">« Previous</a> + </li> + {% endif %} + + {% if next_url %} + <li class="next"> + <a href="{{ next_url }}">Next »</a> + </li> + {% else %} + <li class="next disabled"> + <a href="#">Next »</a> + </li> + {% endif %} +</ul> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/raw_data_form.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/raw_data_form.html new file mode 100644 index 0000000000000000000000000000000000000000..d2798320644d88c16117dc09e39afe9b75ccf6df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/raw_data_form.html @@ -0,0 +1,11 @@ +{% load rest_framework %} +{{ form.non_field_errors }} +{% for field in form %} + <div class="form-group"> + {{ field.label_tag|add_class:"col-sm-2 control-label" }} + <div class="col-sm-10"> + {{ field|add_class:"form-control" }} + <span class="help-block">{{ field.help_text|safe }}</span> + </div> + </div> +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/schema.js b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/schema.js new file mode 100644 index 0000000000000000000000000000000000000000..692cb90466e332fc45217ec5dc9d0e93d9b42bba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/schema.js @@ -0,0 +1,3 @@ +var codec = new window.coreapi.codecs.CoreJSONCodec() +var coreJSON = window.atob('{{ schema }}') +window.schema = codec.decode(coreJSON) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox.html new file mode 100644 index 0000000000000000000000000000000000000000..827ad8af42e2481ee19664db2b2a8c055e0365c5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox.html @@ -0,0 +1,18 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + <div class="checkbox"> + <label> + <input type="checkbox" name="{{ field.name }}" value="true" {% if field.value %}checked{% endif %}> + {% if field.label %}{{ field.label }}{% endif %} + </label> + </div> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..1bc13dfcfbdcfa63b1ba00827666e4abcf9da07f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/checkbox_multiple.html @@ -0,0 +1,37 @@ +{% load rest_framework %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label> + {% endif %} + + {% if style.inline %} + <div> + {% for key, text in field.choices|items %} + <label class="checkbox-inline"> + <input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}> + {{ text }} + </label> + {% endfor %} + </div> + {% else %} + {% for key, text in field.choices|items %} + <div class="checkbox"> + <label> + <input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}> + {{ text }} + </label> + </div> + {% endfor %} + {% endif %} + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/dict_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/dict_field.html new file mode 100644 index 0000000000000000000000000000000000000000..dde803b4924e731a6c602851ee9f5f0f1d230e0e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/dict_field.html @@ -0,0 +1,7 @@ +<div class="form-group"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label> + {% endif %} + + <p class="form-control-static">Dictionaries are not currently supported in HTML input.</p> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..4ec2a5d4892660b1256173ccc95680388a373799 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/fieldset.html @@ -0,0 +1,15 @@ +{% load rest_framework %} + +<fieldset> + {% if field.label %} + <legend {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </legend> + {% endif %} + + {% for nested_field in field %} + {% if not nested_field.read_only %} + {% render_field nested_field style=style %} + {% endif %} + {% endfor %} +</fieldset> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/form.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/form.html new file mode 100644 index 0000000000000000000000000000000000000000..13fc807eb45e9d069391fe2ad57884aeff872b26 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/form.html @@ -0,0 +1,6 @@ +{% load rest_framework %} +{% for field in form %} + {% if not field.read_only %} + {% render_field field style=style %} + {% endif %} +{% endfor %} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/input.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/input.html new file mode 100644 index 0000000000000000000000000000000000000000..29c4370d5f32a286800217a489e56463fd450566 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/input.html @@ -0,0 +1,17 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label> + {% endif %} + + <input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value is not None %}value="{{ field.value }}"{% endif %} {% if style.autofocus and style.input_type != "hidden" %}autofocus{% endif %}> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_field.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_field.html new file mode 100644 index 0000000000000000000000000000000000000000..47a60c5d91b6619fc76a0d95c12197d6a206608d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_field.html @@ -0,0 +1,7 @@ +<div class="form-group"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label> + {% endif %} + + <p class="form-control-static">Lists are not currently supported in HTML input.</p> +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_fieldset.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_fieldset.html new file mode 100644 index 0000000000000000000000000000000000000000..f2b615fe10375b4dc2671a6bfa38831c811b51fb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/list_fieldset.html @@ -0,0 +1,9 @@ +<fieldset> + {% if field.label %} + <legend {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </legend> + {% endif %} + + <p>Lists are not currently supported in HTML input.</p> +</fieldset> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/radio.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/radio.html new file mode 100644 index 0000000000000000000000000000000000000000..39b3c71502a712dc245a51aad44a3e2719a491bd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/radio.html @@ -0,0 +1,57 @@ +{% load i18n %} +{% load rest_framework %} +{% trans "None" as none_choice %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </label> + {% endif %} + + {% if style.inline %} + <div> + {% if field.allow_null or field.allow_blank %} + <label class="radio-inline"> + <input type="radio" name="{{ field.name }}" value="" {% if not field.value %}checked{% endif %} /> + {{ none_choice }} + </label> + {% endif %} + + {% for key, text in field.choices|items %} + <label class="radio-inline"> + <input type="radio" name="{{ field.name }}" value="{{ key }}" {% if key|as_string == field.value|as_string %}checked{% endif %}> + {{ text }} + </label> + {% endfor %} + </div> + {% else %} + {% if field.allow_null or field.allow_blank %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="" {% if not field.value %}checked{% endif %} /> + {{ none_choice }} + </label> + </div> + {% endif %} + + {% for key, text in field.choices|items %} + <div class="radio"> + <label> + <input type="radio" name="{{ field.name }}" value="{{ key }}" {% if key|as_string == field.value|as_string %}checked{% endif %}> + {{ text }} + </label> + </div> + {% endfor %} + {% endif %} + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select.html new file mode 100644 index 0000000000000000000000000000000000000000..6ccaaf27faaa9e0c514677a6aba8f7d28b74f645 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select.html @@ -0,0 +1,34 @@ +{% load rest_framework %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </label> + {% endif %} + + <select class="form-control" name="{{ field.name }}"> + {% if field.allow_null or field.allow_blank %} + <option value="" {% if not field.value %}selected{% endif %}>--------</option> + {% endif %} + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string == field.value|as_string %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% endfor %} + </select> + + {% if field.errors %} + {% for error in field.errors %} + <span class="help-block">{{ error }}</span> + {% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select_multiple.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select_multiple.html new file mode 100644 index 0000000000000000000000000000000000000000..b77c4be3bc4a31ea3eeb3e13d27b8d4c7566fee7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/select_multiple.html @@ -0,0 +1,33 @@ +{% load i18n %} +{% load rest_framework %} +{% trans "No items to select." as no_items %} + +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </label> + {% endif %} + + <select multiple {{ field.choices|yesno:",disabled" }} class="form-control" name="{{ field.name }}"> + {% for select in field.iter_options %} + {% if select.start_option_group %} + <optgroup label="{{ select.label }}"> + {% elif select.end_option_group %} + </optgroup> + {% else %} + <option value="{{ select.value }}" {% if select.value|as_string in field.value|as_list_of_strings %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option> + {% endif %} + {% empty %} + <option>{{ no_items }}</option> + {% endfor %} + </select> + + {% if field.errors %} + {% for error in field.errors %}<span class="help-block">{{ error }}</span>{% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/textarea.html b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/textarea.html new file mode 100644 index 0000000000000000000000000000000000000000..fea94cd06bcae36bf3418e8f67dbd2faaa2f88ba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templates/rest_framework/vertical/textarea.html @@ -0,0 +1,17 @@ +<div class="form-group {% if field.errors %}has-error{% endif %}"> + {% if field.label %} + <label {% if style.hide_label %}class="sr-only"{% endif %}> + {{ field.label }} + </label> + {% endif %} + + <textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.value %}{{ field.value }}{% endif %}</textarea> + + {% if field.errors %} + {% for error in field.errors %}<span class="help-block">{{ error }}</span>{% endfor %} + {% endif %} + + {% if field.help_text %} + <span class="help-block">{{ field.help_text|safe }}</span> + {% endif %} +</div> diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..342cb3f166511aae6ac45c6d4217b3178a3ae8a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/rest_framework.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/rest_framework.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3b72b0eeb3e4c4dd6120214b157a2ed82fe00e3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/__pycache__/rest_framework.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/rest_framework.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/rest_framework.py new file mode 100644 index 0000000000000000000000000000000000000000..ccd9430b4e6b831aa5bba933667f0add85916a06 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/templatetags/rest_framework.py @@ -0,0 +1,322 @@ +import re +from collections import OrderedDict + +from django import template +from django.template import loader +from django.urls import NoReverseMatch, reverse +from django.utils.encoding import iri_to_uri +from django.utils.html import escape, format_html, smart_urlquote +from django.utils.safestring import mark_safe + +from rest_framework.compat import apply_markdown, pygments_highlight +from rest_framework.renderers import HTMLFormRenderer +from rest_framework.utils.urls import replace_query_param + +register = template.Library() + +# Regex for adding classes to html snippets +class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') + + +@register.tag(name='code') +def highlight_code(parser, token): + code = token.split_contents()[-1] + nodelist = parser.parse(('endcode',)) + parser.delete_first_token() + return CodeNode(code, nodelist) + + +class CodeNode(template.Node): + style = 'emacs' + + def __init__(self, lang, code): + self.lang = lang + self.nodelist = code + + def render(self, context): + text = self.nodelist.render(context) + return pygments_highlight(text, self.lang, self.style) + + +@register.filter() +def with_location(fields, location): + return [ + field for field in fields + if field.location == location + ] + + +@register.simple_tag +def form_for_link(link): + import coreschema + properties = OrderedDict([ + (field.name, field.schema or coreschema.String()) + for field in link.fields + ]) + required = [ + field.name + for field in link.fields + if field.required + ] + schema = coreschema.Object(properties=properties, required=required) + return mark_safe(coreschema.render_to_form(schema)) + + +@register.simple_tag +def render_markdown(markdown_text): + if apply_markdown is None: + return markdown_text + return mark_safe(apply_markdown(markdown_text)) + + +@register.simple_tag +def get_pagination_html(pager): + return pager.to_html() + + +@register.simple_tag +def render_form(serializer, template_pack=None): + style = {'template_pack': template_pack} if template_pack else {} + renderer = HTMLFormRenderer() + return renderer.render(serializer.data, None, {'style': style}) + + +@register.simple_tag +def render_field(field, style): + renderer = style.get('renderer', HTMLFormRenderer()) + return renderer.render_field(field, style) + + +@register.simple_tag +def optional_login(request): + """ + Include a login snippet if REST framework's login view is in the URLconf. + """ + try: + login_url = reverse('rest_framework:login') + except NoReverseMatch: + return '' + + snippet = "<li><a href='{href}?next={next}'>Log in</a></li>" + snippet = format_html(snippet, href=login_url, next=escape(request.path)) + + return mark_safe(snippet) + + +@register.simple_tag +def optional_docs_login(request): + """ + Include a login snippet if REST framework's login view is in the URLconf. + """ + try: + login_url = reverse('rest_framework:login') + except NoReverseMatch: + return 'log in' + + snippet = "<a href='{href}?next={next}'>log in</a>" + snippet = format_html(snippet, href=login_url, next=escape(request.path)) + + return mark_safe(snippet) + + +@register.simple_tag +def optional_logout(request, user): + """ + Include a logout snippet if REST framework's logout view is in the URLconf. + """ + try: + logout_url = reverse('rest_framework:logout') + except NoReverseMatch: + snippet = format_html('<li class="navbar-text">{user}</li>', user=escape(user)) + return mark_safe(snippet) + + snippet = """<li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> + {user} + <b class="caret"></b> + </a> + <ul class="dropdown-menu"> + <li><a href='{href}?next={next}'>Log out</a></li> + </ul> + </li>""" + snippet = format_html(snippet, user=escape(user), href=logout_url, next=escape(request.path)) + + return mark_safe(snippet) + + +@register.simple_tag +def add_query_param(request, key, val): + """ + Add a query parameter to the current request url, and return the new url. + """ + iri = request.get_full_path() + uri = iri_to_uri(iri) + return escape(replace_query_param(uri, key, val)) + + +@register.filter +def as_string(value): + if value is None: + return '' + return '%s' % value + + +@register.filter +def as_list_of_strings(value): + return [ + '' if (item is None) else ('%s' % item) + for item in value + ] + + +@register.filter +def add_class(value, css_class): + """ + https://stackoverflow.com/questions/4124220/django-adding-css-classes-when-rendering-form-fields-in-a-template + + Inserts classes into template variables that contain HTML tags, + useful for modifying forms without needing to change the Form objects. + + Usage: + + {{ field.label_tag|add_class:"control-label" }} + + In the case of REST Framework, the filter is used to add Bootstrap-specific + classes to the forms. + """ + html = str(value) + match = class_re.search(html) + if match: + m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, + css_class, css_class), + match.group(1)) + if not m: + return mark_safe(class_re.sub(match.group(1) + " " + css_class, + html)) + else: + return mark_safe(html.replace('>', ' class="%s">' % css_class, 1)) + return value + + +@register.filter +def format_value(value): + if getattr(value, 'is_hyperlink', False): + name = str(value.obj) + return mark_safe('<a href=%s>%s</a>' % (value, escape(name))) + if value is None or isinstance(value, bool): + return mark_safe('<code>%s</code>' % {True: 'true', False: 'false', None: 'null'}[value]) + elif isinstance(value, list): + if any(isinstance(item, (list, dict)) for item in value): + template = loader.get_template('rest_framework/admin/list_value.html') + else: + template = loader.get_template('rest_framework/admin/simple_list_value.html') + context = {'value': value} + return template.render(context) + elif isinstance(value, dict): + template = loader.get_template('rest_framework/admin/dict_value.html') + context = {'value': value} + return template.render(context) + elif isinstance(value, str): + if ( + (value.startswith('http:') or value.startswith('https:') or value.startswith('/')) and not + re.search(r'\s', value) + ): + return mark_safe('<a href="{value}">{value}</a>'.format(value=escape(value))) + elif '@' in value and not re.search(r'\s', value): + return mark_safe('<a href="mailto:{value}">{value}</a>'.format(value=escape(value))) + elif '\n' in value: + return mark_safe('<pre>%s</pre>' % escape(value)) + return str(value) + + +@register.filter +def items(value): + """ + Simple filter to return the items of the dict. Useful when the dict may + have a key 'items' which is resolved first in Django template dot-notation + lookup. See issue #4931 + Also see: https://stackoverflow.com/questions/15416662/django-template-loop-over-dictionary-items-with-items-as-key + """ + if value is None: + # `{% for k, v in value.items %}` doesn't raise when value is None or + # not in the context, so neither should `{% for k, v in value|items %}` + return [] + return value.items() + + +@register.filter +def data(value): + """ + Simple filter to access `data` attribute of object, + specifically coreapi.Document. + + As per `items` filter above, allows accessing `document.data` when + Document contains Link keyed-at "data". + + See issue #5395 + """ + return value.data + + +@register.filter +def schema_links(section, sec_key=None): + """ + Recursively find every link in a schema, even nested. + """ + NESTED_FORMAT = '%s > %s' # this format is used in docs/js/api.js:normalizeKeys + links = section.links + if section.data: + data = section.data.items() + for sub_section_key, sub_section in data: + new_links = schema_links(sub_section, sec_key=sub_section_key) + links.update(new_links) + + if sec_key is not None: + new_links = OrderedDict() + for link_key, link in links.items(): + new_key = NESTED_FORMAT % (sec_key, link_key) + new_links.update({new_key: link}) + return new_links + + return links + + +@register.filter +def add_nested_class(value): + if isinstance(value, dict): + return 'class=nested' + if isinstance(value, list) and any(isinstance(item, (list, dict)) for item in value): + return 'class=nested' + return '' + + +# Bunch of stuff cloned from urlize +TRAILING_PUNCTUATION = ['.', ',', ':', ';', '.)', '"', "']", "'}", "'"] +WRAPPING_PUNCTUATION = [('(', ')'), ('<', '>'), ('[', ']'), ('<', '>'), + ('"', '"'), ("'", "'")] +word_split_re = re.compile(r'(\s+)') +simple_url_re = re.compile(r'^https?://\[?\w', re.IGNORECASE) +simple_url_2_re = re.compile(r'^www\.|^(?!http)\w[^@]+\.(com|edu|gov|int|mil|net|org)$', re.IGNORECASE) +simple_email_re = re.compile(r'^\S+@\S+\.\S+$') + + +def smart_urlquote_wrapper(matched_url): + """ + Simple wrapper for smart_urlquote. ValueError("Invalid IPv6 URL") can + be raised here, see issue #1386 + """ + try: + return smart_urlquote(matched_url) + except ValueError: + return None + + +@register.filter +def break_long_headers(header): + """ + Breaks headers longer than 160 characters (~page length) + when possible (are comma separated) + """ + if len(header) > 160 and ',' in header: + header = mark_safe('<br> ' + ', <br>'.join(header.split(','))) + return header diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/test.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/test.py new file mode 100644 index 0000000000000000000000000000000000000000..04409f9621da298fcb925a770239ddba3bfc0b6a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/test.py @@ -0,0 +1,412 @@ +# Note that we import as `DjangoRequestFactory` and `DjangoClient` in order +# to make it harder for the user to import the wrong thing without realizing. +import io +from importlib import import_module + +import django +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.core.handlers.wsgi import WSGIHandler +from django.test import override_settings, testcases +from django.test.client import Client as DjangoClient +from django.test.client import ClientHandler +from django.test.client import RequestFactory as DjangoRequestFactory +from django.utils.encoding import force_bytes +from django.utils.http import urlencode + +from rest_framework.compat import coreapi, requests +from rest_framework.settings import api_settings + + +def force_authenticate(request, user=None, token=None): + request._force_auth_user = user + request._force_auth_token = token + + +if requests is not None: + class HeaderDict(requests.packages.urllib3._collections.HTTPHeaderDict): + def get_all(self, key, default): + return self.getheaders(key) + + class MockOriginalResponse: + def __init__(self, headers): + self.msg = HeaderDict(headers) + self.closed = False + + def isclosed(self): + return self.closed + + def close(self): + self.closed = True + + class DjangoTestAdapter(requests.adapters.HTTPAdapter): + """ + A transport adapter for `requests`, that makes requests via the + Django WSGI app, rather than making actual HTTP requests over the network. + """ + def __init__(self): + self.app = WSGIHandler() + self.factory = DjangoRequestFactory() + + def get_environ(self, request): + """ + Given a `requests.PreparedRequest` instance, return a WSGI environ dict. + """ + method = request.method + url = request.url + kwargs = {} + + # Set request content, if any exists. + if request.body is not None: + if hasattr(request.body, 'read'): + kwargs['data'] = request.body.read() + else: + kwargs['data'] = request.body + if 'content-type' in request.headers: + kwargs['content_type'] = request.headers['content-type'] + + # Set request headers. + for key, value in request.headers.items(): + key = key.upper() + if key in ('CONNECTION', 'CONTENT-LENGTH', 'CONTENT-TYPE'): + continue + kwargs['HTTP_%s' % key.replace('-', '_')] = value + + return self.factory.generic(method, url, **kwargs).environ + + def send(self, request, *args, **kwargs): + """ + Make an outgoing request to the Django WSGI application. + """ + raw_kwargs = {} + + def start_response(wsgi_status, wsgi_headers, exc_info=None): + status, _, reason = wsgi_status.partition(' ') + raw_kwargs['status'] = int(status) + raw_kwargs['reason'] = reason + raw_kwargs['headers'] = wsgi_headers + raw_kwargs['version'] = 11 + raw_kwargs['preload_content'] = False + raw_kwargs['original_response'] = MockOriginalResponse(wsgi_headers) + + # Make the outgoing request via WSGI. + environ = self.get_environ(request) + wsgi_response = self.app(environ, start_response) + + # Build the underlying urllib3.HTTPResponse + raw_kwargs['body'] = io.BytesIO(b''.join(wsgi_response)) + raw = requests.packages.urllib3.HTTPResponse(**raw_kwargs) + + # Build the requests.Response + return self.build_response(request, raw) + + def close(self): + pass + + class RequestsClient(requests.Session): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + adapter = DjangoTestAdapter() + self.mount('http://', adapter) + self.mount('https://', adapter) + + def request(self, method, url, *args, **kwargs): + if not url.startswith('http'): + raise ValueError('Missing "http:" or "https:". Use a fully qualified URL, eg "http://testserver%s"' % url) + return super().request(method, url, *args, **kwargs) + +else: + def RequestsClient(*args, **kwargs): + raise ImproperlyConfigured('requests must be installed in order to use RequestsClient.') + + +if coreapi is not None: + class CoreAPIClient(coreapi.Client): + def __init__(self, *args, **kwargs): + self._session = RequestsClient() + kwargs['transports'] = [coreapi.transports.HTTPTransport(session=self.session)] + super().__init__(*args, **kwargs) + + @property + def session(self): + return self._session + +else: + def CoreAPIClient(*args, **kwargs): + raise ImproperlyConfigured('coreapi must be installed in order to use CoreAPIClient.') + + +class APIRequestFactory(DjangoRequestFactory): + renderer_classes_list = api_settings.TEST_REQUEST_RENDERER_CLASSES + default_format = api_settings.TEST_REQUEST_DEFAULT_FORMAT + + def __init__(self, enforce_csrf_checks=False, **defaults): + self.enforce_csrf_checks = enforce_csrf_checks + self.renderer_classes = {} + for cls in self.renderer_classes_list: + self.renderer_classes[cls.format] = cls + super().__init__(**defaults) + + def _encode_data(self, data, format=None, content_type=None): + """ + Encode the data returning a two tuple of (bytes, content_type) + """ + + if data is None: + return ('', content_type) + + assert format is None or content_type is None, ( + 'You may not set both `format` and `content_type`.' + ) + + if content_type: + # Content type specified explicitly, treat data as a raw bytestring + ret = force_bytes(data, settings.DEFAULT_CHARSET) + + else: + format = format or self.default_format + + assert format in self.renderer_classes, ( + "Invalid format '{}'. Available formats are {}. " + "Set TEST_REQUEST_RENDERER_CLASSES to enable " + "extra request formats.".format( + format, + ', '.join(["'" + fmt + "'" for fmt in self.renderer_classes]) + ) + ) + + # Use format and render the data into a bytestring + renderer = self.renderer_classes[format]() + ret = renderer.render(data) + + # Determine the content-type header from the renderer + content_type = renderer.media_type + if renderer.charset: + content_type = "{}; charset={}".format( + content_type, renderer.charset + ) + + # Coerce text to bytes if required. + if isinstance(ret, str): + ret = ret.encode(renderer.charset) + + return ret, content_type + + def get(self, path, data=None, **extra): + r = { + 'QUERY_STRING': urlencode(data or {}, doseq=True), + } + if not data and '?' in path: + # Fix to support old behavior where you have the arguments in the + # url. See #1461. + query_string = force_bytes(path.split('?')[1]) + query_string = query_string.decode('iso-8859-1') + r['QUERY_STRING'] = query_string + r.update(extra) + return self.generic('GET', path, **r) + + def post(self, path, data=None, format=None, content_type=None, **extra): + data, content_type = self._encode_data(data, format, content_type) + return self.generic('POST', path, data, content_type, **extra) + + def put(self, path, data=None, format=None, content_type=None, **extra): + data, content_type = self._encode_data(data, format, content_type) + return self.generic('PUT', path, data, content_type, **extra) + + def patch(self, path, data=None, format=None, content_type=None, **extra): + data, content_type = self._encode_data(data, format, content_type) + return self.generic('PATCH', path, data, content_type, **extra) + + def delete(self, path, data=None, format=None, content_type=None, **extra): + data, content_type = self._encode_data(data, format, content_type) + return self.generic('DELETE', path, data, content_type, **extra) + + def options(self, path, data=None, format=None, content_type=None, **extra): + data, content_type = self._encode_data(data, format, content_type) + return self.generic('OPTIONS', path, data, content_type, **extra) + + def generic(self, method, path, data='', + content_type='application/octet-stream', secure=False, **extra): + # Include the CONTENT_TYPE, regardless of whether or not data is empty. + if content_type is not None: + extra['CONTENT_TYPE'] = str(content_type) + + return super().generic( + method, path, data, content_type, secure, **extra) + + def request(self, **kwargs): + request = super().request(**kwargs) + request._dont_enforce_csrf_checks = not self.enforce_csrf_checks + return request + + +class ForceAuthClientHandler(ClientHandler): + """ + A patched version of ClientHandler that can enforce authentication + on the outgoing requests. + """ + + def __init__(self, *args, **kwargs): + self._force_user = None + self._force_token = None + super().__init__(*args, **kwargs) + + def get_response(self, request): + # This is the simplest place we can hook into to patch the + # request object. + force_authenticate(request, self._force_user, self._force_token) + return super().get_response(request) + + +class APIClient(APIRequestFactory, DjangoClient): + def __init__(self, enforce_csrf_checks=False, **defaults): + super().__init__(**defaults) + self.handler = ForceAuthClientHandler(enforce_csrf_checks) + self._credentials = {} + + def credentials(self, **kwargs): + """ + Sets headers that will be used on every outgoing request. + """ + self._credentials = kwargs + + def force_authenticate(self, user=None, token=None): + """ + Forcibly authenticates outgoing requests with the given + user and/or token. + """ + self.handler._force_user = user + self.handler._force_token = token + if user is None and token is None: + self.logout() # Also clear any possible session info if required + + def request(self, **kwargs): + # Ensure that any credentials set get added to every request. + kwargs.update(self._credentials) + return super().request(**kwargs) + + def get(self, path, data=None, follow=False, **extra): + response = super().get(path, data=data, **extra) + if follow: + response = self._handle_redirects(response, data=data, **extra) + return response + + def post(self, path, data=None, format=None, content_type=None, + follow=False, **extra): + response = super().post( + path, data=data, format=format, content_type=content_type, **extra) + if follow: + response = self._handle_redirects(response, data=data, format=format, content_type=content_type, **extra) + return response + + def put(self, path, data=None, format=None, content_type=None, + follow=False, **extra): + response = super().put( + path, data=data, format=format, content_type=content_type, **extra) + if follow: + response = self._handle_redirects(response, data=data, format=format, content_type=content_type, **extra) + return response + + def patch(self, path, data=None, format=None, content_type=None, + follow=False, **extra): + response = super().patch( + path, data=data, format=format, content_type=content_type, **extra) + if follow: + response = self._handle_redirects(response, data=data, format=format, content_type=content_type, **extra) + return response + + def delete(self, path, data=None, format=None, content_type=None, + follow=False, **extra): + response = super().delete( + path, data=data, format=format, content_type=content_type, **extra) + if follow: + response = self._handle_redirects(response, data=data, format=format, content_type=content_type, **extra) + return response + + def options(self, path, data=None, format=None, content_type=None, + follow=False, **extra): + response = super().options( + path, data=data, format=format, content_type=content_type, **extra) + if follow: + response = self._handle_redirects(response, data=data, format=format, content_type=content_type, **extra) + return response + + def logout(self): + self._credentials = {} + + # Also clear any `force_authenticate` + self.handler._force_user = None + self.handler._force_token = None + + if self.session: + super().logout() + + +class APITransactionTestCase(testcases.TransactionTestCase): + client_class = APIClient + + +class APITestCase(testcases.TestCase): + client_class = APIClient + + +class APISimpleTestCase(testcases.SimpleTestCase): + client_class = APIClient + + +class APILiveServerTestCase(testcases.LiveServerTestCase): + client_class = APIClient + + +def cleanup_url_patterns(cls): + if hasattr(cls, '_module_urlpatterns'): + cls._module.urlpatterns = cls._module_urlpatterns + else: + del cls._module.urlpatterns + + +class URLPatternsTestCase(testcases.SimpleTestCase): + """ + Isolate URL patterns on a per-TestCase basis. For example, + + class ATestCase(URLPatternsTestCase): + urlpatterns = [...] + + def test_something(self): + ... + + class AnotherTestCase(URLPatternsTestCase): + urlpatterns = [...] + + def test_something_else(self): + ... + """ + @classmethod + def setUpClass(cls): + # Get the module of the TestCase subclass + cls._module = import_module(cls.__module__) + cls._override = override_settings(ROOT_URLCONF=cls.__module__) + + if hasattr(cls._module, 'urlpatterns'): + cls._module_urlpatterns = cls._module.urlpatterns + + cls._module.urlpatterns = cls.urlpatterns + + cls._override.enable() + + if django.VERSION > (4, 0): + cls.addClassCleanup(cls._override.disable) + cls.addClassCleanup(cleanup_url_patterns, cls) + + super().setUpClass() + + if django.VERSION < (4, 0): + @classmethod + def tearDownClass(cls): + super().tearDownClass() + cls._override.disable() + + if hasattr(cls, '_module_urlpatterns'): + cls._module.urlpatterns = cls._module_urlpatterns + else: + del cls._module.urlpatterns diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/throttling.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/throttling.py new file mode 100644 index 0000000000000000000000000000000000000000..c0d6cf42fe0311cd4af9ba9f9d7f281e4a7bdc76 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/throttling.py @@ -0,0 +1,250 @@ +""" +Provides various throttling policies. +""" +import time + +from django.core.cache import cache as default_cache +from django.core.exceptions import ImproperlyConfigured + +from rest_framework.settings import api_settings + + +class BaseThrottle: + """ + Rate throttling of requests. + """ + + def allow_request(self, request, view): + """ + Return `True` if the request should be allowed, `False` otherwise. + """ + raise NotImplementedError('.allow_request() must be overridden') + + def get_ident(self, request): + """ + Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR + if present and number of proxies is > 0. If not use all of + HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. + """ + xff = request.META.get('HTTP_X_FORWARDED_FOR') + remote_addr = request.META.get('REMOTE_ADDR') + num_proxies = api_settings.NUM_PROXIES + + if num_proxies is not None: + if num_proxies == 0 or xff is None: + return remote_addr + addrs = xff.split(',') + client_addr = addrs[-min(num_proxies, len(addrs))] + return client_addr.strip() + + return ''.join(xff.split()) if xff else remote_addr + + def wait(self): + """ + Optionally, return a recommended number of seconds to wait before + the next request. + """ + return None + + +class SimpleRateThrottle(BaseThrottle): + """ + A simple cache implementation, that only requires `.get_cache_key()` + to be overridden. + + The rate (requests / seconds) is set by a `rate` attribute on the Throttle + class. The attribute is a string of the form 'number_of_requests/period'. + + Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day') + + Previous request information used for throttling is stored in the cache. + """ + cache = default_cache + timer = time.time + cache_format = 'throttle_%(scope)s_%(ident)s' + scope = None + THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES + + def __init__(self): + if not getattr(self, 'rate', None): + self.rate = self.get_rate() + self.num_requests, self.duration = self.parse_rate(self.rate) + + def get_cache_key(self, request, view): + """ + Should return a unique cache-key which can be used for throttling. + Must be overridden. + + May return `None` if the request should not be throttled. + """ + raise NotImplementedError('.get_cache_key() must be overridden') + + def get_rate(self): + """ + Determine the string representation of the allowed request rate. + """ + if not getattr(self, 'scope', None): + msg = ("You must set either `.scope` or `.rate` for '%s' throttle" % + self.__class__.__name__) + raise ImproperlyConfigured(msg) + + try: + return self.THROTTLE_RATES[self.scope] + except KeyError: + msg = "No default throttle rate set for '%s' scope" % self.scope + raise ImproperlyConfigured(msg) + + def parse_rate(self, rate): + """ + Given the request rate string, return a two tuple of: + <allowed number of requests>, <period of time in seconds> + """ + if rate is None: + return (None, None) + num, period = rate.split('/') + num_requests = int(num) + duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] + return (num_requests, duration) + + def allow_request(self, request, view): + """ + Implement the check to see if the request should be throttled. + + On success calls `throttle_success`. + On failure calls `throttle_failure`. + """ + if self.rate is None: + return True + + self.key = self.get_cache_key(request, view) + if self.key is None: + return True + + self.history = self.cache.get(self.key, []) + self.now = self.timer() + + # Drop any requests from the history which have now passed the + # throttle duration + while self.history and self.history[-1] <= self.now - self.duration: + self.history.pop() + if len(self.history) >= self.num_requests: + return self.throttle_failure() + return self.throttle_success() + + def throttle_success(self): + """ + Inserts the current request's timestamp along with the key + into the cache. + """ + self.history.insert(0, self.now) + self.cache.set(self.key, self.history, self.duration) + return True + + def throttle_failure(self): + """ + Called when a request to the API has failed due to throttling. + """ + return False + + def wait(self): + """ + Returns the recommended next request time in seconds. + """ + if self.history: + remaining_duration = self.duration - (self.now - self.history[-1]) + else: + remaining_duration = self.duration + + available_requests = self.num_requests - len(self.history) + 1 + if available_requests <= 0: + return None + + return remaining_duration / float(available_requests) + + +class AnonRateThrottle(SimpleRateThrottle): + """ + Limits the rate of API calls that may be made by a anonymous users. + + The IP address of the request will be used as the unique cache key. + """ + scope = 'anon' + + def get_cache_key(self, request, view): + if request.user and request.user.is_authenticated: + return None # Only throttle unauthenticated requests. + + return self.cache_format % { + 'scope': self.scope, + 'ident': self.get_ident(request) + } + + +class UserRateThrottle(SimpleRateThrottle): + """ + Limits the rate of API calls that may be made by a given user. + + The user id will be used as a unique cache key if the user is + authenticated. For anonymous requests, the IP address of the request will + be used. + """ + scope = 'user' + + def get_cache_key(self, request, view): + if request.user and request.user.is_authenticated: + ident = request.user.pk + else: + ident = self.get_ident(request) + + return self.cache_format % { + 'scope': self.scope, + 'ident': ident + } + + +class ScopedRateThrottle(SimpleRateThrottle): + """ + Limits the rate of API calls by different amounts for various parts of + the API. Any view that has the `throttle_scope` property set will be + throttled. The unique cache key will be generated by concatenating the + user id of the request, and the scope of the view being accessed. + """ + scope_attr = 'throttle_scope' + + def __init__(self): + # Override the usual SimpleRateThrottle, because we can't determine + # the rate until called by the view. + pass + + def allow_request(self, request, view): + # We can only determine the scope once we're called by the view. + self.scope = getattr(view, self.scope_attr, None) + + # If a view does not have a `throttle_scope` always allow the request + if not self.scope: + return True + + # Determine the allowed request rate as we normally would during + # the `__init__` call. + self.rate = self.get_rate() + self.num_requests, self.duration = self.parse_rate(self.rate) + + # We can now proceed as normal. + return super().allow_request(request, view) + + def get_cache_key(self, request, view): + """ + If `view.throttle_scope` is not set, don't apply this throttle. + + Otherwise generate the unique cache key by concatenating the user id + with the `.throttle_scope` property of the view. + """ + if request.user and request.user.is_authenticated: + ident = request.user.pk + else: + ident = self.get_ident(request) + + return self.cache_format % { + 'scope': self.scope, + 'ident': ident + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urlpatterns.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urlpatterns.py new file mode 100644 index 0000000000000000000000000000000000000000..bed5708eb8f1aed2867c53ede6ed0aef8c3e1d2e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urlpatterns.py @@ -0,0 +1,112 @@ +from django.urls import URLResolver, include, path, re_path, register_converter +from django.urls.resolvers import RoutePattern + +from rest_framework.settings import api_settings + + +def _get_format_path_converter(suffix_kwarg, allowed): + if allowed: + if len(allowed) == 1: + allowed_pattern = allowed[0] + else: + allowed_pattern = '(?:%s)' % '|'.join(allowed) + suffix_pattern = r"\.%s/?" % allowed_pattern + else: + suffix_pattern = r"\.[a-z0-9]+/?" + + class FormatSuffixConverter: + regex = suffix_pattern + + def to_python(self, value): + return value.strip('./') + + def to_url(self, value): + return '.' + value + '/' + + converter_name = 'drf_format_suffix' + if allowed: + converter_name += '_' + '_'.join(allowed) + + return converter_name, FormatSuffixConverter + + +def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_route=None): + ret = [] + for urlpattern in urlpatterns: + if isinstance(urlpattern, URLResolver): + # Set of included URL patterns + regex = urlpattern.pattern.regex.pattern + namespace = urlpattern.namespace + app_name = urlpattern.app_name + kwargs = urlpattern.default_kwargs + # Add in the included patterns, after applying the suffixes + patterns = apply_suffix_patterns(urlpattern.url_patterns, + suffix_pattern, + suffix_required, + suffix_route) + + # if the original pattern was a RoutePattern we need to preserve it + if isinstance(urlpattern.pattern, RoutePattern): + assert path is not None + route = str(urlpattern.pattern) + new_pattern = path(route, include((patterns, app_name), namespace), kwargs) + else: + new_pattern = re_path(regex, include((patterns, app_name), namespace), kwargs) + + ret.append(new_pattern) + else: + # Regular URL pattern + regex = urlpattern.pattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern + view = urlpattern.callback + kwargs = urlpattern.default_args + name = urlpattern.name + # Add in both the existing and the new urlpattern + if not suffix_required: + ret.append(urlpattern) + + # if the original pattern was a RoutePattern we need to preserve it + if isinstance(urlpattern.pattern, RoutePattern): + assert path is not None + assert suffix_route is not None + route = str(urlpattern.pattern).rstrip('$').rstrip('/') + suffix_route + new_pattern = path(route, view, kwargs, name) + else: + new_pattern = re_path(regex, view, kwargs, name) + + ret.append(new_pattern) + + return ret + + +def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None): + """ + Supplement existing urlpatterns with corresponding patterns that also + include a '.format' suffix. Retains urlpattern ordering. + + urlpatterns: + A list of URL patterns. + + suffix_required: + If `True`, only suffixed URLs will be generated, and non-suffixed + URLs will not be used. Defaults to `False`. + + allowed: + An optional tuple/list of allowed suffixes. eg ['json', 'api'] + Defaults to `None`, which allows any suffix. + """ + suffix_kwarg = api_settings.FORMAT_SUFFIX_KWARG + if allowed: + if len(allowed) == 1: + allowed_pattern = allowed[0] + else: + allowed_pattern = '(%s)' % '|'.join(allowed) + suffix_pattern = r'\.(?P<%s>%s)/?$' % (suffix_kwarg, allowed_pattern) + else: + suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg + + converter_name, suffix_converter = _get_format_path_converter(suffix_kwarg, allowed) + register_converter(suffix_converter, converter_name) + + suffix_route = '<%s:%s>' % (converter_name, suffix_kwarg) + + return apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_route) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urls.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..0aa301332ba61d2049691a7597e1487508f84a5e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/urls.py @@ -0,0 +1,21 @@ +""" +Login and logout views for the browsable API. + +Add these to your root URLconf if you're using the browsable API and +your API requires authentication: + + urlpatterns = [ + ... + path('auth/', include('rest_framework.urls')) + ] + +You should make sure your authentication settings include `SessionAuthentication`. +""" +from django.contrib.auth import views +from django.urls import path + +app_name = 'rest_framework' +urlpatterns = [ + path('login/', views.LoginView.as_view(template_name='rest_framework/login.html'), name='login'), + path('logout/', views.LogoutView.as_view(), name='logout'), +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35533dacd308cc8107d3817490ecc552cc572634 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/breadcrumbs.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/breadcrumbs.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f64354419fbeccef88667b174fd48864df33c898 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/breadcrumbs.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/encoders.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/encoders.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db9c5f0ca04488ab1181345a9a3d6cdf71bceb4c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/encoders.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/field_mapping.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/field_mapping.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fccb97307639c4e797b7142ec1f20ef9229ee77b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/field_mapping.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/formatting.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/formatting.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b917dcbf666fe120a7d9ec2129902ae129765e3a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/formatting.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/html.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/html.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db6f83e79a31699df3c29439a53b39f25de26866 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/html.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/humanize_datetime.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/humanize_datetime.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..922fdf652c83c8d668271cf0df9513ae47bd946d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/humanize_datetime.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/json.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/json.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bccebc11aaa9e20b20ed2b0c9def9e68f8609a59 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/json.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/mediatypes.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/mediatypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7ab32558d9bb42cac4a917c2cd6a028d929dda1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/mediatypes.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/model_meta.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/model_meta.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8434c48b2b3c53f15b6ed1aa17672d03255e7df7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/model_meta.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/representation.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/representation.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8eaeaee75ca222a2f7fed40414904e7b342a33b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/representation.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/serializer_helpers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/serializer_helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ce164fb8270a6b4f607a57ff1f5e4d5a9a532c5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/serializer_helpers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/urls.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43aaab0c135b485bc0261cdb5f773c5e0a88b6b4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/__pycache__/urls.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/breadcrumbs.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/breadcrumbs.py new file mode 100644 index 0000000000000000000000000000000000000000..54990e9f6cd3ea080c06764e845682c14fd1dc28 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/breadcrumbs.py @@ -0,0 +1,53 @@ +from django.urls import get_script_prefix, resolve + + +def get_breadcrumbs(url, request=None): + """ + Given a url returns a list of breadcrumbs, which are each a + tuple of (name, url). + """ + from rest_framework.reverse import preserve_builtin_query_params + from rest_framework.views import APIView + + def breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen): + """ + Add tuples of (name, url) to the breadcrumbs list, + progressively chomping off parts of the url. + """ + try: + (view, unused_args, unused_kwargs) = resolve(url) + except Exception: + pass + else: + # Check if this is a REST framework view, + # and if so add it to the breadcrumbs + cls = getattr(view, 'cls', None) + initkwargs = getattr(view, 'initkwargs', {}) + if cls is not None and issubclass(cls, APIView): + # Don't list the same view twice in a row. + # Probably an optional trailing slash. + if not seen or seen[-1] != view: + c = cls(**initkwargs) + name = c.get_view_name() + insert_url = preserve_builtin_query_params(prefix + url, request) + breadcrumbs_list.insert(0, (name, insert_url)) + seen.append(view) + + if url == '': + # All done + return breadcrumbs_list + + elif url.endswith('/'): + # Drop trailing slash off the end and continue to try to + # resolve more breadcrumbs + url = url.rstrip('/') + return breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen) + + # Drop trailing non-slash off the end and continue to try to + # resolve more breadcrumbs + url = url[:url.rfind('/') + 1] + return breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen) + + prefix = get_script_prefix().rstrip('/') + url = url[len(prefix):] + return breadcrumbs_recursive(url, [], prefix, []) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/encoders.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/encoders.py new file mode 100644 index 0000000000000000000000000000000000000000..27293b7252858043d8af464a203baf3c4656e775 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/encoders.py @@ -0,0 +1,67 @@ +""" +Helper classes for parsers. +""" +import datetime +import decimal +import json # noqa +import uuid + +from django.db.models.query import QuerySet +from django.utils import timezone +from django.utils.encoding import force_str +from django.utils.functional import Promise + +from rest_framework.compat import coreapi + + +class JSONEncoder(json.JSONEncoder): + """ + JSONEncoder subclass that knows how to encode date/time/timedelta, + decimal types, generators and other basic python objects. + """ + def default(self, obj): + # For Date Time string spec, see ECMA 262 + # https://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 + if isinstance(obj, Promise): + return force_str(obj) + elif isinstance(obj, datetime.datetime): + representation = obj.isoformat() + if representation.endswith('+00:00'): + representation = representation[:-6] + 'Z' + return representation + elif isinstance(obj, datetime.date): + return obj.isoformat() + elif isinstance(obj, datetime.time): + if timezone and timezone.is_aware(obj): + raise ValueError("JSON can't represent timezone-aware times.") + representation = obj.isoformat() + return representation + elif isinstance(obj, datetime.timedelta): + return str(obj.total_seconds()) + elif isinstance(obj, decimal.Decimal): + # Serializers will coerce decimals to strings by default. + return float(obj) + elif isinstance(obj, uuid.UUID): + return str(obj) + elif isinstance(obj, QuerySet): + return tuple(obj) + elif isinstance(obj, bytes): + # Best-effort for binary blobs. See #4187. + return obj.decode() + elif hasattr(obj, 'tolist'): + # Numpy arrays and array scalars. + return obj.tolist() + elif (coreapi is not None) and isinstance(obj, (coreapi.Document, coreapi.Error)): + raise RuntimeError( + 'Cannot return a coreapi object from a JSON view. ' + 'You should be using a schema renderer instead for this view.' + ) + elif hasattr(obj, '__getitem__'): + cls = (list if isinstance(obj, (list, tuple)) else dict) + try: + return cls(obj) + except Exception: + pass + elif hasattr(obj, '__iter__'): + return tuple(item for item in obj) + return super().default(obj) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/field_mapping.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/field_mapping.py new file mode 100644 index 0000000000000000000000000000000000000000..7e8e8f046bd9dd0e77eadd235fad4dd3b9329b15 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/field_mapping.py @@ -0,0 +1,308 @@ +""" +Helper functions for mapping model fields to a dictionary of default +keyword arguments that should be used for their equivalent serializer fields. +""" +import inspect + +from django.core import validators +from django.db import models +from django.utils.text import capfirst + +from rest_framework.compat import postgres_fields +from rest_framework.validators import UniqueValidator + +NUMERIC_FIELD_TYPES = ( + models.IntegerField, models.FloatField, models.DecimalField, models.DurationField, +) + + +class ClassLookupDict: + """ + Takes a dictionary with classes as keys. + Lookups against this object will traverses the object's inheritance + hierarchy in method resolution order, and returns the first matching value + from the dictionary or raises a KeyError if nothing matches. + """ + def __init__(self, mapping): + self.mapping = mapping + + def __getitem__(self, key): + if hasattr(key, '_proxy_class'): + # Deal with proxy classes. Ie. BoundField behaves as if it + # is a Field instance when using ClassLookupDict. + base_class = key._proxy_class + else: + base_class = key.__class__ + + for cls in inspect.getmro(base_class): + if cls in self.mapping: + return self.mapping[cls] + raise KeyError('Class %s not found in lookup.' % base_class.__name__) + + def __setitem__(self, key, value): + self.mapping[key] = value + + +def needs_label(model_field, field_name): + """ + Returns `True` if the label based on the model's verbose name + is not equal to the default label it would have based on it's field name. + """ + default_label = field_name.replace('_', ' ').capitalize() + return capfirst(model_field.verbose_name) != default_label + + +def get_detail_view_name(model): + """ + Given a model class, return the view name to use for URL relationships + that refer to instances of the model. + """ + return '%(model_name)s-detail' % { + 'model_name': model._meta.object_name.lower() + } + + +def get_field_kwargs(field_name, model_field): + """ + Creates a default instance of a basic non-relational field. + """ + kwargs = {} + validator_kwarg = list(model_field.validators) + + # The following will only be used by ModelField classes. + # Gets removed for everything else. + kwargs['model_field'] = model_field + + if model_field.verbose_name and needs_label(model_field, field_name): + kwargs['label'] = capfirst(model_field.verbose_name) + + if model_field.help_text: + kwargs['help_text'] = model_field.help_text + + max_digits = getattr(model_field, 'max_digits', None) + if max_digits is not None: + kwargs['max_digits'] = max_digits + + decimal_places = getattr(model_field, 'decimal_places', None) + if decimal_places is not None: + kwargs['decimal_places'] = decimal_places + + if isinstance(model_field, models.SlugField): + kwargs['allow_unicode'] = model_field.allow_unicode + + if isinstance(model_field, models.TextField) and not model_field.choices or \ + (postgres_fields and isinstance(model_field, postgres_fields.JSONField)) or \ + (hasattr(models, 'JSONField') and isinstance(model_field, models.JSONField)): + kwargs['style'] = {'base_template': 'textarea.html'} + + if model_field.null: + kwargs['allow_null'] = True + + if isinstance(model_field, models.AutoField) or not model_field.editable: + # If this field is read-only, then return early. + # Further keyword arguments are not valid. + kwargs['read_only'] = True + return kwargs + + if model_field.has_default() or model_field.blank or model_field.null: + kwargs['required'] = False + + if model_field.blank and (isinstance(model_field, (models.CharField, models.TextField))): + kwargs['allow_blank'] = True + + if not model_field.blank and (postgres_fields and isinstance(model_field, postgres_fields.ArrayField)): + kwargs['allow_empty'] = False + + if isinstance(model_field, models.FilePathField): + kwargs['path'] = model_field.path + + if model_field.match is not None: + kwargs['match'] = model_field.match + + if model_field.recursive is not False: + kwargs['recursive'] = model_field.recursive + + if model_field.allow_files is not True: + kwargs['allow_files'] = model_field.allow_files + + if model_field.allow_folders is not False: + kwargs['allow_folders'] = model_field.allow_folders + + if model_field.choices: + kwargs['choices'] = model_field.choices + else: + # Ensure that max_value is passed explicitly as a keyword arg, + # rather than as a validator. + max_value = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MaxValueValidator) + ), None) + if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): + kwargs['max_value'] = max_value + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MaxValueValidator) + ] + + # Ensure that min_value is passed explicitly as a keyword arg, + # rather than as a validator. + min_value = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MinValueValidator) + ), None) + if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): + kwargs['min_value'] = min_value + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MinValueValidator) + ] + + # URLField does not need to include the URLValidator argument, + # as it is explicitly added in. + if isinstance(model_field, models.URLField): + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.URLValidator) + ] + + # EmailField does not need to include the validate_email argument, + # as it is explicitly added in. + if isinstance(model_field, models.EmailField): + validator_kwarg = [ + validator for validator in validator_kwarg + if validator is not validators.validate_email + ] + + # SlugField do not need to include the 'validate_slug' argument, + if isinstance(model_field, models.SlugField): + validator_kwarg = [ + validator for validator in validator_kwarg + if validator is not validators.validate_slug + ] + + # IPAddressField do not need to include the 'validate_ipv46_address' argument, + if isinstance(model_field, models.GenericIPAddressField): + validator_kwarg = [ + validator for validator in validator_kwarg + if validator is not validators.validate_ipv46_address + ] + # Our decimal validation is handled in the field code, not validator code. + if isinstance(model_field, models.DecimalField): + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.DecimalValidator) + ] + + # Ensure that max_length is passed explicitly as a keyword arg, + # rather than as a validator. + max_length = getattr(model_field, 'max_length', None) + if max_length is not None and (isinstance(model_field, (models.CharField, models.TextField, models.FileField))): + kwargs['max_length'] = max_length + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MaxLengthValidator) + ] + + # Ensure that min_length is passed explicitly as a keyword arg, + # rather than as a validator. + min_length = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MinLengthValidator) + ), None) + if min_length is not None and isinstance(model_field, models.CharField): + kwargs['min_length'] = min_length + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MinLengthValidator) + ] + + if getattr(model_field, 'unique', False): + validator = UniqueValidator( + queryset=model_field.model._default_manager, + message=get_unique_error_message(model_field)) + validator_kwarg.append(validator) + + if validator_kwarg: + kwargs['validators'] = validator_kwarg + + return kwargs + + +def get_relation_kwargs(field_name, relation_info): + """ + Creates a default instance of a flat relational field. + """ + model_field, related_model, to_many, to_field, has_through_model, reverse = relation_info + kwargs = { + 'queryset': related_model._default_manager, + 'view_name': get_detail_view_name(related_model) + } + + if to_many: + kwargs['many'] = True + + if to_field: + kwargs['to_field'] = to_field + + limit_choices_to = model_field and model_field.get_limit_choices_to() + if limit_choices_to: + if not isinstance(limit_choices_to, models.Q): + limit_choices_to = models.Q(**limit_choices_to) + kwargs['queryset'] = kwargs['queryset'].filter(limit_choices_to) + + if has_through_model: + kwargs['read_only'] = True + kwargs.pop('queryset', None) + + if model_field: + if model_field.verbose_name and needs_label(model_field, field_name): + kwargs['label'] = capfirst(model_field.verbose_name) + help_text = model_field.help_text + if help_text: + kwargs['help_text'] = help_text + if not model_field.editable: + kwargs['read_only'] = True + kwargs.pop('queryset', None) + if model_field.null: + kwargs['allow_null'] = True + if kwargs.get('read_only', False): + # If this field is read-only, then return early. + # No further keyword arguments are valid. + return kwargs + + if model_field.has_default() or model_field.blank or model_field.null: + kwargs['required'] = False + if model_field.validators: + kwargs['validators'] = model_field.validators + if getattr(model_field, 'unique', False): + validator = UniqueValidator( + queryset=model_field.model._default_manager, + message=get_unique_error_message(model_field)) + kwargs['validators'] = kwargs.get('validators', []) + [validator] + if to_many and not model_field.blank: + kwargs['allow_empty'] = False + + return kwargs + + +def get_nested_relation_kwargs(relation_info): + kwargs = {'read_only': True} + if relation_info.to_many: + kwargs['many'] = True + return kwargs + + +def get_url_kwargs(model_field): + return { + 'view_name': get_detail_view_name(model_field) + } + + +def get_unique_error_message(model_field): + unique_error_message = model_field.error_messages.get('unique', None) + if unique_error_message: + unique_error_message = unique_error_message % { + 'model_name': model_field.model._meta.verbose_name, + 'field_label': model_field.verbose_name + } + return unique_error_message diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/formatting.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/formatting.py new file mode 100644 index 0000000000000000000000000000000000000000..c5917fd415ff7073f6cf8e28bbf2f332ebe851c0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/formatting.py @@ -0,0 +1,93 @@ +""" +Utility functions to return a formatted name and description for a given view. +""" +import re + +from django.utils.encoding import force_str +from django.utils.html import escape +from django.utils.safestring import mark_safe + +from rest_framework.compat import apply_markdown + + +def remove_trailing_string(content, trailing): + """ + Strip trailing component `trailing` from `content` if it exists. + Used when generating names from view classes. + """ + if content.endswith(trailing) and content != trailing: + return content[:-len(trailing)] + return content + + +def dedent(content): + """ + Remove leading indent from a block of text. + Used when generating descriptions from docstrings. + + Note that python's `textwrap.dedent` doesn't quite cut it, + as it fails to dedent multiline docstrings that include + unindented text on the initial line. + """ + content = force_str(content) + lines = [line for line in content.splitlines()[1:] if line.lstrip()] + + # unindent the content if needed + if lines: + whitespace_counts = min([len(line) - len(line.lstrip(' ')) for line in lines]) + tab_counts = min([len(line) - len(line.lstrip('\t')) for line in lines]) + if whitespace_counts: + whitespace_pattern = '^' + (' ' * whitespace_counts) + content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content) + elif tab_counts: + whitespace_pattern = '^' + ('\t' * tab_counts) + content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content) + return content.strip() + + +def camelcase_to_spaces(content): + """ + Translate 'CamelCaseNames' to 'Camel Case Names'. + Used when generating names from view classes. + """ + camelcase_boundary = '(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))' + content = re.sub(camelcase_boundary, ' \\1', content).strip() + return ' '.join(content.split('_')).title() + + +def markup_description(description): + """ + Apply HTML markup to the given description. + """ + if apply_markdown: + description = apply_markdown(description) + else: + description = escape(description).replace('\n', '<br />') + description = '<p>' + description + '</p>' + return mark_safe(description) + + +class lazy_format: + """ + Delay formatting until it's actually needed. + + Useful when the format string or one of the arguments is lazy. + + Not using Django's lazy because it is too slow. + """ + __slots__ = ('format_string', 'args', 'kwargs', 'result') + + def __init__(self, format_string, *args, **kwargs): + self.result = None + self.format_string = format_string + self.args = args + self.kwargs = kwargs + + def __str__(self): + if self.result is None: + self.result = self.format_string.format(*self.args, **self.kwargs) + self.format_string, self.args, self.kwargs = None, None, None + return self.result + + def __mod__(self, value): + return str(self) % value diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/html.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/html.py new file mode 100644 index 0000000000000000000000000000000000000000..c7ede78035be7e29beb1540396e52a3e5e2ab6f4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/html.py @@ -0,0 +1,95 @@ +""" +Helpers for dealing with HTML input. +""" +import re + +from django.utils.datastructures import MultiValueDict + + +def is_html_input(dictionary): + # MultiDict type datastructures are used to represent HTML form input, + # which may have more than one value for each key. + return hasattr(dictionary, 'getlist') + + +def parse_html_list(dictionary, prefix='', default=None): + """ + Used to support list values in HTML forms. + Supports lists of primitives and/or dictionaries. + + * List of primitives. + + { + '[0]': 'abc', + '[1]': 'def', + '[2]': 'hij' + } + --> + [ + 'abc', + 'def', + 'hij' + ] + + * List of dictionaries. + + { + '[0]foo': 'abc', + '[0]bar': 'def', + '[1]foo': 'hij', + '[1]bar': 'klm', + } + --> + [ + {'foo': 'abc', 'bar': 'def'}, + {'foo': 'hij', 'bar': 'klm'} + ] + + :returns a list of objects, or the value specified in ``default`` if the list is empty + """ + ret = {} + regex = re.compile(r'^%s\[([0-9]+)\](.*)$' % re.escape(prefix)) + for field, value in dictionary.items(): + match = regex.match(field) + if not match: + continue + index, key = match.groups() + index = int(index) + if not key: + ret[index] = value + elif isinstance(ret.get(index), dict): + ret[index][key] = value + else: + ret[index] = MultiValueDict({key: [value]}) + + # return the items of the ``ret`` dict, sorted by key, or ``default`` if the dict is empty + return [ret[item] for item in sorted(ret)] if ret else default + + +def parse_html_dict(dictionary, prefix=''): + """ + Used to support dictionary values in HTML forms. + + { + 'profile.username': 'example', + 'profile.email': 'example@example.com', + } + --> + { + 'profile': { + 'username': 'example', + 'email': 'example@example.com' + } + } + """ + ret = MultiValueDict() + regex = re.compile(r'^%s\.(.+)$' % re.escape(prefix)) + for field in dictionary: + match = regex.match(field) + if not match: + continue + key = match.groups()[0] + value = dictionary.getlist(field) + ret.setlist(key, value) + + return ret diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/humanize_datetime.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/humanize_datetime.py new file mode 100644 index 0000000000000000000000000000000000000000..48ef895475b1b66e0a813df0e26d869acde4ecec --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/humanize_datetime.py @@ -0,0 +1,47 @@ +""" +Helper functions that convert strftime formats into more readable representations. +""" +from rest_framework import ISO_8601 + + +def datetime_formats(formats): + format = ', '.join(formats).replace( + ISO_8601, + 'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]' + ) + return humanize_strptime(format) + + +def date_formats(formats): + format = ', '.join(formats).replace(ISO_8601, 'YYYY-MM-DD') + return humanize_strptime(format) + + +def time_formats(formats): + format = ', '.join(formats).replace(ISO_8601, 'hh:mm[:ss[.uuuuuu]]') + return humanize_strptime(format) + + +def humanize_strptime(format_string): + # Note that we're missing some of the locale specific mappings that + # don't really make sense. + mapping = { + "%Y": "YYYY", + "%y": "YY", + "%m": "MM", + "%b": "[Jan-Dec]", + "%B": "[January-December]", + "%d": "DD", + "%H": "hh", + "%I": "hh", # Requires '%p' to differentiate from '%H'. + "%M": "mm", + "%S": "ss", + "%f": "uuuuuu", + "%a": "[Mon-Sun]", + "%A": "[Monday-Sunday]", + "%p": "[AM|PM]", + "%z": "[+HHMM|-HHMM]" + } + for key, val in mapping.items(): + format_string = format_string.replace(key, val) + return format_string diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/json.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/json.py new file mode 100644 index 0000000000000000000000000000000000000000..1c1e69bf169047f1f15b065e8c76f04b6ac4c75b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/json.py @@ -0,0 +1,37 @@ +""" +Wrapper for the builtin json module that ensures compliance with the JSON spec. + +REST framework should always import this wrapper module in order to maintain +spec-compliant encoding/decoding. Support for non-standard features should be +handled by users at the renderer and parser layer. +""" +import functools +import json # noqa + + +def strict_constant(o): + raise ValueError('Out of range float values are not JSON compliant: ' + repr(o)) + + +@functools.wraps(json.dump) +def dump(*args, **kwargs): + kwargs.setdefault('allow_nan', False) + return json.dump(*args, **kwargs) + + +@functools.wraps(json.dumps) +def dumps(*args, **kwargs): + kwargs.setdefault('allow_nan', False) + return json.dumps(*args, **kwargs) + + +@functools.wraps(json.load) +def load(*args, **kwargs): + kwargs.setdefault('parse_constant', strict_constant) + return json.load(*args, **kwargs) + + +@functools.wraps(json.loads) +def loads(*args, **kwargs): + kwargs.setdefault('parse_constant', strict_constant) + return json.loads(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/mediatypes.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/mediatypes.py new file mode 100644 index 0000000000000000000000000000000000000000..b9004d49632469a02a289b6015891a50846ffd21 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/mediatypes.py @@ -0,0 +1,81 @@ +""" +Handling of media types, as found in HTTP Content-Type and Accept headers. + +See https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 +""" +from rest_framework.compat import parse_header_parameters + + +def media_type_matches(lhs, rhs): + """ + Returns ``True`` if the media type in the first argument <= the + media type in the second argument. The media types are strings + as described by the HTTP spec. + + Valid media type strings include: + + 'application/json; indent=4' + 'application/json' + 'text/*' + '*/*' + """ + lhs = _MediaType(lhs) + rhs = _MediaType(rhs) + return lhs.match(rhs) + + +def order_by_precedence(media_type_lst): + """ + Returns a list of sets of media type strings, ordered by precedence. + Precedence is determined by how specific a media type is: + + 3. 'type/subtype; param=val' + 2. 'type/subtype' + 1. 'type/*' + 0. '*/*' + """ + ret = [set(), set(), set(), set()] + for media_type in media_type_lst: + precedence = _MediaType(media_type).precedence + ret[3 - precedence].add(media_type) + return [media_types for media_types in ret if media_types] + + +class _MediaType: + def __init__(self, media_type_str): + self.orig = '' if (media_type_str is None) else media_type_str + self.full_type, self.params = parse_header_parameters(self.orig) + self.main_type, sep, self.sub_type = self.full_type.partition('/') + + def match(self, other): + """Return true if this MediaType satisfies the given MediaType.""" + for key in self.params: + if key != 'q' and other.params.get(key, None) != self.params.get(key, None): + return False + + if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type: + return False + + if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type: + return False + + return True + + @property + def precedence(self): + """ + Return a precedence level from 0-3 for the media type given how specific it is. + """ + if self.main_type == '*': + return 0 + elif self.sub_type == '*': + return 1 + elif not self.params or list(self.params) == ['q']: + return 2 + return 3 + + def __str__(self): + ret = "%s/%s" % (self.main_type, self.sub_type) + for key, val in self.params.items(): + ret += "; %s=%s" % (key, val) + return ret diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/model_meta.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/model_meta.py new file mode 100644 index 0000000000000000000000000000000000000000..4cc93b8ef5186d18e1262d67a48698d3ccdec472 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/model_meta.py @@ -0,0 +1,161 @@ +""" +Helper function for returning the field information that is associated +with a model class. This includes returning all the forward and reverse +relationships and their associated metadata. + +Usage: `get_field_info(model)` returns a `FieldInfo` instance. +""" +from collections import OrderedDict, namedtuple + +FieldInfo = namedtuple('FieldResult', [ + 'pk', # Model field instance + 'fields', # Dict of field name -> model field instance + 'forward_relations', # Dict of field name -> RelationInfo + 'reverse_relations', # Dict of field name -> RelationInfo + 'fields_and_pk', # Shortcut for 'pk' + 'fields' + 'relations' # Shortcut for 'forward_relations' + 'reverse_relations' +]) + +RelationInfo = namedtuple('RelationInfo', [ + 'model_field', + 'related_model', + 'to_many', + 'to_field', + 'has_through_model', + 'reverse' +]) + + +def get_field_info(model): + """ + Given a model class, returns a `FieldInfo` instance, which is a + `namedtuple`, containing metadata about the various field types on the model + including information about their relationships. + """ + opts = model._meta.concrete_model._meta + + pk = _get_pk(opts) + fields = _get_fields(opts) + forward_relations = _get_forward_relationships(opts) + reverse_relations = _get_reverse_relationships(opts) + fields_and_pk = _merge_fields_and_pk(pk, fields) + relationships = _merge_relationships(forward_relations, reverse_relations) + + return FieldInfo(pk, fields, forward_relations, reverse_relations, + fields_and_pk, relationships) + + +def _get_pk(opts): + pk = opts.pk + rel = pk.remote_field + + while rel and rel.parent_link: + # If model is a child via multi-table inheritance, use parent's pk. + pk = pk.remote_field.model._meta.pk + rel = pk.remote_field + + return pk + + +def _get_fields(opts): + fields = OrderedDict() + for field in [field for field in opts.fields if field.serialize and not field.remote_field]: + fields[field.name] = field + + return fields + + +def _get_to_field(field): + return getattr(field, 'to_fields', None) and field.to_fields[0] + + +def _get_forward_relationships(opts): + """ + Returns an `OrderedDict` of field names to `RelationInfo`. + """ + forward_relations = OrderedDict() + for field in [field for field in opts.fields if field.serialize and field.remote_field]: + forward_relations[field.name] = RelationInfo( + model_field=field, + related_model=field.remote_field.model, + to_many=False, + to_field=_get_to_field(field), + has_through_model=False, + reverse=False + ) + + # Deal with forward many-to-many relationships. + for field in [field for field in opts.many_to_many if field.serialize]: + forward_relations[field.name] = RelationInfo( + model_field=field, + related_model=field.remote_field.model, + to_many=True, + # manytomany do not have to_fields + to_field=None, + has_through_model=( + not field.remote_field.through._meta.auto_created + ), + reverse=False + ) + + return forward_relations + + +def _get_reverse_relationships(opts): + """ + Returns an `OrderedDict` of field names to `RelationInfo`. + """ + reverse_relations = OrderedDict() + all_related_objects = [r for r in opts.related_objects if not r.field.many_to_many] + for relation in all_related_objects: + accessor_name = relation.get_accessor_name() + reverse_relations[accessor_name] = RelationInfo( + model_field=None, + related_model=relation.related_model, + to_many=relation.field.remote_field.multiple, + to_field=_get_to_field(relation.field), + has_through_model=False, + reverse=True + ) + + # Deal with reverse many-to-many relationships. + all_related_many_to_many_objects = [r for r in opts.related_objects if r.field.many_to_many] + for relation in all_related_many_to_many_objects: + accessor_name = relation.get_accessor_name() + reverse_relations[accessor_name] = RelationInfo( + model_field=None, + related_model=relation.related_model, + to_many=True, + # manytomany do not have to_fields + to_field=None, + has_through_model=( + (getattr(relation.field.remote_field, 'through', None) is not None) and + not relation.field.remote_field.through._meta.auto_created + ), + reverse=True + ) + + return reverse_relations + + +def _merge_fields_and_pk(pk, fields): + fields_and_pk = OrderedDict() + fields_and_pk['pk'] = pk + fields_and_pk[pk.name] = pk + fields_and_pk.update(fields) + + return fields_and_pk + + +def _merge_relationships(forward_relations, reverse_relations): + return OrderedDict( + list(forward_relations.items()) + + list(reverse_relations.items()) + ) + + +def is_abstract_model(model): + """ + Given a model class, returns a boolean True if it is abstract and False if it is not. + """ + return hasattr(model, '_meta') and hasattr(model._meta, 'abstract') and model._meta.abstract diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/representation.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/representation.py new file mode 100644 index 0000000000000000000000000000000000000000..6f2efee164f16d7625de0dec42ec9b6339cd3ea7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/representation.py @@ -0,0 +1,101 @@ +""" +Helper functions for creating user-friendly representations +of serializer classes and serializer fields. +""" +import re + +from django.db import models +from django.utils.encoding import force_str +from django.utils.functional import Promise + + +def manager_repr(value): + model = value.model + opts = model._meta + names_and_managers = [ + (manager.name, manager) + for manager + in opts.managers + ] + for manager_name, manager_instance in names_and_managers: + if manager_instance == value: + return '%s.%s.all()' % (model._meta.object_name, manager_name) + return repr(value) + + +def smart_repr(value): + if isinstance(value, models.Manager): + return manager_repr(value) + + if isinstance(value, Promise) and value._delegate_text: + value = force_str(value) + + value = repr(value) + + # Representations like u'help text' + # should simply be presented as 'help text' + if value.startswith("u'") and value.endswith("'"): + return value[1:] + + # Representations like + # <django.core.validators.RegexValidator object at 0x1047af050> + # Should be presented as + # <django.core.validators.RegexValidator object> + return re.sub(' at 0x[0-9A-Fa-f]{4,32}>', '>', value) + + +def field_repr(field, force_many=False): + kwargs = field._kwargs + if force_many: + kwargs = kwargs.copy() + kwargs['many'] = True + kwargs.pop('child', None) + + arg_string = ', '.join([smart_repr(val) for val in field._args]) + kwarg_string = ', '.join([ + '%s=%s' % (key, smart_repr(val)) + for key, val in sorted(kwargs.items()) + ]) + if arg_string and kwarg_string: + arg_string += ', ' + + if force_many: + class_name = force_many.__class__.__name__ + else: + class_name = field.__class__.__name__ + + return "%s(%s%s)" % (class_name, arg_string, kwarg_string) + + +def serializer_repr(serializer, indent, force_many=None): + ret = field_repr(serializer, force_many) + ':' + indent_str = ' ' * indent + + if force_many: + fields = force_many.fields + else: + fields = serializer.fields + + for field_name, field in fields.items(): + ret += '\n' + indent_str + field_name + ' = ' + if hasattr(field, 'fields'): + ret += serializer_repr(field, indent + 1) + elif hasattr(field, 'child'): + ret += list_repr(field, indent + 1) + elif hasattr(field, 'child_relation'): + ret += field_repr(field.child_relation, force_many=field.child_relation) + else: + ret += field_repr(field) + + if serializer.validators: + ret += '\n' + indent_str + 'class Meta:' + ret += '\n' + indent_str + ' validators = ' + smart_repr(serializer.validators) + + return ret + + +def list_repr(serializer, indent): + child = serializer.child + if hasattr(child, 'fields'): + return serializer_repr(serializer, indent, force_many=child) + return field_repr(serializer) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/serializer_helpers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/serializer_helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..54068f5fb053bbebb5a16d9efa82c3ba341502f1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/serializer_helpers.py @@ -0,0 +1,184 @@ +import sys +from collections import OrderedDict +from collections.abc import Mapping, MutableMapping + +from django.utils.encoding import force_str + +from rest_framework.utils import json + + +class ReturnDict(OrderedDict): + """ + Return object from `serializer.data` for the `Serializer` class. + Includes a backlink to the serializer instance for renderers + to use if they need richer field information. + """ + + def __init__(self, *args, **kwargs): + self.serializer = kwargs.pop('serializer') + super().__init__(*args, **kwargs) + + def copy(self): + return ReturnDict(self, serializer=self.serializer) + + def __repr__(self): + return dict.__repr__(self) + + def __reduce__(self): + # Pickling these objects will drop the .serializer backlink, + # but preserve the raw data. + return (dict, (dict(self),)) + + if sys.version_info >= (3, 9): + # These are basically copied from OrderedDict, with `serializer` added. + def __or__(self, other): + if not isinstance(other, dict): + return NotImplemented + new = self.__class__(self, serializer=self.serializer) + new.update(other) + return new + + def __ror__(self, other): + if not isinstance(other, dict): + return NotImplemented + new = self.__class__(other, serializer=self.serializer) + new.update(self) + return new + + +class ReturnList(list): + """ + Return object from `serializer.data` for the `SerializerList` class. + Includes a backlink to the serializer instance for renderers + to use if they need richer field information. + """ + + def __init__(self, *args, **kwargs): + self.serializer = kwargs.pop('serializer') + super().__init__(*args, **kwargs) + + def __repr__(self): + return list.__repr__(self) + + def __reduce__(self): + # Pickling these objects will drop the .serializer backlink, + # but preserve the raw data. + return (list, (list(self),)) + + +class BoundField: + """ + A field object that also includes `.value` and `.error` properties. + Returned when iterating over a serializer instance, + providing an API similar to Django forms and form fields. + """ + + def __init__(self, field, value, errors, prefix=''): + self._field = field + self._prefix = prefix + self.value = value + self.errors = errors + self.name = prefix + self.field_name + + def __getattr__(self, attr_name): + return getattr(self._field, attr_name) + + @property + def _proxy_class(self): + return self._field.__class__ + + def __repr__(self): + return '<%s value=%s errors=%s>' % ( + self.__class__.__name__, self.value, self.errors + ) + + def as_form_field(self): + value = '' if (self.value is None or self.value is False) else self.value + return self.__class__(self._field, value, self.errors, self._prefix) + + +class JSONBoundField(BoundField): + def as_form_field(self): + value = self.value + # When HTML form input is used and the input is not valid + # value will be a JSONString, rather than a JSON primitive. + if not getattr(value, 'is_json_string', False): + try: + value = json.dumps( + self.value, + sort_keys=True, + indent=4, + separators=(',', ': '), + ) + except (TypeError, ValueError): + pass + return self.__class__(self._field, value, self.errors, self._prefix) + + +class NestedBoundField(BoundField): + """ + This `BoundField` additionally implements __iter__ and __getitem__ + in order to support nested bound fields. This class is the type of + `BoundField` that is used for serializer fields. + """ + + def __init__(self, field, value, errors, prefix=''): + if value is None or value == '' or not isinstance(value, Mapping): + value = {} + super().__init__(field, value, errors, prefix) + + def __iter__(self): + for field in self.fields.values(): + yield self[field.field_name] + + def __getitem__(self, key): + field = self.fields[key] + value = self.value.get(key) if self.value else None + error = self.errors.get(key) if isinstance(self.errors, dict) else None + if hasattr(field, 'fields'): + return NestedBoundField(field, value, error, prefix=self.name + '.') + elif getattr(field, '_is_jsonfield', False): + return JSONBoundField(field, value, error, prefix=self.name + '.') + return BoundField(field, value, error, prefix=self.name + '.') + + def as_form_field(self): + values = {} + for key, value in self.value.items(): + if isinstance(value, (list, dict)): + values[key] = value + else: + values[key] = '' if (value is None or value is False) else force_str(value) + return self.__class__(self._field, values, self.errors, self._prefix) + + +class BindingDict(MutableMapping): + """ + This dict-like object is used to store fields on a serializer. + + This ensures that whenever fields are added to the serializer we call + `field.bind()` so that the `field_name` and `parent` attributes + can be set correctly. + """ + + def __init__(self, serializer): + self.serializer = serializer + self.fields = OrderedDict() + + def __setitem__(self, key, field): + self.fields[key] = field + field.bind(field_name=key, parent=self.serializer) + + def __getitem__(self, key): + return self.fields[key] + + def __delitem__(self, key): + del self.fields[key] + + def __iter__(self): + return iter(self.fields) + + def __len__(self): + return len(self.fields) + + def __repr__(self): + return dict.__repr__(self.fields) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/urls.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..afb06994ce2af9e79cff6c06733740fdae8e47d2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/utils/urls.py @@ -0,0 +1,27 @@ +from urllib import parse + +from django.utils.encoding import force_str + + +def replace_query_param(url, key, val): + """ + Given a URL and a key/val pair, set or replace an item in the query + parameters of the URL, and return the new URL. + """ + (scheme, netloc, path, query, fragment) = parse.urlsplit(force_str(url)) + query_dict = parse.parse_qs(query, keep_blank_values=True) + query_dict[force_str(key)] = [force_str(val)] + query = parse.urlencode(sorted(query_dict.items()), doseq=True) + return parse.urlunsplit((scheme, netloc, path, query, fragment)) + + +def remove_query_param(url, key): + """ + Given a URL and a key/val pair, remove an item in the query + parameters of the URL, and return the new URL. + """ + (scheme, netloc, path, query, fragment) = parse.urlsplit(force_str(url)) + query_dict = parse.parse_qs(query, keep_blank_values=True) + query_dict.pop(key, None) + query = parse.urlencode(sorted(query_dict.items()), doseq=True) + return parse.urlunsplit((scheme, netloc, path, query, fragment)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/validators.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/validators.py new file mode 100644 index 0000000000000000000000000000000000000000..a5cb75a84a48538c5f9aca29c479f39da2e16abb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/validators.py @@ -0,0 +1,280 @@ +""" +We perform uniqueness checks explicitly on the serializer class, rather +the using Django's `.full_clean()`. + +This gives us better separation of concerns, allows us to use single-step +object creation, and makes it possible to switch between using the implicit +`ModelSerializer` class and an equivalent explicit `Serializer` class. +""" +from django.db import DataError +from django.utils.translation import gettext_lazy as _ + +from rest_framework.exceptions import ValidationError +from rest_framework.utils.representation import smart_repr + + +# Robust filter and exist implementations. Ensures that queryset.exists() for +# an invalid value returns `False`, rather than raising an error. +# Refs https://github.com/encode/django-rest-framework/issues/3381 +def qs_exists(queryset): + try: + return queryset.exists() + except (TypeError, ValueError, DataError): + return False + + +def qs_filter(queryset, **kwargs): + try: + return queryset.filter(**kwargs) + except (TypeError, ValueError, DataError): + return queryset.none() + + +class UniqueValidator: + """ + Validator that corresponds to `unique=True` on a model field. + + Should be applied to an individual field on the serializer. + """ + message = _('This field must be unique.') + requires_context = True + + def __init__(self, queryset, message=None, lookup='exact'): + self.queryset = queryset + self.message = message or self.message + self.lookup = lookup + + def filter_queryset(self, value, queryset, field_name): + """ + Filter the queryset to all instances matching the given attribute. + """ + filter_kwargs = {'%s__%s' % (field_name, self.lookup): value} + return qs_filter(queryset, **filter_kwargs) + + def exclude_current_instance(self, queryset, instance): + """ + If an instance is being updated, then do not include + that instance itself as a uniqueness conflict. + """ + if instance is not None: + return queryset.exclude(pk=instance.pk) + return queryset + + def __call__(self, value, serializer_field): + # Determine the underlying model field name. This may not be the + # same as the serializer field name if `source=<>` is set. + field_name = serializer_field.source_attrs[-1] + # Determine the existing instance, if this is an update operation. + instance = getattr(serializer_field.parent, 'instance', None) + + queryset = self.queryset + queryset = self.filter_queryset(value, queryset, field_name) + queryset = self.exclude_current_instance(queryset, instance) + if qs_exists(queryset): + raise ValidationError(self.message, code='unique') + + def __repr__(self): + return '<%s(queryset=%s)>' % ( + self.__class__.__name__, + smart_repr(self.queryset) + ) + + +class UniqueTogetherValidator: + """ + Validator that corresponds to `unique_together = (...)` on a model class. + + Should be applied to the serializer class, not to an individual field. + """ + message = _('The fields {field_names} must make a unique set.') + missing_message = _('This field is required.') + requires_context = True + + def __init__(self, queryset, fields, message=None): + self.queryset = queryset + self.fields = fields + self.message = message or self.message + + def enforce_required_fields(self, attrs, serializer): + """ + The `UniqueTogetherValidator` always forces an implied 'required' + state on the fields it applies to. + """ + if serializer.instance is not None: + return + + missing_items = { + field_name: self.missing_message + for field_name in self.fields + if serializer.fields[field_name].source not in attrs + } + if missing_items: + raise ValidationError(missing_items, code='required') + + def filter_queryset(self, attrs, queryset, serializer): + """ + Filter the queryset to all instances matching the given attributes. + """ + # field names => field sources + sources = [ + serializer.fields[field_name].source + for field_name in self.fields + ] + + # If this is an update, then any unprovided field should + # have it's value set based on the existing instance attribute. + if serializer.instance is not None: + for source in sources: + if source not in attrs: + attrs[source] = getattr(serializer.instance, source) + + # Determine the filter keyword arguments and filter the queryset. + filter_kwargs = { + source: attrs[source] + for source in sources + } + return qs_filter(queryset, **filter_kwargs) + + def exclude_current_instance(self, attrs, queryset, instance): + """ + If an instance is being updated, then do not include + that instance itself as a uniqueness conflict. + """ + if instance is not None: + return queryset.exclude(pk=instance.pk) + return queryset + + def __call__(self, attrs, serializer): + self.enforce_required_fields(attrs, serializer) + queryset = self.queryset + queryset = self.filter_queryset(attrs, queryset, serializer) + queryset = self.exclude_current_instance(attrs, queryset, serializer.instance) + + # Ignore validation if any field is None + checked_values = [ + value for field, value in attrs.items() if field in self.fields + ] + if None not in checked_values and qs_exists(queryset): + field_names = ', '.join(self.fields) + message = self.message.format(field_names=field_names) + raise ValidationError(message, code='unique') + + def __repr__(self): + return '<%s(queryset=%s, fields=%s)>' % ( + self.__class__.__name__, + smart_repr(self.queryset), + smart_repr(self.fields) + ) + + +class ProhibitSurrogateCharactersValidator: + message = _('Surrogate characters are not allowed: U+{code_point:X}.') + code = 'surrogate_characters_not_allowed' + + def __call__(self, value): + for surrogate_character in (ch for ch in str(value) + if 0xD800 <= ord(ch) <= 0xDFFF): + message = self.message.format(code_point=ord(surrogate_character)) + raise ValidationError(message, code=self.code) + + +class BaseUniqueForValidator: + message = None + missing_message = _('This field is required.') + requires_context = True + + def __init__(self, queryset, field, date_field, message=None): + self.queryset = queryset + self.field = field + self.date_field = date_field + self.message = message or self.message + + def enforce_required_fields(self, attrs): + """ + The `UniqueFor<Range>Validator` classes always force an implied + 'required' state on the fields they are applied to. + """ + missing_items = { + field_name: self.missing_message + for field_name in [self.field, self.date_field] + if field_name not in attrs + } + if missing_items: + raise ValidationError(missing_items, code='required') + + def filter_queryset(self, attrs, queryset, field_name, date_field_name): + raise NotImplementedError('`filter_queryset` must be implemented.') + + def exclude_current_instance(self, attrs, queryset, instance): + """ + If an instance is being updated, then do not include + that instance itself as a uniqueness conflict. + """ + if instance is not None: + return queryset.exclude(pk=instance.pk) + return queryset + + def __call__(self, attrs, serializer): + # Determine the underlying model field names. These may not be the + # same as the serializer field names if `source=<>` is set. + field_name = serializer.fields[self.field].source_attrs[-1] + date_field_name = serializer.fields[self.date_field].source_attrs[-1] + + self.enforce_required_fields(attrs) + queryset = self.queryset + queryset = self.filter_queryset(attrs, queryset, field_name, date_field_name) + queryset = self.exclude_current_instance(attrs, queryset, serializer.instance) + if qs_exists(queryset): + message = self.message.format(date_field=self.date_field) + raise ValidationError({ + self.field: message + }, code='unique') + + def __repr__(self): + return '<%s(queryset=%s, field=%s, date_field=%s)>' % ( + self.__class__.__name__, + smart_repr(self.queryset), + smart_repr(self.field), + smart_repr(self.date_field) + ) + + +class UniqueForDateValidator(BaseUniqueForValidator): + message = _('This field must be unique for the "{date_field}" date.') + + def filter_queryset(self, attrs, queryset, field_name, date_field_name): + value = attrs[self.field] + date = attrs[self.date_field] + + filter_kwargs = {} + filter_kwargs[field_name] = value + filter_kwargs['%s__day' % date_field_name] = date.day + filter_kwargs['%s__month' % date_field_name] = date.month + filter_kwargs['%s__year' % date_field_name] = date.year + return qs_filter(queryset, **filter_kwargs) + + +class UniqueForMonthValidator(BaseUniqueForValidator): + message = _('This field must be unique for the "{date_field}" month.') + + def filter_queryset(self, attrs, queryset, field_name, date_field_name): + value = attrs[self.field] + date = attrs[self.date_field] + + filter_kwargs = {} + filter_kwargs[field_name] = value + filter_kwargs['%s__month' % date_field_name] = date.month + return qs_filter(queryset, **filter_kwargs) + + +class UniqueForYearValidator(BaseUniqueForValidator): + message = _('This field must be unique for the "{date_field}" year.') + + def filter_queryset(self, attrs, queryset, field_name, date_field_name): + value = attrs[self.field] + date = attrs[self.date_field] + + filter_kwargs = {} + filter_kwargs[field_name] = value + filter_kwargs['%s__year' % date_field_name] = date.year + return qs_filter(queryset, **filter_kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/versioning.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/versioning.py new file mode 100644 index 0000000000000000000000000000000000000000..78cfc9dc81947853a28635e367c02de8e1e78d17 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/versioning.py @@ -0,0 +1,184 @@ +import re + +from django.utils.translation import gettext_lazy as _ + +from rest_framework import exceptions +from rest_framework.compat import unicode_http_header +from rest_framework.reverse import _reverse +from rest_framework.settings import api_settings +from rest_framework.templatetags.rest_framework import replace_query_param +from rest_framework.utils.mediatypes import _MediaType + + +class BaseVersioning: + default_version = api_settings.DEFAULT_VERSION + allowed_versions = api_settings.ALLOWED_VERSIONS + version_param = api_settings.VERSION_PARAM + + def determine_version(self, request, *args, **kwargs): + msg = '{cls}.determine_version() must be implemented.' + raise NotImplementedError(msg.format( + cls=self.__class__.__name__ + )) + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + return _reverse(viewname, args, kwargs, request, format, **extra) + + def is_allowed_version(self, version): + if not self.allowed_versions: + return True + return ((version is not None and version == self.default_version) or + (version in self.allowed_versions)) + + +class AcceptHeaderVersioning(BaseVersioning): + """ + GET /something/ HTTP/1.1 + Host: example.com + Accept: application/json; version=1.0 + """ + invalid_version_message = _('Invalid version in "Accept" header.') + + def determine_version(self, request, *args, **kwargs): + media_type = _MediaType(request.accepted_media_type) + version = media_type.params.get(self.version_param, self.default_version) + version = unicode_http_header(version) + if not self.is_allowed_version(version): + raise exceptions.NotAcceptable(self.invalid_version_message) + return version + + # We don't need to implement `reverse`, as the versioning is based + # on the `Accept` header, not on the request URL. + + +class URLPathVersioning(BaseVersioning): + """ + To the client this is the same style as `NamespaceVersioning`. + The difference is in the backend - this implementation uses + Django's URL keyword arguments to determine the version. + + An example URL conf for two views that accept two different versions. + + urlpatterns = [ + re_path(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'), + re_path(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail') + ] + + GET /1.0/something/ HTTP/1.1 + Host: example.com + Accept: application/json + """ + invalid_version_message = _('Invalid version in URL path.') + + def determine_version(self, request, *args, **kwargs): + version = kwargs.get(self.version_param, self.default_version) + if version is None: + version = self.default_version + + if not self.is_allowed_version(version): + raise exceptions.NotFound(self.invalid_version_message) + return version + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + if request.version is not None: + kwargs = {} if (kwargs is None) else kwargs + kwargs[self.version_param] = request.version + + return super().reverse( + viewname, args, kwargs, request, format, **extra + ) + + +class NamespaceVersioning(BaseVersioning): + """ + To the client this is the same style as `URLPathVersioning`. + The difference is in the backend - this implementation uses + Django's URL namespaces to determine the version. + + An example URL conf that is namespaced into two separate versions + + # users/urls.py + urlpatterns = [ + path('/users/', users_list, name='users-list'), + path('/users/<int:pk>/', users_detail, name='users-detail') + ] + + # urls.py + urlpatterns = [ + path('v1/', include('users.urls', namespace='v1')), + path('v2/', include('users.urls', namespace='v2')) + ] + + GET /1.0/something/ HTTP/1.1 + Host: example.com + Accept: application/json + """ + invalid_version_message = _('Invalid version in URL path. Does not match any version namespace.') + + def determine_version(self, request, *args, **kwargs): + resolver_match = getattr(request, 'resolver_match', None) + if resolver_match is None or not resolver_match.namespace: + return self.default_version + + # Allow for possibly nested namespaces. + possible_versions = resolver_match.namespace.split(':') + for version in possible_versions: + if self.is_allowed_version(version): + return version + raise exceptions.NotFound(self.invalid_version_message) + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + if request.version is not None: + viewname = self.get_versioned_viewname(viewname, request) + return super().reverse( + viewname, args, kwargs, request, format, **extra + ) + + def get_versioned_viewname(self, viewname, request): + return request.version + ':' + viewname + + +class HostNameVersioning(BaseVersioning): + """ + GET /something/ HTTP/1.1 + Host: v1.example.com + Accept: application/json + """ + hostname_regex = re.compile(r'^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$') + invalid_version_message = _('Invalid version in hostname.') + + def determine_version(self, request, *args, **kwargs): + hostname, separator, port = request.get_host().partition(':') + match = self.hostname_regex.match(hostname) + if not match: + return self.default_version + version = match.group(1) + if not self.is_allowed_version(version): + raise exceptions.NotFound(self.invalid_version_message) + return version + + # We don't need to implement `reverse`, as the hostname will already be + # preserved as part of the REST framework `reverse` implementation. + + +class QueryParameterVersioning(BaseVersioning): + """ + GET /something/?version=0.1 HTTP/1.1 + Host: example.com + Accept: application/json + """ + invalid_version_message = _('Invalid version in query parameter.') + + def determine_version(self, request, *args, **kwargs): + version = request.query_params.get(self.version_param, self.default_version) + if not self.is_allowed_version(version): + raise exceptions.NotFound(self.invalid_version_message) + return version + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + url = super().reverse( + viewname, args, kwargs, request, format, **extra + ) + if request.version is not None: + return replace_query_param(url, self.version_param, request.version) + return url diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/views.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/views.py new file mode 100644 index 0000000000000000000000000000000000000000..5b0622069110e6ea886455faa65127cd2624e1ce --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/views.py @@ -0,0 +1,521 @@ +""" +Provides an APIView class that is the base of all views in REST framework. +""" +from django.conf import settings +from django.core.exceptions import PermissionDenied +from django.db import connections, models +from django.http import Http404 +from django.http.response import HttpResponseBase +from django.utils.cache import cc_delim_re, patch_vary_headers +from django.utils.encoding import smart_str +from django.views.decorators.csrf import csrf_exempt +from django.views.generic import View + +from rest_framework import exceptions, status +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.schemas import DefaultSchema +from rest_framework.settings import api_settings +from rest_framework.utils import formatting + + +def get_view_name(view): + """ + Given a view instance, return a textual name to represent the view. + This name is used in the browsable API, and in OPTIONS responses. + + This function is the default for the `VIEW_NAME_FUNCTION` setting. + """ + # Name may be set by some Views, such as a ViewSet. + name = getattr(view, 'name', None) + if name is not None: + return name + + name = view.__class__.__name__ + name = formatting.remove_trailing_string(name, 'View') + name = formatting.remove_trailing_string(name, 'ViewSet') + name = formatting.camelcase_to_spaces(name) + + # Suffix may be set by some Views, such as a ViewSet. + suffix = getattr(view, 'suffix', None) + if suffix: + name += ' ' + suffix + + return name + + +def get_view_description(view, html=False): + """ + Given a view instance, return a textual description to represent the view. + This name is used in the browsable API, and in OPTIONS responses. + + This function is the default for the `VIEW_DESCRIPTION_FUNCTION` setting. + """ + # Description may be set by some Views, such as a ViewSet. + description = getattr(view, 'description', None) + if description is None: + description = view.__class__.__doc__ or '' + + description = formatting.dedent(smart_str(description)) + if html: + return formatting.markup_description(description) + return description + + +def set_rollback(): + for db in connections.all(): + if db.settings_dict['ATOMIC_REQUESTS'] and db.in_atomic_block: + db.set_rollback(True) + + +def exception_handler(exc, context): + """ + Returns the response that should be used for any given exception. + + By default we handle the REST framework `APIException`, and also + Django's built-in `Http404` and `PermissionDenied` exceptions. + + Any unhandled exceptions may return `None`, which will cause a 500 error + to be raised. + """ + if isinstance(exc, Http404): + exc = exceptions.NotFound() + elif isinstance(exc, PermissionDenied): + exc = exceptions.PermissionDenied() + + if isinstance(exc, exceptions.APIException): + headers = {} + if getattr(exc, 'auth_header', None): + headers['WWW-Authenticate'] = exc.auth_header + if getattr(exc, 'wait', None): + headers['Retry-After'] = '%d' % exc.wait + + if isinstance(exc.detail, (list, dict)): + data = exc.detail + else: + data = {'detail': exc.detail} + + set_rollback() + return Response(data, status=exc.status_code, headers=headers) + + return None + + +class APIView(View): + + # The following policies may be set at either globally, or per-view. + renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + parser_classes = api_settings.DEFAULT_PARSER_CLASSES + authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES + throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES + permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES + content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS + metadata_class = api_settings.DEFAULT_METADATA_CLASS + versioning_class = api_settings.DEFAULT_VERSIONING_CLASS + + # Allow dependency injection of other settings to make testing easier. + settings = api_settings + + schema = DefaultSchema() + + @classmethod + def as_view(cls, **initkwargs): + """ + Store the original class on the view function. + + This allows us to discover information about the view when we do URL + reverse lookups. Used for breadcrumb generation. + """ + if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): + def force_evaluation(): + raise RuntimeError( + 'Do not evaluate the `.queryset` attribute directly, ' + 'as the result will be cached and reused between requests. ' + 'Use `.all()` or call `.get_queryset()` instead.' + ) + cls.queryset._fetch_all = force_evaluation + + view = super().as_view(**initkwargs) + view.cls = cls + view.initkwargs = initkwargs + + # Note: session based authentication is explicitly CSRF validated, + # all other authentication is CSRF exempt. + return csrf_exempt(view) + + @property + def allowed_methods(self): + """ + Wrap Django's private `_allowed_methods` interface in a public property. + """ + return self._allowed_methods() + + @property + def default_response_headers(self): + headers = { + 'Allow': ', '.join(self.allowed_methods), + } + if len(self.renderer_classes) > 1: + headers['Vary'] = 'Accept' + return headers + + def http_method_not_allowed(self, request, *args, **kwargs): + """ + If `request.method` does not correspond to a handler method, + determine what kind of exception to raise. + """ + raise exceptions.MethodNotAllowed(request.method) + + def permission_denied(self, request, message=None, code=None): + """ + If request is not permitted, determine what kind of exception to raise. + """ + if request.authenticators and not request.successful_authenticator: + raise exceptions.NotAuthenticated() + raise exceptions.PermissionDenied(detail=message, code=code) + + def throttled(self, request, wait): + """ + If request is throttled, determine what kind of exception to raise. + """ + raise exceptions.Throttled(wait) + + def get_authenticate_header(self, request): + """ + If a request is unauthenticated, determine the WWW-Authenticate + header to use for 401 responses, if any. + """ + authenticators = self.get_authenticators() + if authenticators: + return authenticators[0].authenticate_header(request) + + def get_parser_context(self, http_request): + """ + Returns a dict that is passed through to Parser.parse(), + as the `parser_context` keyword argument. + """ + # Note: Additionally `request` and `encoding` will also be added + # to the context by the Request object. + return { + 'view': self, + 'args': getattr(self, 'args', ()), + 'kwargs': getattr(self, 'kwargs', {}) + } + + def get_renderer_context(self): + """ + Returns a dict that is passed through to Renderer.render(), + as the `renderer_context` keyword argument. + """ + # Note: Additionally 'response' will also be added to the context, + # by the Response object. + return { + 'view': self, + 'args': getattr(self, 'args', ()), + 'kwargs': getattr(self, 'kwargs', {}), + 'request': getattr(self, 'request', None) + } + + def get_exception_handler_context(self): + """ + Returns a dict that is passed through to EXCEPTION_HANDLER, + as the `context` argument. + """ + return { + 'view': self, + 'args': getattr(self, 'args', ()), + 'kwargs': getattr(self, 'kwargs', {}), + 'request': getattr(self, 'request', None) + } + + def get_view_name(self): + """ + Return the view name, as used in OPTIONS responses and in the + browsable API. + """ + func = self.settings.VIEW_NAME_FUNCTION + return func(self) + + def get_view_description(self, html=False): + """ + Return some descriptive text for the view, as used in OPTIONS responses + and in the browsable API. + """ + func = self.settings.VIEW_DESCRIPTION_FUNCTION + return func(self, html) + + # API policy instantiation methods + + def get_format_suffix(self, **kwargs): + """ + Determine if the request includes a '.json' style format suffix + """ + if self.settings.FORMAT_SUFFIX_KWARG: + return kwargs.get(self.settings.FORMAT_SUFFIX_KWARG) + + def get_renderers(self): + """ + Instantiates and returns the list of renderers that this view can use. + """ + return [renderer() for renderer in self.renderer_classes] + + def get_parsers(self): + """ + Instantiates and returns the list of parsers that this view can use. + """ + return [parser() for parser in self.parser_classes] + + def get_authenticators(self): + """ + Instantiates and returns the list of authenticators that this view can use. + """ + return [auth() for auth in self.authentication_classes] + + def get_permissions(self): + """ + Instantiates and returns the list of permissions that this view requires. + """ + return [permission() for permission in self.permission_classes] + + def get_throttles(self): + """ + Instantiates and returns the list of throttles that this view uses. + """ + return [throttle() for throttle in self.throttle_classes] + + def get_content_negotiator(self): + """ + Instantiate and return the content negotiation class to use. + """ + if not getattr(self, '_negotiator', None): + self._negotiator = self.content_negotiation_class() + return self._negotiator + + def get_exception_handler(self): + """ + Returns the exception handler that this view uses. + """ + return self.settings.EXCEPTION_HANDLER + + # API policy implementation methods + + def perform_content_negotiation(self, request, force=False): + """ + Determine which renderer and media type to use render the response. + """ + renderers = self.get_renderers() + conneg = self.get_content_negotiator() + + try: + return conneg.select_renderer(request, renderers, self.format_kwarg) + except Exception: + if force: + return (renderers[0], renderers[0].media_type) + raise + + def perform_authentication(self, request): + """ + Perform authentication on the incoming request. + + Note that if you override this and simply 'pass', then authentication + will instead be performed lazily, the first time either + `request.user` or `request.auth` is accessed. + """ + request.user + + def check_permissions(self, request): + """ + Check if the request should be permitted. + Raises an appropriate exception if the request is not permitted. + """ + for permission in self.get_permissions(): + if not permission.has_permission(request, self): + self.permission_denied( + request, + message=getattr(permission, 'message', None), + code=getattr(permission, 'code', None) + ) + + def check_object_permissions(self, request, obj): + """ + Check if the request should be permitted for a given object. + Raises an appropriate exception if the request is not permitted. + """ + for permission in self.get_permissions(): + if not permission.has_object_permission(request, self, obj): + self.permission_denied( + request, + message=getattr(permission, 'message', None), + code=getattr(permission, 'code', None) + ) + + def check_throttles(self, request): + """ + Check if request should be throttled. + Raises an appropriate exception if the request is throttled. + """ + throttle_durations = [] + for throttle in self.get_throttles(): + if not throttle.allow_request(request, self): + throttle_durations.append(throttle.wait()) + + if throttle_durations: + # Filter out `None` values which may happen in case of config / rate + # changes, see #1438 + durations = [ + duration for duration in throttle_durations + if duration is not None + ] + + duration = max(durations, default=None) + self.throttled(request, duration) + + def determine_version(self, request, *args, **kwargs): + """ + If versioning is being used, then determine any API version for the + incoming request. Returns a two-tuple of (version, versioning_scheme) + """ + if self.versioning_class is None: + return (None, None) + scheme = self.versioning_class() + return (scheme.determine_version(request, *args, **kwargs), scheme) + + # Dispatch methods + + def initialize_request(self, request, *args, **kwargs): + """ + Returns the initial request object. + """ + parser_context = self.get_parser_context(request) + + return Request( + request, + parsers=self.get_parsers(), + authenticators=self.get_authenticators(), + negotiator=self.get_content_negotiator(), + parser_context=parser_context + ) + + def initial(self, request, *args, **kwargs): + """ + Runs anything that needs to occur prior to calling the method handler. + """ + self.format_kwarg = self.get_format_suffix(**kwargs) + + # Perform content negotiation and store the accepted info on the request + neg = self.perform_content_negotiation(request) + request.accepted_renderer, request.accepted_media_type = neg + + # Determine the API version, if versioning is in use. + version, scheme = self.determine_version(request, *args, **kwargs) + request.version, request.versioning_scheme = version, scheme + + # Ensure that the incoming request is permitted + self.perform_authentication(request) + self.check_permissions(request) + self.check_throttles(request) + + def finalize_response(self, request, response, *args, **kwargs): + """ + Returns the final response object. + """ + # Make the error obvious if a proper response is not returned + assert isinstance(response, HttpResponseBase), ( + 'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` ' + 'to be returned from the view, but received a `%s`' + % type(response) + ) + + if isinstance(response, Response): + if not getattr(request, 'accepted_renderer', None): + neg = self.perform_content_negotiation(request, force=True) + request.accepted_renderer, request.accepted_media_type = neg + + response.accepted_renderer = request.accepted_renderer + response.accepted_media_type = request.accepted_media_type + response.renderer_context = self.get_renderer_context() + + # Add new vary headers to the response instead of overwriting. + vary_headers = self.headers.pop('Vary', None) + if vary_headers is not None: + patch_vary_headers(response, cc_delim_re.split(vary_headers)) + + for key, value in self.headers.items(): + response[key] = value + + return response + + def handle_exception(self, exc): + """ + Handle any exception that occurs, by returning an appropriate response, + or re-raising the error. + """ + if isinstance(exc, (exceptions.NotAuthenticated, + exceptions.AuthenticationFailed)): + # WWW-Authenticate header for 401 responses, else coerce to 403 + auth_header = self.get_authenticate_header(self.request) + + if auth_header: + exc.auth_header = auth_header + else: + exc.status_code = status.HTTP_403_FORBIDDEN + + exception_handler = self.get_exception_handler() + + context = self.get_exception_handler_context() + response = exception_handler(exc, context) + + if response is None: + self.raise_uncaught_exception(exc) + + response.exception = True + return response + + def raise_uncaught_exception(self, exc): + if settings.DEBUG: + request = self.request + renderer_format = getattr(request.accepted_renderer, 'format') + use_plaintext_traceback = renderer_format not in ('html', 'api', 'admin') + request.force_plaintext_errors(use_plaintext_traceback) + raise exc + + # Note: Views are made CSRF exempt from within `as_view` as to prevent + # accidental removal of this exemption in cases where `dispatch` needs to + # be overridden. + def dispatch(self, request, *args, **kwargs): + """ + `.dispatch()` is pretty much the same as Django's regular dispatch, + but with extra hooks for startup, finalize, and exception handling. + """ + self.args = args + self.kwargs = kwargs + request = self.initialize_request(request, *args, **kwargs) + self.request = request + self.headers = self.default_response_headers # deprecate? + + try: + self.initial(request, *args, **kwargs) + + # Get the appropriate handler method + if request.method.lower() in self.http_method_names: + handler = getattr(self, request.method.lower(), + self.http_method_not_allowed) + else: + handler = self.http_method_not_allowed + + response = handler(request, *args, **kwargs) + + except Exception as exc: + response = self.handle_exception(exc) + + self.response = self.finalize_response(request, response, *args, **kwargs) + return self.response + + def options(self, request, *args, **kwargs): + """ + Handler method for HTTP 'OPTIONS' request. + """ + if self.metadata_class is None: + return self.http_method_not_allowed(request, *args, **kwargs) + data = self.metadata_class().determine_metadata(request, self) + return Response(data, status=status.HTTP_200_OK) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/viewsets.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/viewsets.py new file mode 100644 index 0000000000000000000000000000000000000000..1c56f61e861f6802e04d7919f3136ee347695293 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework/viewsets.py @@ -0,0 +1,249 @@ +""" +ViewSets are essentially just a type of class based view, that doesn't provide +any method handlers, such as `get()`, `post()`, etc... but instead has actions, +such as `list()`, `retrieve()`, `create()`, etc... + +Actions are only bound to methods at the point of instantiating the views. + + user_list = UserViewSet.as_view({'get': 'list'}) + user_detail = UserViewSet.as_view({'get': 'retrieve'}) + +Typically, rather than instantiate views from viewsets directly, you'll +register the viewset with a router and let the URL conf be determined +automatically. + + router = DefaultRouter() + router.register(r'users', UserViewSet, 'user') + urlpatterns = router.urls +""" +from collections import OrderedDict +from functools import update_wrapper +from inspect import getmembers + +from django.urls import NoReverseMatch +from django.utils.decorators import classonlymethod +from django.views.decorators.csrf import csrf_exempt + +from rest_framework import generics, mixins, views +from rest_framework.decorators import MethodMapper +from rest_framework.reverse import reverse + + +def _is_extra_action(attr): + return hasattr(attr, 'mapping') and isinstance(attr.mapping, MethodMapper) + + +def _check_attr_name(func, name): + assert func.__name__ == name, ( + 'Expected function (`{func.__name__}`) to match its attribute name ' + '(`{name}`). If using a decorator, ensure the inner function is ' + 'decorated with `functools.wraps`, or that `{func.__name__}.__name__` ' + 'is otherwise set to `{name}`.').format(func=func, name=name) + return func + + +class ViewSetMixin: + """ + This is the magic. + + Overrides `.as_view()` so that it takes an `actions` keyword that performs + the binding of HTTP methods to actions on the Resource. + + For example, to create a concrete view binding the 'GET' and 'POST' methods + to the 'list' and 'create' actions... + + view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) + """ + + @classonlymethod + def as_view(cls, actions=None, **initkwargs): + """ + Because of the way class based views create a closure around the + instantiated view, we need to totally reimplement `.as_view`, + and slightly modify the view function that is created and returned. + """ + # The name and description initkwargs may be explicitly overridden for + # certain route configurations. eg, names of extra actions. + cls.name = None + cls.description = None + + # The suffix initkwarg is reserved for displaying the viewset type. + # This initkwarg should have no effect if the name is provided. + # eg. 'List' or 'Instance'. + cls.suffix = None + + # The detail initkwarg is reserved for introspecting the viewset type. + cls.detail = None + + # Setting a basename allows a view to reverse its action urls. This + # value is provided by the router through the initkwargs. + cls.basename = None + + # actions must not be empty + if not actions: + raise TypeError("The `actions` argument must be provided when " + "calling `.as_view()` on a ViewSet. For example " + "`.as_view({'get': 'list'})`") + + # sanitize keyword arguments + for key in initkwargs: + if key in cls.http_method_names: + raise TypeError("You tried to pass in the %s method name as a " + "keyword argument to %s(). Don't do that." + % (key, cls.__name__)) + if not hasattr(cls, key): + raise TypeError("%s() received an invalid keyword %r" % ( + cls.__name__, key)) + + # name and suffix are mutually exclusive + if 'name' in initkwargs and 'suffix' in initkwargs: + raise TypeError("%s() received both `name` and `suffix`, which are " + "mutually exclusive arguments." % (cls.__name__)) + + def view(request, *args, **kwargs): + self = cls(**initkwargs) + + if 'get' in actions and 'head' not in actions: + actions['head'] = actions['get'] + + # We also store the mapping of request methods to actions, + # so that we can later set the action attribute. + # eg. `self.action = 'list'` on an incoming GET request. + self.action_map = actions + + # Bind methods to actions + # This is the bit that's different to a standard view + for method, action in actions.items(): + handler = getattr(self, action) + setattr(self, method, handler) + + self.request = request + self.args = args + self.kwargs = kwargs + + # And continue as usual + return self.dispatch(request, *args, **kwargs) + + # take name and docstring from class + update_wrapper(view, cls, updated=()) + + # and possible attributes set by decorators + # like csrf_exempt from dispatch + update_wrapper(view, cls.dispatch, assigned=()) + + # We need to set these on the view function, so that breadcrumb + # generation can pick out these bits of information from a + # resolved URL. + view.cls = cls + view.initkwargs = initkwargs + view.actions = actions + return csrf_exempt(view) + + def initialize_request(self, request, *args, **kwargs): + """ + Set the `.action` attribute on the view, depending on the request method. + """ + request = super().initialize_request(request, *args, **kwargs) + method = request.method.lower() + if method == 'options': + # This is a special case as we always provide handling for the + # options method in the base `View` class. + # Unlike the other explicitly defined actions, 'metadata' is implicit. + self.action = 'metadata' + else: + self.action = self.action_map.get(method) + return request + + def reverse_action(self, url_name, *args, **kwargs): + """ + Reverse the action for the given `url_name`. + """ + url_name = '%s-%s' % (self.basename, url_name) + namespace = None + if self.request and self.request.resolver_match: + namespace = self.request.resolver_match.namespace + if namespace: + url_name = namespace + ':' + url_name + kwargs.setdefault('request', self.request) + + return reverse(url_name, *args, **kwargs) + + @classmethod + def get_extra_actions(cls): + """ + Get the methods that are marked as an extra ViewSet `@action`. + """ + return [_check_attr_name(method, name) + for name, method + in getmembers(cls, _is_extra_action)] + + def get_extra_action_url_map(self): + """ + Build a map of {names: urls} for the extra actions. + + This method will noop if `detail` was not provided as a view initkwarg. + """ + action_urls = OrderedDict() + + # exit early if `detail` has not been provided + if self.detail is None: + return action_urls + + # filter for the relevant extra actions + actions = [ + action for action in self.get_extra_actions() + if action.detail == self.detail + ] + + for action in actions: + try: + url_name = '%s-%s' % (self.basename, action.url_name) + namespace = self.request.resolver_match.namespace + if namespace: + url_name = '%s:%s' % (namespace, url_name) + + url = reverse(url_name, self.args, self.kwargs, request=self.request) + view = self.__class__(**action.kwargs) + action_urls[view.get_view_name()] = url + except NoReverseMatch: + pass # URL requires additional arguments, ignore + + return action_urls + + +class ViewSet(ViewSetMixin, views.APIView): + """ + The base ViewSet class does not provide any actions by default. + """ + pass + + +class GenericViewSet(ViewSetMixin, generics.GenericAPIView): + """ + The GenericViewSet class does not provide any actions by default, + but does include the base set of generic view behavior, such as + the `get_object` and `get_queryset` methods. + """ + pass + + +class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, + mixins.ListModelMixin, + GenericViewSet): + """ + A viewset that provides default `list()` and `retrieve()` actions. + """ + pass + + +class ModelViewSet(mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + mixins.ListModelMixin, + GenericViewSet): + """ + A viewset that provides default `create()`, `retrieve()`, `update()`, + `partial_update()`, `destroy()` and `list()` actions. + """ + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6929b410c705a4ee4f31d6c01c8ecd03ca40137a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__init__.py @@ -0,0 +1,7 @@ +from pkg_resources import DistributionNotFound, get_distribution + +try: + __version__ = get_distribution("djangorestframework_simplejwt").version +except DistributionNotFound: + # package is not installed + __version__ = None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..784265e6c16cc17dd416118413cc9a418d6e5848 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/authentication.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/authentication.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66fc6867de93ced98701f55248105aca63e6c09a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/authentication.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/backends.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/backends.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bbc026f108babd65350f210233fe219b81888e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/backends.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8079fd92a0f67112a51494b8e10753a590447efa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b04a3baff8266cb9a0f19f0e38db5a168b07be29 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..625e0e15624779eb428a3a706585dc1ee4908686 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/serializers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a92f1ea2128bd8ea66d8dcc157c57124d627ca9e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/serializers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/settings.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfe037497d7fb6643acd49f42d2b4f6b3a48baf1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/settings.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/state.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/state.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebb7bc9028a61da0845a231bd218fbcea994dc12 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/state.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/tokens.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/tokens.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e5e42a7e974a6f83f1b7e546910ed3fc122b6cf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/tokens.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..973007469ab5406375f4777049e5266c41d6e2f3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5475fd44e3d1df1cc296d3de8c90ef343a9699c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/authentication.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/authentication.py new file mode 100644 index 0000000000000000000000000000000000000000..32899ddd0c0c42b81e678f97b6c3e6f0c6e44ded --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/authentication.py @@ -0,0 +1,147 @@ +from django.contrib.auth import get_user_model +from django.utils.translation import gettext_lazy as _ +from rest_framework import HTTP_HEADER_ENCODING, authentication + +from .exceptions import AuthenticationFailed, InvalidToken, TokenError +from .settings import api_settings + +AUTH_HEADER_TYPES = api_settings.AUTH_HEADER_TYPES + +if not isinstance(api_settings.AUTH_HEADER_TYPES, (list, tuple)): + AUTH_HEADER_TYPES = (AUTH_HEADER_TYPES,) + +AUTH_HEADER_TYPE_BYTES = set( + h.encode(HTTP_HEADER_ENCODING) + for h in AUTH_HEADER_TYPES +) + + +class JWTAuthentication(authentication.BaseAuthentication): + """ + An authentication plugin that authenticates requests through a JSON web + token provided in a request header. + """ + www_authenticate_realm = 'api' + media_type = 'application/json' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user_model = get_user_model() + + def authenticate(self, request): + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), validated_token + + def authenticate_header(self, request): + return '{0} realm="{1}"'.format( + AUTH_HEADER_TYPES[0], + self.www_authenticate_realm, + ) + + def get_header(self, request): + """ + Extracts the header containing the JSON web token from the given + request. + """ + header = request.META.get(api_settings.AUTH_HEADER_NAME) + + if isinstance(header, str): + # Work around django test client oddness + header = header.encode(HTTP_HEADER_ENCODING) + + return header + + def get_raw_token(self, header): + """ + Extracts an unvalidated JSON web token from the given "Authorization" + header value. + """ + parts = header.split() + + if len(parts) == 0: + # Empty AUTHORIZATION header sent + return None + + if parts[0] not in AUTH_HEADER_TYPE_BYTES: + # Assume the header does not contain a JSON web token + return None + + if len(parts) != 2: + raise AuthenticationFailed( + _('Authorization header must contain two space-delimited values'), + code='bad_authorization_header', + ) + + return parts[1] + + def get_validated_token(self, raw_token): + """ + Validates an encoded JSON web token and returns a validated token + wrapper object. + """ + messages = [] + for AuthToken in api_settings.AUTH_TOKEN_CLASSES: + try: + return AuthToken(raw_token) + except TokenError as e: + messages.append({'token_class': AuthToken.__name__, + 'token_type': AuthToken.token_type, + 'message': e.args[0]}) + + raise InvalidToken({ + 'detail': _('Given token not valid for any token type'), + 'messages': messages, + }) + + def get_user(self, validated_token): + """ + Attempts to find and return a user using the given validated token. + """ + try: + user_id = validated_token[api_settings.USER_ID_CLAIM] + except KeyError: + raise InvalidToken(_('Token contained no recognizable user identification')) + + try: + user = self.user_model.objects.get(**{api_settings.USER_ID_FIELD: user_id}) + except self.user_model.DoesNotExist: + raise AuthenticationFailed(_('User not found'), code='user_not_found') + + if not user.is_active: + raise AuthenticationFailed(_('User is inactive'), code='user_inactive') + + return user + + +class JWTTokenUserAuthentication(JWTAuthentication): + def get_user(self, validated_token): + """ + Returns a stateless user object which is backed by the given validated + token. + """ + if api_settings.USER_ID_CLAIM not in validated_token: + # The TokenUser class assumes tokens will have a recognizable user + # identifier claim. + raise InvalidToken(_('Token contained no recognizable user identification')) + + return api_settings.TOKEN_USER_CLASS(validated_token) + + +def default_user_authentication_rule(user): + # Prior to Django 1.10, inactive users could be authenticated with the + # default `ModelBackend`. As of Django 1.10, the `ModelBackend` + # prevents inactive users from authenticating. App designers can still + # allow inactive users to authenticate by opting for the new + # `AllowAllUsersModelBackend`. However, we explicitly prevent inactive + # users from authenticating to enforce a reasonable policy and provide + # sensible backwards compatibility with older Django versions. + return user is not None and user.is_active diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/backends.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/backends.py new file mode 100644 index 0000000000000000000000000000000000000000..d4844471fe6ed20b744416dc4caa1d7a8d76d22d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/backends.py @@ -0,0 +1,106 @@ +from django.utils.translation import gettext_lazy as _ +import jwt +from jwt import InvalidAlgorithmError, InvalidTokenError, PyJWKClient, algorithms + +from .exceptions import TokenBackendError +from .utils import format_lazy + +ALLOWED_ALGORITHMS = ( + 'HS256', + 'HS384', + 'HS512', + 'RS256', + 'RS384', + 'RS512', +) + + +class TokenBackend: + def __init__( + self, + algorithm, + signing_key=None, + verifying_key=None, + audience=None, + issuer=None, + jwk_url: str = None, + leeway=0, + ): + self._validate_algorithm(algorithm) + + self.algorithm = algorithm + self.signing_key = signing_key + self.audience = audience + self.issuer = issuer + + self.jwks_client = PyJWKClient(jwk_url) if jwk_url else None + self.leeway = leeway + + if algorithm.startswith("HS"): + self.verifying_key = signing_key + else: + self.verifying_key = verifying_key + + def _validate_algorithm(self, algorithm): + """ + Ensure that the nominated algorithm is recognized, and that cryptography is installed for those + algorithms that require it + """ + if algorithm not in ALLOWED_ALGORITHMS: + raise TokenBackendError(format_lazy(_("Unrecognized algorithm type '{}'"), algorithm)) + + if algorithm in algorithms.requires_cryptography and not algorithms.has_crypto: + raise TokenBackendError(format_lazy(_("You must have cryptography installed to use {}."), algorithm)) + + def get_verifying_key(self, token): + if self.algorithm.startswith("HS"): + return self.signing_key + + if self.jwks_client: + return self.jwks_client.get_signing_key_from_jwt(token).key + + return self.verifying_key + + def encode(self, payload): + """ + Returns an encoded token for the given payload dictionary. + """ + jwt_payload = payload.copy() + if self.audience is not None: + jwt_payload['aud'] = self.audience + if self.issuer is not None: + jwt_payload['iss'] = self.issuer + + token = jwt.encode(jwt_payload, self.signing_key, algorithm=self.algorithm) + if isinstance(token, bytes): + # For PyJWT <= 1.7.1 + return token.decode('utf-8') + # For PyJWT >= 2.0.0a1 + return token + + def decode(self, token, verify=True): + """ + Performs a validation of the given token and returns its payload + dictionary. + + Raises a `TokenBackendError` if the token is malformed, if its + signature check fails, or if its 'exp' claim indicates it has expired. + """ + try: + return jwt.decode( + token, + self.get_verifying_key(token), + algorithms=[self.algorithm], + verify=verify, + audience=self.audience, + issuer=self.issuer, + leeway=self.leeway, + options={ + 'verify_aud': self.audience is not None, + 'verify_signature': verify, + }, + ) + except InvalidAlgorithmError as ex: + raise TokenBackendError(_('Invalid algorithm specified')) from ex + except InvalidTokenError: + raise TokenBackendError(_('Token is invalid or expired')) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..dda6f3c9622f424a1bd65b12dc018e982c71b5ff --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/compat.py @@ -0,0 +1,53 @@ +import warnings + +try: + from django.urls import reverse, reverse_lazy +except ImportError: + from django.core.urlresolvers import reverse, reverse_lazy # NOQA + + +class RemovedInDjango20Warning(DeprecationWarning): + pass + + +class CallableBool: # pragma: no cover + """ + An boolean-like object that is also callable for backwards compatibility. + """ + do_not_call_in_templates = True + + def __init__(self, value): + self.value = value + + def __bool__(self): + return self.value + + def __call__(self): + warnings.warn( + "Using user.is_authenticated() and user.is_anonymous() as a method " + "is deprecated. Remove the parentheses to use it as an attribute.", + RemovedInDjango20Warning, stacklevel=2 + ) + return self.value + + def __nonzero__(self): # Python 2 compatibility + return self.value + + def __repr__(self): + return 'CallableBool(%r)' % self.value + + def __eq__(self, other): + return self.value == other + + def __ne__(self, other): + return self.value != other + + def __or__(self, other): + return bool(self.value or other) + + def __hash__(self): + return hash(self.value) + + +CallableFalse = CallableBool(False) +CallableTrue = CallableBool(True) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..530d3a8e052bef78e20ba962cd2b1604c3b2b44e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/exceptions.py @@ -0,0 +1,39 @@ +from django.utils.translation import gettext_lazy as _ +from rest_framework import exceptions, status + + +class TokenError(Exception): + pass + + +class TokenBackendError(Exception): + pass + + +class DetailDictMixin: + def __init__(self, detail=None, code=None): + """ + Builds a detail dictionary for the error to give more information to API + users. + """ + detail_dict = {'detail': self.default_detail, 'code': self.default_code} + + if isinstance(detail, dict): + detail_dict.update(detail) + elif detail is not None: + detail_dict['detail'] = detail + + if code is not None: + detail_dict['code'] = code + + super().__init__(detail_dict) + + +class AuthenticationFailed(DetailDictMixin, exceptions.AuthenticationFailed): + pass + + +class InvalidToken(AuthenticationFailed): + status_code = status.HTTP_401_UNAUTHORIZED + default_detail = _('Token is invalid or expired') + default_code = 'token_not_valid' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2e2be82a97ab33c1b333a3efd79ff1a31a38ae2a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..16fd7ad4cc781ca72ad74f4f242bebf24f5ea9e5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,106 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <info@lukasrod.cz>, 2019. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Lukáš Rod <info@lukasrod.cz>\n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "Autorizační hlavička musí obsahovat dvě hodnoty oddělené mezerou" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Daný token není validní pro žádný typ tokenu" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Token neobsahoval žádnou rozpoznatelnou identifikaci uživatele" + +#: authentication.py:116 +msgid "User not found" +msgstr "Uživatel nenalezen" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Uživatel není aktivní" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Nerozpoznaný typ algoritmu '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Token není validní nebo vypršela jeho platnost" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Žádný aktivní účet s danými údaji nebyl nalezen" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "Nastavení '{}' bylo odstraněno. Dostupná nastavení jsou v '{}'" + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "uživatel" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "vytvořený v" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "platí do" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Nelze vytvořit token bez zadaného typu nebo životnosti" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token nemá žádný identifikátor" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token nemá žádný typ" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token má špatný typ" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token nemá žádnou hodnotu '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Hodnota tokenu '{}' vypršela" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token je na černé listině" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..52eae959f78ccc7004831554dbf831d8b071fd2a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..5b70353ff1bee1decb68ad6692eef4011947eb03 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/de_CH/LC_MESSAGES/django.po @@ -0,0 +1,110 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <rene@matraxi.ch>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: rene <rene@matraxi.ch>\n" +"Language: de_CH\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"Der Authorizationheader muss zwei leerzeichen-getrennte Werte enthalten" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Der Token ist für keinen Tokentyp gültig" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Token enthält keine erkennbare Benutzeridentifikation" + +#: authentication.py:116 +msgid "User not found" +msgstr "Benutzer nicht gefunden" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Inaktiver Benutzer" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Unerkannter Algorithmustyp '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Ungültiger oder abgelaufener Token" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Kein aktiver Account mit diesen Zugangsdaten gefunden" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"Die Einstellung '{}' wurde gelöscht. Bitte beachte '{}' für verfügbare " +"Einstellungen." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "Benutzer" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "erstellt am" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "läuft ab am" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Ein Token ohne Typ oder Lebensdauer kann nicht erstellt werden" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token hat keine Id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token hat keinen Typ" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token hat den falschen Typ" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token hat kein '{}' Recht" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Das Tokenrecht '{}' ist abgelaufen" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token steht auf der Blacklist" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a25a73868622601b4d4334a14a5556943f346482 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..6e647115c75e9ff201117b7f00b2b1c738b048e1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,110 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <zeack@protonmail.com>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: zeack <zeack@protonmail.com>\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"El encabezado 'Authorization' debe contener valores delimitados por espacios" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "El token dado no es valido para ningun tipo de token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "El token no contenía identificación de usuario reconocible" + +#: authentication.py:116 +msgid "User not found" +msgstr "Usuario no encontrado" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "El usuario está inactivo" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Tipo de algoritmo no reconocido '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Debe tener criptografía instalada para usar {}." + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "Algoritmo especificado no válido" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "El token es inválido o ha expirado" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "La combination de credenciales no tiene una cuenta activa" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"La configuración '{}' fue removida. Por favor, refiérase a '{}' para " +"consultar las disponibles." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "usuario" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "creado en" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "expira en" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Lista negra de Tokens" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "No se puede crear un token sin tipo o de tan larga vida" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "El token no tiene id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "El token no tiene tipo" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "El token tiene un tipo incorrecto" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "El token no tiene el privilegio '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "El privilegio '{}' del token ha expirado" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "El token está en lista negra" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..968365d9e33d43e0fb7431395d514f9be317bc15 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..ebec2a3de93f81d97485b7bdf17ff87388f1cc93 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.po @@ -0,0 +1,116 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Ariel Torti <arieltorti14@gmail.com>, 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Ariel Torti <arieltort14@gmail.com>\n" +"Language: es_AR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"El header de autorización debe contener dos valores delimitados por espacio" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "El token dado no es válido para ningún tipo de token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "El token no contiene ninguna identificación de usuario" + +#: authentication.py:116 +msgid "User not found" +msgstr "Usuario no encontrado" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "El usuario está inactivo" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Tipo de algoritmo no reconocido '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "El token es inválido o ha expirado" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "" +"No se encontró una cuenta de usuario activa para las credenciales dadas" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"La configuración '{}' fue removida. Por favor, refiérase a '{}' para " +"consultar las configuraciones disponibles." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "usuario" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "creado en" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "expira en" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Lista negra de Tokens" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "No es posible crear un token sin tipo o tiempo de vida" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "El token no tiene id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "El token no tiene tipo" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "El token tiene un tipo incorrecto" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "El token no tiene el privilegio '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "El privilegio '{}' del token ha expirado" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "El token está en la lista negra" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a7dea8ecaa93750df4c3f2693673b7d10cd4400b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..2869d6b0dff98599b147575d9af7cd393007d9ae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.po @@ -0,0 +1,111 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <alfonso.pola@gmail.com>, 2019. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Alfonso Pola <alfonso.pola@gmail.com>\n" +"Language: es_CL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"El header de autorización debe contener dos valores delimitados por espacio" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "El token provisto no es válido para ningún tipo de token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "El token no contiene identificación de usuario reconocible" + +#: authentication.py:116 +msgid "User not found" +msgstr "Usuario no encontrado" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "El usuario está inactivo" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Tipo de algoritmo no reconocido '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Token inválido o expirado" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "" +"No se encontró una cuenta de usuario activa para las credenciales provistas" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"La configuración '{}' fue removida. Por favor, refiérase a '{}' para " +"configuraciones disponibles." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "Usuario" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "creado en" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "expira en" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "No es posible crear un token sin tipo o tiempo de vida" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token no tiene id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token no tiene tipo" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token tiene tipo erróneo" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token no tiene privilegio '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "El provilegio '{}' del token está expirado" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token está en la blacklist" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5af1970973fcbc9e108a82e3430326bc30369ceb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..f39b6b16291a0f9460d6843ccf9f19ea095955e3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.po @@ -0,0 +1,106 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <hirad.daneshvar@gmail.com>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Hirad Daneshvar <hirad.daneshvar@gmail.com>\n" +"Language: fa_IR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "هدر اعتبارسنجی باید شامل دو مقدار جدا شده با فاصله باشد" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "توکن داده شده برای هیچ نوع توکنی معتبر نمیباشد" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "توکن شامل هیچ شناسه قابل تشخیصی از کاربر نیست" + +#: authentication.py:116 +msgid "User not found" +msgstr "کاربر یافت نشد" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "کاربر غیرفعال است" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "نوع الگوریتم ناشناخته '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "توکن نامعتبر است یا منقضی شده است" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "هیچ اکانت فعالی برای اطلاعات داده شده یافت نشد" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "تنظیمات '{}' حذف شده است. لطفا به '{}' برای تنظیمات موجود مراجعه کنید." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "کاربر" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "زمان ایجاد" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "زمان انقضا" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "لیست سیاه توکن" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "توکن بدون هیچ نوع و طول عمر قابل ساخت نیست" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "توکن id ندارد" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "توکن نوع ندارد" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "توکن نوع اشتباهی دارد" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "توکن دارای '{}' claim نمیباشد" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "'{}' claim توکن منقضی شده" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "توکن به لیست سیاه رفته است" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5165dd9126e08f013856757d7bdfe0d36bb76677 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..fd2cd1c16b6b5d56332dada189ea87505767aab1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,110 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <stephane.maltaesousa@ne.ch>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Stéphane Malta e Sousa <stephane.maltaesousa@ne.ch>\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"L'en-tête 'Authorization' doit contenir deux valeurs séparées par des espaces" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Le type de jeton fourni n'est pas valide" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "" +"Le jeton ne contient aucune information permettant d'identifier l'utilisateur" + +#: authentication.py:116 +msgid "User not found" +msgstr "L'utilisateur n'a pas été trouvé" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "L'utilisateur est désactivé" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Type d'algorithme non reconnu '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Vous devez installer cryptography afin d'utiliser {}." + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "L'algorithme spécifié est invalide" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Le jeton est invalide ou expiré" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Aucun compte actif n'a été trouvé avec les identifiants fournis" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"Le paramètre '{}' a été supprimé. Voir '{}' pour la liste des paramètres " +"disponibles." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "Utilisateur" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "Créé le" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "Expire le" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Liste des jetons bannis" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Ne peut pas créer de jeton sans type ni durée de vie" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Le jeton n'a pas d'id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Le jeton n'a pas de type" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Le jeton a un type erroné" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Le jeton n'a pas le privilège '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Le privilège '{}' du jeton a expiré" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Le jeton a été banni" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..33f3f669f3431da664dc506d1a436c041642ec0d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..bab7fc9738200c0a94dd19c46e1dfddd10c18f98 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.po @@ -0,0 +1,109 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <oon.arfiandwi@gmail.com>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: oon arfiandwi <oon.arfiandwi@gmail.com>\n" +"Language: id_ID\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "Header otorisasi harus berisi dua nilai yang dipisahkan spasi" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Token yang diberikan tidak valid untuk semua jenis token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Token tidak mengandung identifikasi pengguna yang dapat dikenali" + +#: authentication.py:116 +msgid "User not found" +msgstr "Pengguna tidak ditemukan" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Pengguna tidak aktif" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Jenis algoritma tidak dikenal '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Anda harus memasang kriptografi untuk menggunakan {}." + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "Algoritma yang ditentukan tidak valid" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Token tidak valid atau kedaluwarsa" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Tidak ada akun aktif yang ditemukan dengan kredensial yang diberikan" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"Setelan '{}' telah dihapus. Silakan merujuk ke '{}' untuk pengaturan yang " +"tersedia." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "pengguna" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "created at" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "kedaluwarsa pada" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Daftar Hitam Token" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Tidak dapat membuat token tanpa tipe atau masa pakai" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token tidak memiliki id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token tidak memiliki tipe" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Jenis token salah" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token tidak memiliki klaim '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Klaim token '{}' telah kedaluwarsa" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token masuk daftar hitam" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1708e9dd890ba0a8008ee2b95afe8d319deb4a79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..ec5212282616ae0e8cf2e6fdbb8a53edb7536220 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.po @@ -0,0 +1,113 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <95adriano@gmail.com>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"PO-Revision-Date: \n" +"Last-Translator: Adriano Di Dio <95adriano@gmail.com>\n" +"Language-Team: \n" +"Language: it_IT\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.6\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"L'header di autorizzazione deve contenere due valori delimitati da uno spazio" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Il token dato non è valido per qualsiasi tipo di token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Il token non conteneva nessuna informazione riconoscibile dell'utente" + +#: authentication.py:116 +msgid "User not found" +msgstr "Utente non trovato" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Utente non attivo" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Algoritmo di tipo '{}' non riconosciuto" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Devi avere installato cryptography per usare '{}'." + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "L'algoritmo specificato non è valido" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Il token non è valido o è scaduto" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Nessun account attivo trovato con queste credenziali" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"L'impostazione '{}' è stata rimossa. Per favore utilizza '{}' per " +"visualizzare le impostazioni valide." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "utente" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "creato il" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "scade il" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Blacklist dei token" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Impossibile creare un token senza tipo o durata" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Il token non ha un id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Il token non ha un tipo" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Il token ha un tipo sbagliato" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Il token non contiene il parametro '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Il parametro '{}' del token è scaduto" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Il token è stato inserito nella blacklist" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f68b4bf84775472f0a497d2908b5d4c6315cdfbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..856e1f97f389653a91e7f8513a601b1fd31356e7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.po @@ -0,0 +1,108 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <rene@roadbearstudios.com>, 2020. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-06-17 11:06+0200\n" +"Last-Translator: rene <rene@roadbearstudios.com>\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"Authorisatie header moet twee waarden bevatten, gescheiden door een spatie" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Het token is voor geen enkel token-type geldig" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Token bevat geen herkenbare gebruikersidentificatie" + +#: authentication.py:116 +msgid "User not found" +msgstr "Gebruiker niet gevonden" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Gebruiker is inactief" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Niet herkend algoritme type '{}" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Token is niet geldig of verlopen" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Geen actief account gevonden voor deze gegevens" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"De '{}' instelling bestaat niet meer. Zie '{}' for beschikbareinstellingen." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "gebruiker" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "aangemaakt op" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "verloopt op" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Kan geen token maken zonder type of levensduur" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token heeft geen id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token heeft geen type" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token heeft het verkeerde type" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token heeft geen '{}' recht" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Token '{}' recht is verlopen" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token is ge-blacklist" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3b3451154fe4cff6dfebc25cd6730fe58d8e19bd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..425320a6fc9d9598f8287e298457dfd1e1d79626 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.po @@ -0,0 +1,107 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <mat.slisz@yahoo.com>, 2019. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Mateusz Slisz <mat.slisz@yahoo.com>\n" +"Language: pl_PL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "Nagłówek autoryzacji musi zawierać dwie wartości rodzielone spacjami" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Podany token jest błędny dla każdego typu tokena" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Token nie zawierał rozpoznawalnej identyfikacji użytkownika" + +#: authentication.py:116 +msgid "User not found" +msgstr "Użytkownik nie znaleziony" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Użytkownik jest nieaktywny" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Nierozpoznany typ algorytmu '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Token jest niepoprawny lub wygasł" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Nie znaleziono aktywnego konta dla podanych danych uwierzytelniających" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"Ustawienie '{}' zostało usunięte. Dostępne ustawienia znajdują sie w '{}'" + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "użytkownik" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "stworzony w" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "wygasa o" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Nie można utworzyć tokena bez podanego typu lub żywotności" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token nie posiada numeru identyfikacyjnego" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token nie posiada typu" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token posiada zły typ" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token nie posiada upoważnienia '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Upoważnienie tokena '{}' wygasło" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token znajduję się na czarnej liście" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7592fcb28fb76d1386f315edba252bf5e5d17545 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..e36cecfc269f777e587e7800bfc609ab3d272154 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,110 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <sinvalju@gmail.com>, 2019. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"Last-Translator: Bruno Ducraux <bruno.drx@gmail.com>\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"Cabeçalho de autorização deve conter dois valores delimitados por espaço" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "O token informado não é válido para qualquer tipo de token" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "O token não continha nenhuma identificação reconhecível do usuário" + +#: authentication.py:116 +msgid "User not found" +msgstr "Usuário não encontrado" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Usuário está inativo" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Tipo de algoritmo '{}' não reconhecido" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Você deve ter criptografia instalada para usar {}." + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "Algoritmo inválido especificado" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "O token é inválido ou expirado" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Usuário e/ou senha incorreto(s)" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"A configuração '{}' foi removida. Por favor, consulte '{}' para disponível " +"definições." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "usuário" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "criado em" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "expira em" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Lista negra de Tokens" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Não é possível criar token sem tipo ou tempo de vida" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "Token não tem id" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Token não tem nenhum tipo" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Token tem tipo errado" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Token não tem '{}' privilégio" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "O privilégio '{}' do token expirou" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Token está na blacklist" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ce573f2042cfba2cab94e14f27c9edd600e4720e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..afafee8b6e5fecf35e46599bc2c66610c1322bdf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.po @@ -0,0 +1,114 @@ +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <sinvalju@gmail.com>, 2019. +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-22 17:30+0100\n" +"PO-Revision-Date: \n" +"Last-Translator: Sergey Ozeranskiy <sozeranskiy@dreamclass.ru>\n" +"Language-Team: \n" +"Language: ru_RU\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 2.2.1\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "" +"Заголовок авторизации должен содержать два значения, разделенных пробелом" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Данный токен недействителен для любого типа токена" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Токен не содержит идентификатор пользователя" + +#: authentication.py:116 +msgid "User not found" +msgstr "Пользователь не найден" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "Пользователь неактивен" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Нераспознанный тип алгоритма '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Токен недействителен или просрочен" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Не найдено активной учетной записи с указанными данными" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"Параметр '{}' был удален. Пожалуйста, обратитесь к '{}' для просмотра " +"доступных настроек." + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "пользователь" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "создан" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "истекает" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Token Blacklist" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Невозможно создать токен без типа или времени жизни" + +#: tokens.py:98 +msgid "Token has no id" +msgstr "У токена нет идентификатора" + +#: tokens.py:109 +msgid "Token has no type" +msgstr "Токен не имеет типа" + +#: tokens.py:112 +msgid "Token has wrong type" +msgstr "Токен имеет неправильный тип" + +#: tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "Токен не содержит '{}'" + +#: tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Токен имеет просроченное значение '{}'" + +#: tokens.py:192 +msgid "Token is blacklisted" +msgstr "Токен занесен в черный список" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..80681b04eefda4f7d5eaec8621464a153567b738 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..13bdf0192eae6703008c9083e83fde188e556899 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.po @@ -0,0 +1,113 @@ +# This file is distributed under the same license as the PACKAGE package. +# Artiukhov Artem <defenite@meta.ua>, 2021. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-06-17 12:32+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Artiukhov Artem <defenite@meta.ua>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: uk_UA\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: rest_framework_simplejwt/authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "Авторизаційний заголовок має містити два значення розділені пробілом" + +#: rest_framework_simplejwt/authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "Наданий токен не відповідає жодному типу ключа" + +#: rest_framework_simplejwt/authentication.py:111 +#: rest_framework_simplejwt/authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "Наданий токен не мітить жодної ідентифікаційної інформації" + +#: rest_framework_simplejwt/authentication.py:116 +msgid "User not found" +msgstr "Користувач не знайдений" + +#: rest_framework_simplejwt/authentication.py:119 +msgid "User is inactive" +msgstr "Користувач неактивний" + +#: rest_framework_simplejwt/backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "Тип алгоритму '{}' не розпізнаний" + +#: rest_framework_simplejwt/backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "Встановіть модуль cryptography щоб використовувати {}" + +#: rest_framework_simplejwt/backends.py:74 +msgid "Invalid algorithm specified" +msgstr "Вказаний невірний алгоритм" + +#: rest_framework_simplejwt/backends.py:76 +#: rest_framework_simplejwt/exceptions.py:38 +#: rest_framework_simplejwt/tokens.py:44 +msgid "Token is invalid or expired" +msgstr "Токен некоректний або термін його дії вичерпаний" + +#: rest_framework_simplejwt/serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "Не знайдено жодного облікового запису по наданих облікових даних" + +#: rest_framework_simplejwt/settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "Налаштування '{}' видалене. Подивіться у '{}' для інших доступних" + +#: rest_framework_simplejwt/token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: rest_framework_simplejwt/token_blacklist/admin.py:77 +msgid "user" +msgstr "користувач" + +#: rest_framework_simplejwt/token_blacklist/admin.py:82 +msgid "created at" +msgstr "створений о" + +#: rest_framework_simplejwt/token_blacklist/admin.py:87 +msgid "expires at" +msgstr "дійстний по" + +#: rest_framework_simplejwt/token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "Чорний список токенів" + +#: rest_framework_simplejwt/tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "Неможливо створити токен без типу або строку дії" + +#: rest_framework_simplejwt/tokens.py:98 +msgid "Token has no id" +msgstr "У ключі доступу не міститься id" + +#: rest_framework_simplejwt/tokens.py:109 +msgid "Token has no type" +msgstr "У ключі доступу не міститься тип" + +#: rest_framework_simplejwt/tokens.py:112 +msgid "Token has wrong type" +msgstr "токен позначений невірним типом" + +#: rest_framework_simplejwt/tokens.py:149 +msgid "Token has no '{}' claim" +msgstr "У токені не міститься '{}' заголовку" + +#: rest_framework_simplejwt/tokens.py:153 +msgid "Token '{}' claim has expired" +msgstr "Заголовок '{}' токена не дійсний" + +#: rest_framework_simplejwt/tokens.py:192 +msgid "Token is blacklisted" +msgstr "Токен занесений у чорний список" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.mo b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0d5f317f2b71fc74f40db9fdc54051b813b7c8e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.mo differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.po b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 0000000000000000000000000000000000000000..3ba45f0f35ed5818ed0d13efdf1b999fb8877e08 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,113 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2021 +# This file is distributed under the same license as the Simple JWT package. +# zengqiu <zengqiu@qq.com>, 2021. + +msgid "" +msgstr "" +"Project-Id-Version: djangorestframework_simplejwt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-06-23 13:29+0800\n" +"PO-Revision-Date: 2021-06-23 13:29+080\n" +"Last-Translator: zengqiu <zengqiu@qq.com>\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: authentication.py:79 +msgid "Authorization header must contain two space-delimited values" +msgstr "授权头必须包含两个用空格分隔的值" + +#: authentication.py:100 +msgid "Given token not valid for any token type" +msgstr "此令牌对任何类型的令牌无效" + +#: authentication.py:111 authentication.py:133 +msgid "Token contained no recognizable user identification" +msgstr "令牌未包含用户标识符" + +#: authentication.py:116 +msgid "User not found" +msgstr "未找到该用户" + +#: authentication.py:119 +msgid "User is inactive" +msgstr "该用户已禁用" + +#: backends.py:37 +msgid "Unrecognized algorithm type '{}'" +msgstr "未知算法类型 '{}'" + +#: backends.py:40 +msgid "You must have cryptography installed to use {}." +msgstr "你必须安装 cryptography 才能使用 {}。" + +#: backends.py:74 +msgid "Invalid algorithm specified" +msgstr "指定的算法无效" + +#: backends.py:76 exceptions.py:38 tokens.py:44 +msgid "Token is invalid or expired" +msgstr "令牌无效或已过期" + +#: serializers.py:24 +msgid "No active account found with the given credentials" +msgstr "找不到指定凭据对应的有效用户" + +#: settings.py:63 +msgid "" +"The '{}' setting has been removed. Please refer to '{}' for available " +"settings." +msgstr "" +"'{}' 配置已被移除。 请参阅 '{}' 获取可用的" +"配置。" + +#: token_blacklist/admin.py:72 +msgid "jti" +msgstr "jti" + +#: token_blacklist/admin.py:77 +msgid "user" +msgstr "用户" + +#: token_blacklist/admin.py:82 +msgid "created at" +msgstr "创建时间" + +#: token_blacklist/admin.py:87 +msgid "expires at" +msgstr "过期时间" + +#: token_blacklist/apps.py:7 +msgid "Token Blacklist" +msgstr "令牌黑名单" + +#: tokens.py:30 +msgid "Cannot create token with no type or lifetime" +msgstr "无法创建没有类型或生存期的令牌" + +#: tokens.py:96 +msgid "Token has no id" +msgstr "令牌没有标识符" + +#: tokens.py:107 +msgid "Token has no type" +msgstr "令牌没有类型" + +#: tokens.py:110 +msgid "Token has wrong type" +msgstr "令牌类型错误" + +#: tokens.py:147 +msgid "Token has no '{}' claim" +msgstr "令牌没有 '{}' 声明" + +#: tokens.py:151 +msgid "Token '{}' claim has expired" +msgstr "令牌 '{}' 声明已过期" + +#: tokens.py:194 +msgid "Token is blacklisted" +msgstr "令牌已被加入黑名单" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/models.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/models.py new file mode 100644 index 0000000000000000000000000000000000000000..d317788d57327afca069893b6af0476e1efa9435 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/models.py @@ -0,0 +1,104 @@ +from django.contrib.auth import models as auth_models +from django.db.models.manager import EmptyManager +from django.utils.functional import cached_property + +from .compat import CallableFalse, CallableTrue +from .settings import api_settings + + +class TokenUser: + """ + A dummy user class modeled after django.contrib.auth.models.AnonymousUser. + Used in conjunction with the `JWTTokenUserAuthentication` backend to + implement single sign-on functionality across services which share the same + secret key. `JWTTokenUserAuthentication` will return an instance of this + class instead of a `User` model instance. Instances of this class act as + stateless user objects which are backed by validated tokens. + """ + # User is always active since Simple JWT will never issue a token for an + # inactive user + is_active = True + + _groups = EmptyManager(auth_models.Group) + _user_permissions = EmptyManager(auth_models.Permission) + + def __init__(self, token): + self.token = token + + def __str__(self): + return 'TokenUser {}'.format(self.id) + + @cached_property + def id(self): + return self.token[api_settings.USER_ID_CLAIM] + + @cached_property + def pk(self): + return self.id + + @cached_property + def username(self): + return self.token.get('username', '') + + @cached_property + def is_staff(self): + return self.token.get('is_staff', False) + + @cached_property + def is_superuser(self): + return self.token.get('is_superuser', False) + + def __eq__(self, other): + return self.id == other.id + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.id) + + def save(self): + raise NotImplementedError('Token users have no DB representation') + + def delete(self): + raise NotImplementedError('Token users have no DB representation') + + def set_password(self, raw_password): + raise NotImplementedError('Token users have no DB representation') + + def check_password(self, raw_password): + raise NotImplementedError('Token users have no DB representation') + + @property + def groups(self): + return self._groups + + @property + def user_permissions(self): + return self._user_permissions + + def get_group_permissions(self, obj=None): + return set() + + def get_all_permissions(self, obj=None): + return set() + + def has_perm(self, perm, obj=None): + return False + + def has_perms(self, perm_list, obj=None): + return False + + def has_module_perms(self, module): + return False + + @property + def is_anonymous(self): + return CallableFalse + + @property + def is_authenticated(self): + return CallableTrue + + def get_username(self): + return self.username diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/serializers.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..3b90378d00d173ebe98852f1e0dea802b40522fb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/serializers.py @@ -0,0 +1,153 @@ +from django.contrib.auth import authenticate, get_user_model +from django.contrib.auth.models import update_last_login +from django.utils.translation import gettext_lazy as _ +from rest_framework import exceptions, serializers +from rest_framework.exceptions import ValidationError + +from .settings import api_settings +from .tokens import RefreshToken, SlidingToken, UntypedToken + +if api_settings.BLACKLIST_AFTER_ROTATION: + from .token_blacklist.models import BlacklistedToken + + +class PasswordField(serializers.CharField): + def __init__(self, *args, **kwargs): + kwargs.setdefault('style', {}) + + kwargs['style']['input_type'] = 'password' + kwargs['write_only'] = True + + super().__init__(*args, **kwargs) + + +class TokenObtainSerializer(serializers.Serializer): + username_field = get_user_model().USERNAME_FIELD + + default_error_messages = { + 'no_active_account': _('No active account found with the given credentials') + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.fields[self.username_field] = serializers.CharField() + self.fields['password'] = PasswordField() + + def validate(self, attrs): + authenticate_kwargs = { + self.username_field: attrs[self.username_field], + 'password': attrs['password'], + } + try: + authenticate_kwargs['request'] = self.context['request'] + except KeyError: + pass + + self.user = authenticate(**authenticate_kwargs) + + if not api_settings.USER_AUTHENTICATION_RULE(self.user): + raise exceptions.AuthenticationFailed( + self.error_messages['no_active_account'], + 'no_active_account', + ) + + return {} + + @classmethod + def get_token(cls, user): + raise NotImplementedError('Must implement `get_token` method for `TokenObtainSerializer` subclasses') + + +class TokenObtainPairSerializer(TokenObtainSerializer): + @classmethod + def get_token(cls, user): + return RefreshToken.for_user(user) + + def validate(self, attrs): + data = super().validate(attrs) + + refresh = self.get_token(self.user) + + data['refresh'] = str(refresh) + data['access'] = str(refresh.access_token) + + if api_settings.UPDATE_LAST_LOGIN: + update_last_login(None, self.user) + + return data + + +class TokenObtainSlidingSerializer(TokenObtainSerializer): + @classmethod + def get_token(cls, user): + return SlidingToken.for_user(user) + + def validate(self, attrs): + data = super().validate(attrs) + + token = self.get_token(self.user) + + data['token'] = str(token) + + if api_settings.UPDATE_LAST_LOGIN: + update_last_login(None, self.user) + + return data + + +class TokenRefreshSerializer(serializers.Serializer): + refresh = serializers.CharField() + access = serializers.ReadOnlyField() + + def validate(self, attrs): + refresh = RefreshToken(attrs['refresh']) + + data = {'access': str(refresh.access_token)} + + if api_settings.ROTATE_REFRESH_TOKENS: + if api_settings.BLACKLIST_AFTER_ROTATION: + try: + # Attempt to blacklist the given refresh token + refresh.blacklist() + except AttributeError: + # If blacklist app not installed, `blacklist` method will + # not be present + pass + + refresh.set_jti() + refresh.set_exp() + + data['refresh'] = str(refresh) + + return data + + +class TokenRefreshSlidingSerializer(serializers.Serializer): + token = serializers.CharField() + + def validate(self, attrs): + token = SlidingToken(attrs['token']) + + # Check that the timestamp in the "refresh_exp" claim has not + # passed + token.check_exp(api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM) + + # Update the "exp" claim + token.set_exp() + + return {'token': str(token)} + + +class TokenVerifySerializer(serializers.Serializer): + token = serializers.CharField() + + def validate(self, attrs): + token = UntypedToken(attrs['token']) + + if api_settings.BLACKLIST_AFTER_ROTATION: + jti = token.get(api_settings.JTI_CLAIM) + if BlacklistedToken.objects.filter(token__jti=jti).exists(): + raise ValidationError("Token is blacklisted") + + return {} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/settings.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..9cd790599a1dc8b9ce016e657d5795c7a3e7f8aa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/settings.py @@ -0,0 +1,84 @@ +from datetime import timedelta + +from django.conf import settings +from django.test.signals import setting_changed +from django.utils.translation import gettext_lazy as _ +from rest_framework.settings import APISettings as _APISettings + +from .utils import format_lazy + +USER_SETTINGS = getattr(settings, 'SIMPLE_JWT', None) + +DEFAULTS = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'ROTATE_REFRESH_TOKENS': False, + 'BLACKLIST_AFTER_ROTATION': True, + 'UPDATE_LAST_LOGIN': False, + + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': settings.SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + 'JWK_URL': None, + 'LEEWAY': 0, + + 'AUTH_HEADER_TYPES': ('Bearer',), + 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + + 'JTI_CLAIM': 'jti', + 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', + + 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', + 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5), + 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), +} + +IMPORT_STRINGS = ( + 'AUTH_TOKEN_CLASSES', + 'TOKEN_USER_CLASS', + 'USER_AUTHENTICATION_RULE', +) + +REMOVED_SETTINGS = ( + 'AUTH_HEADER_TYPE', + 'AUTH_TOKEN_CLASS', + 'SECRET_KEY', + 'TOKEN_BACKEND_CLASS', +) + + +class APISettings(_APISettings): # pragma: no cover + def __check_user_settings(self, user_settings): + SETTINGS_DOC = 'https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html' + + for setting in REMOVED_SETTINGS: + if setting in user_settings: + raise RuntimeError(format_lazy( + _("The '{}' setting has been removed. Please refer to '{}' for available settings."), + setting, SETTINGS_DOC, + )) + + return user_settings + + +api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS) + + +def reload_api_settings(*args, **kwargs): # pragma: no cover + global api_settings + + setting, value = kwargs['setting'], kwargs['value'] + + if setting == 'SIMPLE_JWT': + api_settings = APISettings(value, DEFAULTS, IMPORT_STRINGS) + + +setting_changed.connect(reload_api_settings) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/state.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/state.py new file mode 100644 index 0000000000000000000000000000000000000000..4fe94faef1c0ea2c974ac5cfdfacdc42459577c4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/state.py @@ -0,0 +1,12 @@ +from .backends import TokenBackend +from .settings import api_settings + +token_backend = TokenBackend( + api_settings.ALGORITHM, + api_settings.SIGNING_KEY, + api_settings.VERIFYING_KEY, + api_settings.AUDIENCE, + api_settings.ISSUER, + api_settings.JWK_URL, + api_settings.LEEWAY, +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..256a7774f9965a72dd2066a9628ef8e1708bbeaf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__init__.py @@ -0,0 +1,4 @@ +from django import VERSION + +if VERSION < (3, 2): + default_app_config = 'rest_framework_simplejwt.token_blacklist.apps.TokenBlacklistConfig' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3009f080884d52590e664860e4917a2f153a938a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/admin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63362b043a5b14554faec0b17e60e5c26e052199 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/admin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/apps.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cc8ed797aec31cb4fd2dce688859688ea9c6359 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/apps.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d68654a5341c2a9554880418417c6971dedbe7fb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/admin.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..7aa4c2f59fa8b23d3987996eefb6c057d36edf82 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/admin.py @@ -0,0 +1,91 @@ +from django.contrib import admin +from django.utils.translation import gettext_lazy as _ + +from .models import BlacklistedToken, OutstandingToken + + +class OutstandingTokenAdmin(admin.ModelAdmin): + list_display = ( + 'jti', + 'user', + 'created_at', + 'expires_at', + ) + search_fields = ( + 'user__id', + 'jti', + ) + ordering = ( + 'user', + ) + + def get_queryset(self, *args, **kwargs): + qs = super().get_queryset(*args, **kwargs) + + return qs.select_related('user') + + # Read-only behavior defined below + actions = None + + def get_readonly_fields(self, *args, **kwargs): + return [f.name for f in self.model._meta.fields] + + def has_add_permission(self, *args, **kwargs): + return False + + def has_delete_permission(self, *args, **kwargs): + return False + + def has_change_permission(self, request, obj=None): + return ( + request.method in ['GET', 'HEAD'] and # noqa: W504 + super().has_change_permission(request, obj) + ) + + +admin.site.register(OutstandingToken, OutstandingTokenAdmin) + + +class BlacklistedTokenAdmin(admin.ModelAdmin): + list_display = ( + 'token_jti', + 'token_user', + 'token_created_at', + 'token_expires_at', + 'blacklisted_at', + ) + search_fields = ( + 'token__user__id', + 'token__jti', + ) + ordering = ( + 'token__user', + ) + + def get_queryset(self, *args, **kwargs): + qs = super().get_queryset(*args, **kwargs) + + return qs.select_related('token__user') + + def token_jti(self, obj): + return obj.token.jti + token_jti.short_description = _('jti') + token_jti.admin_order_field = 'token__jti' + + def token_user(self, obj): + return obj.token.user + token_user.short_description = _('user') + token_user.admin_order_field = 'token__user' + + def token_created_at(self, obj): + return obj.token.created_at + token_created_at.short_description = _('created at') + token_created_at.admin_order_field = 'token__created_at' + + def token_expires_at(self, obj): + return obj.token.expires_at + token_expires_at.short_description = _('expires at') + token_expires_at.admin_order_field = 'token__expires_at' + + +admin.site.register(BlacklistedToken, BlacklistedTokenAdmin) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/apps.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..a30f9e3337c047575c278a675d998389510214eb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class TokenBlacklistConfig(AppConfig): + name = 'rest_framework_simplejwt.token_blacklist' + verbose_name = _('Token Blacklist') + default_auto_field = 'django.db.models.BigAutoField' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21a40e1534155532d0e7a6130ecd479cbe320e56 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0babbfba16e9966953a93c4ba2262a3c30af172e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/flushexpiredtokens.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/flushexpiredtokens.py new file mode 100644 index 0000000000000000000000000000000000000000..00e4d4f39e29133eccda031827bb9ce26570a6cc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/management/commands/flushexpiredtokens.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand + +from rest_framework_simplejwt.utils import aware_utcnow + +from ...models import OutstandingToken + + +class Command(BaseCommand): + help = 'Flushes any expired tokens in the outstanding token list' + + def handle(self, *args, **kwargs): + OutstandingToken.objects.filter(expires_at__lte=aware_utcnow()).delete() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0001_initial.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..d3a7b2af38836a537565f8806922885a239d5192 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0001_initial.py @@ -0,0 +1,41 @@ +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='BlacklistedToken', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('blacklisted_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='OutstandingToken', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('jti', models.UUIDField(unique=True)), + ('token', models.TextField()), + ('created_at', models.DateTimeField()), + ('expires_at', models.DateTimeField()), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('user',), + }, + ), + migrations.AddField( + model_name='blacklistedtoken', + name='token', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='token_blacklist.OutstandingToken'), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0002_outstandingtoken_jti_hex.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0002_outstandingtoken_jti_hex.py new file mode 100644 index 0000000000000000000000000000000000000000..d8af1641d0916dc91ffef2ce17618f5d80a2b4df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0002_outstandingtoken_jti_hex.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='outstandingtoken', + name='jti_hex', + field=models.CharField(blank=True, null=True, max_length=255), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0003_auto_20171017_2007.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0003_auto_20171017_2007.py new file mode 100644 index 0000000000000000000000000000000000000000..ab9d6f3d0440f90060ff2c8f2a5e791da6dd3d51 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0003_auto_20171017_2007.py @@ -0,0 +1,32 @@ +from uuid import UUID + +from django.db import migrations + + +def populate_jti_hex(apps, schema_editor): + OutstandingToken = apps.get_model('token_blacklist', 'OutstandingToken') + + db_alias = schema_editor.connection.alias + for token in OutstandingToken.objects.using(db_alias).all(): + token.jti_hex = token.jti.hex + token.save() + + +def reverse_populate_jti_hex(apps, schema_editor): # pragma: no cover + OutstandingToken = apps.get_model('token_blacklist', 'OutstandingToken') + + db_alias = schema_editor.connection.alias + for token in OutstandingToken.objects.using(db_alias).all(): + token.jti = UUID(hex=token.jti_hex) + token.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0002_outstandingtoken_jti_hex'), + ] + + operations = [ + migrations.RunPython(populate_jti_hex, reverse_populate_jti_hex), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0004_auto_20171017_2013.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0004_auto_20171017_2013.py new file mode 100644 index 0000000000000000000000000000000000000000..0ae3f17a301a49447c51b16eb8d4289c89cf679d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0004_auto_20171017_2013.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0003_auto_20171017_2007'), + ] + + operations = [ + migrations.AlterField( + model_name='outstandingtoken', + name='jti_hex', + field=models.CharField(unique=True, max_length=255), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0005_remove_outstandingtoken_jti.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0005_remove_outstandingtoken_jti.py new file mode 100644 index 0000000000000000000000000000000000000000..b261df77413a8958c322e5b98863083614f9d79f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0005_remove_outstandingtoken_jti.py @@ -0,0 +1,15 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0004_auto_20171017_2013'), + ] + + operations = [ + migrations.RemoveField( + model_name='outstandingtoken', + name='jti', + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0006_auto_20171017_2113.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0006_auto_20171017_2113.py new file mode 100644 index 0000000000000000000000000000000000000000..a6b77a867dc3db2ed8c5b1bbc047f70822a19eca --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0006_auto_20171017_2113.py @@ -0,0 +1,16 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0005_remove_outstandingtoken_jti'), + ] + + operations = [ + migrations.RenameField( + model_name='outstandingtoken', + old_name='jti_hex', + new_name='jti', + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0007_auto_20171017_2214.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0007_auto_20171017_2214.py new file mode 100644 index 0000000000000000000000000000000000000000..273d7111fa6ed7fe158e76e84dfcf54916466341 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0007_auto_20171017_2214.py @@ -0,0 +1,23 @@ +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0006_auto_20171017_2113'), + ] + + operations = [ + migrations.AlterField( + model_name='outstandingtoken', + name='created_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name='outstandingtoken', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0008_migrate_to_bigautofield.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0008_migrate_to_bigautofield.py new file mode 100644 index 0000000000000000000000000000000000000000..dd218d24d215fb8508cbb7e181259e42fe814c90 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0008_migrate_to_bigautofield.py @@ -0,0 +1,21 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0007_auto_20171017_2214'), + ] + + operations = [ + migrations.AlterField( + model_name='blacklistedtoken', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='outstandingtoken', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0010_fix_migrate_to_bigautofield.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0010_fix_migrate_to_bigautofield.py new file mode 100644 index 0000000000000000000000000000000000000000..e2ae85e9f88306742295eadf1e2a2d52f751c641 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0010_fix_migrate_to_bigautofield.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.3 on 2021-05-27 17:46 + +from pathlib import Path + +from django.db import migrations, models + +parent_dir = Path(__file__).resolve(strict=True).parent + + +class Migration(migrations.Migration): + + dependencies = [ + ('token_blacklist', '0008_migrate_to_bigautofield'), + ] + + operations = [ + migrations.AlterField( + model_name='blacklistedtoken', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='outstandingtoken', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0011_linearizes_history.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0011_linearizes_history.py new file mode 100644 index 0000000000000000000000000000000000000000..623c964be1f26058724558169c43fb84645fcfd7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/0011_linearizes_history.py @@ -0,0 +1,22 @@ +import fnmatch +import os +from pathlib import Path + +from django.db import migrations, models # noqa F401 + +parent_dir = Path(__file__).resolve(strict=True).parent + + +class Migration(migrations.Migration): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.dependencies = [ + ('token_blacklist', '0010_fix_migrate_to_bigautofield') + ] + _m = sorted(fnmatch.filter(os.listdir(parent_dir), "000*.py")) + if len(_m) == 9: + self.dependencies.insert(0, ('token_blacklist', os.path.splitext(_m[8])[0])) + + operations = [ + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/0001_initial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd70547d16f9a1767d3c7323930c900ba71c03b0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19b254f149fad50a5641fce84a60dc50a4484ba8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/models.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/models.py new file mode 100644 index 0000000000000000000000000000000000000000..e52d156410d8ec957757697fe93e44889bbee2b4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/token_blacklist/models.py @@ -0,0 +1,46 @@ +from django.conf import settings +from django.db import models + + +class OutstandingToken(models.Model): + id = models.BigAutoField(primary_key=True, serialize=False) + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True) + + jti = models.CharField(unique=True, max_length=255) + token = models.TextField() + + created_at = models.DateTimeField(null=True, blank=True) + expires_at = models.DateTimeField() + + class Meta: + # Work around for a bug in Django: + # https://code.djangoproject.com/ticket/19422 + # + # Also see corresponding ticket: + # https://github.com/encode/django-rest-framework/issues/705 + abstract = 'rest_framework_simplejwt.token_blacklist' not in settings.INSTALLED_APPS + ordering = ('user',) + + def __str__(self): + return 'Token for {} ({})'.format( + self.user, + self.jti, + ) + + +class BlacklistedToken(models.Model): + id = models.BigAutoField(primary_key=True, serialize=False) + token = models.OneToOneField(OutstandingToken, on_delete=models.CASCADE) + + blacklisted_at = models.DateTimeField(auto_now_add=True) + + class Meta: + # Work around for a bug in Django: + # https://code.djangoproject.com/ticket/19422 + # + # Also see corresponding ticket: + # https://github.com/encode/django-rest-framework/issues/705 + abstract = 'rest_framework_simplejwt.token_blacklist' not in settings.INSTALLED_APPS + + def __str__(self): + return 'Blacklisted token for {}'.format(self.token.user) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/tokens.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/tokens.py new file mode 100644 index 0000000000000000000000000000000000000000..46627a2f81f89d5fef56f5bb84a7f7b6a5a3845a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/tokens.py @@ -0,0 +1,312 @@ +from datetime import timedelta +from uuid import uuid4 + +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from django.utils.module_loading import import_string + +from .exceptions import TokenBackendError, TokenError +from .settings import api_settings +from .token_blacklist.models import BlacklistedToken, OutstandingToken +from .utils import ( + aware_utcnow, datetime_from_epoch, datetime_to_epoch, format_lazy, +) + + +class Token: + """ + A class which validates and wraps an existing JWT or can be used to build a + new JWT. + """ + token_type = None + lifetime = None + + def __init__(self, token=None, verify=True): + """ + !!!! IMPORTANT !!!! MUST raise a TokenError with a user-facing error + message if the given token is invalid, expired, or otherwise not safe + to use. + """ + if self.token_type is None or self.lifetime is None: + raise TokenError(_('Cannot create token with no type or lifetime')) + + self.token = token + self.current_time = aware_utcnow() + + # Set up token + if token is not None: + # An encoded token was provided + token_backend = self.get_token_backend() + + # Decode token + try: + self.payload = token_backend.decode(token, verify=verify) + except TokenBackendError: + raise TokenError(_('Token is invalid or expired')) + + if verify: + self.verify() + else: + # New token. Skip all the verification steps. + self.payload = {api_settings.TOKEN_TYPE_CLAIM: self.token_type} + + # Set "exp" claim with default value + self.set_exp(from_time=self.current_time, lifetime=self.lifetime) + + # Set "jti" claim + self.set_jti() + + def __repr__(self): + return repr(self.payload) + + def __getitem__(self, key): + return self.payload[key] + + def __setitem__(self, key, value): + self.payload[key] = value + + def __delitem__(self, key): + del self.payload[key] + + def __contains__(self, key): + return key in self.payload + + def get(self, key, default=None): + return self.payload.get(key, default) + + def __str__(self): + """ + Signs and returns a token as a base64 encoded string. + """ + return self.get_token_backend().encode(self.payload) + + def verify(self): + """ + Performs additional validation steps which were not performed when this + token was decoded. This method is part of the "public" API to indicate + the intention that it may be overridden in subclasses. + """ + # According to RFC 7519, the "exp" claim is OPTIONAL + # (https://tools.ietf.org/html/rfc7519#section-4.1.4). As a more + # correct behavior for authorization tokens, we require an "exp" + # claim. We don't want any zombie tokens walking around. + self.check_exp() + + # Ensure token id is present + if api_settings.JTI_CLAIM not in self.payload: + raise TokenError(_('Token has no id')) + + self.verify_token_type() + + def verify_token_type(self): + """ + Ensures that the token type claim is present and has the correct value. + """ + try: + token_type = self.payload[api_settings.TOKEN_TYPE_CLAIM] + except KeyError: + raise TokenError(_('Token has no type')) + + if self.token_type != token_type: + raise TokenError(_('Token has wrong type')) + + def set_jti(self): + """ + Populates the configured jti claim of a token with a string where there + is a negligible probability that the same string will be chosen at a + later time. + + See here: + https://tools.ietf.org/html/rfc7519#section-4.1.7 + """ + self.payload[api_settings.JTI_CLAIM] = uuid4().hex + + def set_exp(self, claim='exp', from_time=None, lifetime=None): + """ + Updates the expiration time of a token. + """ + if from_time is None: + from_time = self.current_time + + if lifetime is None: + lifetime = self.lifetime + + self.payload[claim] = datetime_to_epoch(from_time + lifetime) + + def check_exp(self, claim='exp', current_time=None): + """ + Checks whether a timestamp value in the given claim has passed (since + the given datetime value in `current_time`). Raises a TokenError with + a user-facing error message if so. + """ + if current_time is None: + current_time = self.current_time + + try: + claim_value = self.payload[claim] + except KeyError: + raise TokenError(format_lazy(_("Token has no '{}' claim"), claim)) + + claim_time = datetime_from_epoch(claim_value) + if claim_time <= current_time: + raise TokenError(format_lazy(_("Token '{}' claim has expired"), claim)) + + @classmethod + def for_user(cls, user): + """ + Returns an authorization token for the given user that will be provided + after authenticating the user's credentials. + """ + user_id = getattr(user, api_settings.USER_ID_FIELD) + if not isinstance(user_id, int): + user_id = str(user_id) + + token = cls() + token[api_settings.USER_ID_CLAIM] = user_id + + return token + + _token_backend = None + + def get_token_backend(self): + if self._token_backend is None: + self._token_backend = import_string( + "rest_framework_simplejwt.state.token_backend" + ) + return self._token_backend + + +class BlacklistMixin: + """ + If the `rest_framework_simplejwt.token_blacklist` app was configured to be + used, tokens created from `BlacklistMixin` subclasses will insert + themselves into an outstanding token list and also check for their + membership in a token blacklist. + """ + if 'rest_framework_simplejwt.token_blacklist' in settings.INSTALLED_APPS: + def verify(self, *args, **kwargs): + self.check_blacklist() + + super().verify(*args, **kwargs) + + def check_blacklist(self): + """ + Checks if this token is present in the token blacklist. Raises + `TokenError` if so. + """ + jti = self.payload[api_settings.JTI_CLAIM] + + if BlacklistedToken.objects.filter(token__jti=jti).exists(): + raise TokenError(_('Token is blacklisted')) + + def blacklist(self): + """ + Ensures this token is included in the outstanding token list and + adds it to the blacklist. + """ + jti = self.payload[api_settings.JTI_CLAIM] + exp = self.payload['exp'] + + # Ensure outstanding token exists with given jti + token, _ = OutstandingToken.objects.get_or_create( + jti=jti, + defaults={ + 'token': str(self), + 'expires_at': datetime_from_epoch(exp), + }, + ) + + return BlacklistedToken.objects.get_or_create(token=token) + + @classmethod + def for_user(cls, user): + """ + Adds this token to the outstanding token list. + """ + token = super().for_user(user) + + jti = token[api_settings.JTI_CLAIM] + exp = token['exp'] + + OutstandingToken.objects.create( + user=user, + jti=jti, + token=str(token), + created_at=token.current_time, + expires_at=datetime_from_epoch(exp), + ) + + return token + + +class SlidingToken(BlacklistMixin, Token): + token_type = 'sliding' + lifetime = api_settings.SLIDING_TOKEN_LIFETIME + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if self.token is None: + # Set sliding refresh expiration claim if new token + self.set_exp( + api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM, + from_time=self.current_time, + lifetime=api_settings.SLIDING_TOKEN_REFRESH_LIFETIME, + ) + + +class RefreshToken(BlacklistMixin, Token): + token_type = 'refresh' + lifetime = api_settings.REFRESH_TOKEN_LIFETIME + no_copy_claims = ( + api_settings.TOKEN_TYPE_CLAIM, + 'exp', + + # Both of these claims are included even though they may be the same. + # It seems possible that a third party token might have a custom or + # namespaced JTI claim as well as a default "jti" claim. In that case, + # we wouldn't want to copy either one. + api_settings.JTI_CLAIM, + 'jti', + ) + + @property + def access_token(self): + """ + Returns an access token created from this refresh token. Copies all + claims present in this refresh token to the new access token except + those claims listed in the `no_copy_claims` attribute. + """ + access = AccessToken() + + # Use instantiation time of refresh token as relative timestamp for + # access token "exp" claim. This ensures that both a refresh and + # access token expire relative to the same time if they are created as + # a pair. + access.set_exp(from_time=self.current_time) + + no_copy = self.no_copy_claims + for claim, value in self.payload.items(): + if claim in no_copy: + continue + access[claim] = value + + return access + + +class AccessToken(Token): + token_type = 'access' + lifetime = api_settings.ACCESS_TOKEN_LIFETIME + + +class UntypedToken(Token): + token_type = 'untyped' + lifetime = timedelta(seconds=0) + + def verify_token_type(self): + """ + Untyped tokens do not verify the "token_type" claim. This is useful + when performing general validation of a token's signature and other + properties which do not relate to the token's intended use. + """ + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..48e950ad65861b494a5fcafa863ce921ae489424 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/utils.py @@ -0,0 +1,32 @@ +from calendar import timegm +from datetime import datetime + +from django.conf import settings +from django.utils.functional import lazy +from django.utils.timezone import is_naive, make_aware, utc + + +def make_utc(dt): + if settings.USE_TZ and is_naive(dt): + return make_aware(dt, timezone=utc) + + return dt + + +def aware_utcnow(): + return make_utc(datetime.utcnow()) + + +def datetime_to_epoch(dt): + return timegm(dt.utctimetuple()) + + +def datetime_from_epoch(ts): + return make_utc(datetime.utcfromtimestamp(ts)) + + +def format_lazy(s, *args, **kwargs): + return s.format(*args, **kwargs) + + +format_lazy = lazy(format_lazy, str) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/views.py b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/views.py new file mode 100644 index 0000000000000000000000000000000000000000..fec1edcac4223838562320ff8e34197f69d60a05 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/rest_framework_simplejwt/views.py @@ -0,0 +1,86 @@ +from rest_framework import generics, status +from rest_framework.response import Response + +from . import serializers +from .authentication import AUTH_HEADER_TYPES +from .exceptions import InvalidToken, TokenError + + +class TokenViewBase(generics.GenericAPIView): + permission_classes = () + authentication_classes = () + + serializer_class = None + + www_authenticate_realm = 'api' + + def get_authenticate_header(self, request): + return '{0} realm="{1}"'.format( + AUTH_HEADER_TYPES[0], + self.www_authenticate_realm, + ) + + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + + try: + serializer.is_valid(raise_exception=True) + except TokenError as e: + raise InvalidToken(e.args[0]) + + return Response(serializer.validated_data, status=status.HTTP_200_OK) + + +class TokenObtainPairView(TokenViewBase): + """ + Takes a set of user credentials and returns an access and refresh JSON web + token pair to prove the authentication of those credentials. + """ + serializer_class = serializers.TokenObtainPairSerializer + + +token_obtain_pair = TokenObtainPairView.as_view() + + +class TokenRefreshView(TokenViewBase): + """ + Takes a refresh type JSON web token and returns an access type JSON web + token if the refresh token is valid. + """ + serializer_class = serializers.TokenRefreshSerializer + + +token_refresh = TokenRefreshView.as_view() + + +class TokenObtainSlidingView(TokenViewBase): + """ + Takes a set of user credentials and returns a sliding JSON web token to + prove the authentication of those credentials. + """ + serializer_class = serializers.TokenObtainSlidingSerializer + + +token_obtain_sliding = TokenObtainSlidingView.as_view() + + +class TokenRefreshSlidingView(TokenViewBase): + """ + Takes a sliding JSON web token and returns a new, refreshed version if the + token's refresh period has not expired. + """ + serializer_class = serializers.TokenRefreshSlidingSerializer + + +token_refresh_sliding = TokenRefreshSlidingView.as_view() + + +class TokenVerifyView(TokenViewBase): + """ + Takes a token and indicates if it is valid. This view provides no + information about a token's fitness for a particular use. + """ + serializer_class = serializers.TokenVerifySerializer + + +token_verify = TokenVerifyView.as_view() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..796a37a54f3fc37e2c245f5aa3a5787c321a67ac --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012-2016, Matías Aguirre +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..1b10e94173aa53cca687bea5486e34c93bec25f8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/METADATA @@ -0,0 +1,76 @@ +Metadata-Version: 2.1 +Name: social-auth-app-django +Version: 4.0.0 +Summary: Python Social Authentication, Django integration. +Home-page: https://github.com/python-social-auth/social-app-django +Author: Matias Aguirre +Author-email: matiasaguirre@gmail.com +License: BSD +Keywords: django,social auth +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Topic :: Internet +Classifier: License :: OSI Approved :: BSD License +Classifier: Intended Audience :: Developers +Classifier: Environment :: Web Environment +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Description-Content-Type: text/markdown +Requires-Dist: six +Requires-Dist: social-auth-core (>=3.3.0) + +# Python Social Auth - Django + +[](https://travis-ci.org/python-social-auth/social-app-django) +[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=matiasaguirre%40gmail%2ecom&lc=US&item_name=Python%20Social%20Auth&no_note=0¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHostedGuest) +[](https://badge.fury.io/py/social-auth-app-django) + +Python Social Auth is an easy to setup social authentication/registration +mechanism with support for several frameworks and auth providers. + +## Description + +This is the [Django](https://www.djangoproject.com/) component of the +[python-social-auth ecosystem](https://github.com/python-social-auth/social-core), +it implements the needed functionality to integrate +[social-auth-core](https://github.com/python-social-auth/social-core) +in a Django based project. + +## Django version + +This project will focus on the currently supported Django releases as +stated on the [Django Project Supported Versions table](https://www.djangoproject.com/download/#supported-versions). + +Backward compatibility with unsupported versions won't be enforced. + +## Documentation + +Project documentation is available at http://python-social-auth.readthedocs.org/. + +## Setup + +```shell +$ pip install social-auth-app-django +``` + +## Contributing + +See the [CONTRIBUTING.md](CONTRIBUTING.md) document for details. + +## Versioning + +This project follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html). + +## License + +This project follows the BSD license. See the [LICENSE](LICENSE) for details. + +## Donations + +This project is maintained on my spare time, consider donating to keep +it improving. + +[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=matiasaguirre%40gmail%2ecom&lc=US&item_name=Python%20Social%20Auth&no_note=0¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHostedGuest) + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..754e182e6746ea15f9eefbd7eaa3f18548f569f0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/RECORD @@ -0,0 +1,62 @@ +social_auth_app_django-4.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +social_auth_app_django-4.0.0.dist-info/LICENSE,sha256=JRBrhWp-z5cdXIo8qCoVw628hhPS-avnXnj3lCDc6zY,1529 +social_auth_app_django-4.0.0.dist-info/METADATA,sha256=v-A-HwZ23nG4si5yme1Zw_Fs5RcmZUI_-7AtMRuKDVM,2919 +social_auth_app_django-4.0.0.dist-info/RECORD,, +social_auth_app_django-4.0.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +social_auth_app_django-4.0.0.dist-info/top_level.txt,sha256=8t6G3xz_UTQ6eV8mCJ3VHJ7AC9jJeykRbymQ_GLLKWI,14 +social_django/__init__.py,sha256=9fJ6Mp-HNKnbNL9SEw9EMyl-dBPdHNk-8Mdzo_kMSjY,801 +social_django/__pycache__/__init__.cpython-310.pyc,, +social_django/__pycache__/admin.cpython-310.pyc,, +social_django/__pycache__/compat.cpython-310.pyc,, +social_django/__pycache__/config.cpython-310.pyc,, +social_django/__pycache__/context_processors.cpython-310.pyc,, +social_django/__pycache__/fields.cpython-310.pyc,, +social_django/__pycache__/managers.cpython-310.pyc,, +social_django/__pycache__/middleware.cpython-310.pyc,, +social_django/__pycache__/models.cpython-310.pyc,, +social_django/__pycache__/storage.cpython-310.pyc,, +social_django/__pycache__/strategy.cpython-310.pyc,, +social_django/__pycache__/urls.cpython-310.pyc,, +social_django/__pycache__/utils.cpython-310.pyc,, +social_django/__pycache__/views.cpython-310.pyc,, +social_django/admin.py,sha256=Z5NYwI8Q4VFObuuqZNtZm3aFWs3RXU8PgnbRBjJFl1Y,2231 +social_django/compat.py,sha256=mTa9GR5-z2Gax1uVOlnmed-OCqvdm9YcqPQfFnGNtcE,819 +social_django/config.py,sha256=CT_ydYB_LPsj8GbZ4d0YCx_52n_z7PnD4-TRrha2w7s,373 +social_django/context_processors.py,sha256=N4vl3hRAsruZSAR-xBLn9aSRrur1K9UKIwM9Hg_GOls,1635 +social_django/fields.py,sha256=UwKJ4bEMchQuWm-CjDL8dHfwjy63QKf5LpkkR8ZzkZw,2355 +social_django/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_django/management/__pycache__/__init__.cpython-310.pyc,, +social_django/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_django/management/commands/__pycache__/__init__.cpython-310.pyc,, +social_django/management/commands/__pycache__/clearsocial.cpython-310.pyc,, +social_django/management/commands/clearsocial.py,sha256=VDjjYf4fbubzZ0LtE3XCDz__O5cecTZWhSN4cIUcUJs,949 +social_django/managers.py,sha256=l_Z4TW9pP8nPGw-cuHobqCqdS70JD7-JXt4XvJSK-f8,438 +social_django/middleware.py,sha256=48eQ6JkO24XciQzlUbZThYZvBiOyOk2hj2evb8XCggY,2591 +social_django/migrations/0001_initial.py,sha256=lrbW2wxvNtHIONMYF_-Wl3TgtH827PhfTt3plUT2xTQ,4369 +social_django/migrations/0002_add_related_name.py,sha256=SnjW14Shrp2YYaaJY5M1EAlje2Z3cdKVHskueTBxuog,840 +social_django/migrations/0003_alter_email_max_length.py,sha256=LdjLzwdMtcAfLIJrcj_EyJ0StgFfXt8zUtsCq0LPIRU,690 +social_django/migrations/0004_auto_20160423_0400.py,sha256=vZkKyquq8Ut15kV3qn7503Tcs2SMTS5lYYXDo0I0k-U,569 +social_django/migrations/0005_auto_20160727_2333.py,sha256=q9NSyIEWxveJtAsKRiCQO_TVbVLBa7p9CORq_Ld9boo,513 +social_django/migrations/0006_partial.py,sha256=cgFmo1RBe9eW2tUbggF4JyOiIIN7iRrd5aELRuFmpAQ,1032 +social_django/migrations/0007_code_timestamp.py,sha256=199XJmySQhJbHWFNHrwyaGJgS6uAiOyEp3pOqmCMMC4,637 +social_django/migrations/0008_partial_timestamp.py,sha256=ajODqXdxPZBjDUCY7EQ5On3GGRS4G3mbolWC81mHihU,648 +social_django/migrations/0009_auto_20191118_0520.py,sha256=8_TAo39nmhRu4nkuksCdNa71fc4tOvmj9-UIPsKNnTM,671 +social_django/migrations/0010_uid_db_index.py,sha256=-m6ZiCl_Do-c6jnhJS54wi7VW156QFeabbS6ot0poGg,577 +social_django/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_django/migrations/__pycache__/0001_initial.cpython-310.pyc,, +social_django/migrations/__pycache__/0002_add_related_name.cpython-310.pyc,, +social_django/migrations/__pycache__/0003_alter_email_max_length.cpython-310.pyc,, +social_django/migrations/__pycache__/0004_auto_20160423_0400.cpython-310.pyc,, +social_django/migrations/__pycache__/0005_auto_20160727_2333.cpython-310.pyc,, +social_django/migrations/__pycache__/0006_partial.cpython-310.pyc,, +social_django/migrations/__pycache__/0007_code_timestamp.cpython-310.pyc,, +social_django/migrations/__pycache__/0008_partial_timestamp.cpython-310.pyc,, +social_django/migrations/__pycache__/0009_auto_20191118_0520.cpython-310.pyc,, +social_django/migrations/__pycache__/0010_uid_db_index.cpython-310.pyc,, +social_django/migrations/__pycache__/__init__.cpython-310.pyc,, +social_django/models.py,sha256=mti20d2w0ienEn66b82famcpuaM6QRePsrmr763YUkY,4674 +social_django/storage.py,sha256=kEhIr78W5ioA1tUgr9LnmF0x1L7zljBM3ujI6Xb1q9I,7737 +social_django/strategy.py,sha256=9qGyAOHzTi50s1KOVBbmHVeKyfWIfzh5hylP_nc6n4g,5438 +social_django/urls.py,sha256=sQGqyarF4c868gmtKos5brdY9WiypvR_f1f7wj5BvTI,765 +social_django/utils.py,sha256=tmJZji4tkA7XccoN1Z3R1YfJIUz-2Z3Vr4Bx-viEpAQ,1779 +social_django/views.py,sha256=w7Y64hlq4fRKP4wmEjKU7-hAIpENcosX8BhK6XKxm3A,5650 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..b552003ff90e66227ec90d1b159324f140d46001 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bfdf7e83a9d1af93fb92c00ee58a2b1a52a9321 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_app_django-4.0.0.dist-info/top_level.txt @@ -0,0 +1 @@ +social_django diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..796a37a54f3fc37e2c245f5aa3a5787c321a67ac --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012-2016, Matías Aguirre +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..ae10f27f8bc20892c4e8c825213193dd80d5838e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/METADATA @@ -0,0 +1,102 @@ +Metadata-Version: 2.1 +Name: social-auth-core +Version: 4.4.0 +Summary: Python social authentication made simple. +Home-page: https://github.com/python-social-auth/social-core +Author: Matias Aguirre +Author-email: matiasaguirre@gmail.com +License: BSD +Keywords: openid,oauth,saml,social auth +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Topic :: Internet +Classifier: License :: OSI Approved :: BSD License +Classifier: Intended Audience :: Developers +Classifier: Environment :: Web Environment +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: requests (>=2.9.1) +Requires-Dist: oauthlib (>=1.0.3) +Requires-Dist: requests-oauthlib (>=0.6.1) +Requires-Dist: PyJWT (>=2.0.0) +Requires-Dist: cryptography (>=1.4) +Requires-Dist: defusedxml (>=0.5.0rc1) +Requires-Dist: python3-openid (>=3.0.10) +Provides-Extra: all +Requires-Dist: python-jose (>=3.0.0) ; extra == 'all' +Requires-Dist: python3-saml (>=1.5.0) ; extra == 'all' +Requires-Dist: cryptography (>=2.1.1) ; extra == 'all' +Provides-Extra: allpy3 +Requires-Dist: python-jose (>=3.0.0) ; extra == 'allpy3' +Requires-Dist: python3-saml (>=1.5.0) ; extra == 'allpy3' +Requires-Dist: cryptography (>=2.1.1) ; extra == 'allpy3' +Provides-Extra: azuread +Requires-Dist: cryptography (>=2.1.1) ; extra == 'azuread' +Provides-Extra: openidconnect +Requires-Dist: python-jose (>=3.0.0) ; extra == 'openidconnect' +Provides-Extra: saml +Requires-Dist: python3-saml (>=1.5.0) ; extra == 'saml' + +> ## THIS PROJECT IS OPEN FOR MAINTAINERS +> Development on the python-social-auth projects has been stagnated for a while, +> #445 was open a long time ago to discuss this matter and a plan (failed) was +> presented to fix the situation. For that reason, I'm opening the organization to +> new maintainers that will have the proper permissions to unstuck development. +> +> Those willing to join, contact me by email with the subject `[PSA Maintainer] +> <your name>` and please let me know what motivates you to join in such role. + +# Python Social Auth - Core + + +[](https://travis-ci.org/python-social-auth/social-core) +[](https://badge.fury.io/py/social-auth-core) +[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=matiasaguirre%40gmail%2ecom&lc=US&item_name=Python%20Social%20Auth&no_note=0¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHostedGuest) + +Python Social Auth is an easy to setup social authentication/registration +mechanism with support for several frameworks and auth providers. + +## Description + +This is the core component of the python-social-auth ecosystem, it +implements the common interface to define new authentication backends +to third parties services, implement integrations with web frameworks +and storage solutions. + +## Documentation + +Project documentation is available at http://python-social-auth.readthedocs.org/. + +## Setup + +```shell +$ pip install social-auth-core +``` + +## Contributing + +See the [CONTRIBUTING.md](CONTRIBUTING.md) document for details. + +## Versioning + +This project follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html). + +## License + +This project follows the BSD license. See the [LICENSE](LICENSE) for details. + +## Donations + +This project is maintained on my spare time, consider donating to keep +it improving. + +[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=matiasaguirre%40gmail%2ecom&lc=US&item_name=Python%20Social%20Auth&no_note=0¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHostedGuest) + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..ab1bb587fb235b8526b398c904ff2b49206d40bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/RECORD @@ -0,0 +1,668 @@ +social_auth_core-4.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +social_auth_core-4.4.0.dist-info/LICENSE,sha256=JRBrhWp-z5cdXIo8qCoVw628hhPS-avnXnj3lCDc6zY,1529 +social_auth_core-4.4.0.dist-info/METADATA,sha256=0iaLmHFJxSoINQUu7zHtCPSGJ2FktUFw0mpO26ZB0Zc,4269 +social_auth_core-4.4.0.dist-info/RECORD,, +social_auth_core-4.4.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +social_auth_core-4.4.0.dist-info/top_level.txt,sha256=CuEK6eKXcMTo6BpFhFEZetBiCqD8OjooJ-Hrr_MjUDE,12 +social_core/__init__.py,sha256=ZMEVsrDCFAaWRcxycPFTA5eXcNSdnxmLtUHTvt__4Tg,22 +social_core/__pycache__/__init__.cpython-310.pyc,, +social_core/__pycache__/actions.cpython-310.pyc,, +social_core/__pycache__/exceptions.cpython-310.pyc,, +social_core/__pycache__/storage.cpython-310.pyc,, +social_core/__pycache__/store.cpython-310.pyc,, +social_core/__pycache__/strategy.cpython-310.pyc,, +social_core/__pycache__/utils.cpython-310.pyc,, +social_core/actions.py,sha256=I1TqdsuDaw3f8tPHeJ0oCr2qhfXCKl4Odsj-HNCffYs,5565 +social_core/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_core/backends/__pycache__/__init__.cpython-310.pyc,, +social_core/backends/__pycache__/amazon.cpython-310.pyc,, +social_core/backends/__pycache__/angel.cpython-310.pyc,, +social_core/backends/__pycache__/aol.cpython-310.pyc,, +social_core/backends/__pycache__/apple.cpython-310.pyc,, +social_core/backends/__pycache__/appsfuel.cpython-310.pyc,, +social_core/backends/__pycache__/arcgis.cpython-310.pyc,, +social_core/backends/__pycache__/asana.cpython-310.pyc,, +social_core/backends/__pycache__/atlassian.cpython-310.pyc,, +social_core/backends/__pycache__/auth0.cpython-310.pyc,, +social_core/backends/__pycache__/azuread.cpython-310.pyc,, +social_core/backends/__pycache__/azuread_b2c.cpython-310.pyc,, +social_core/backends/__pycache__/azuread_tenant.cpython-310.pyc,, +social_core/backends/__pycache__/base.cpython-310.pyc,, +social_core/backends/__pycache__/battlenet.cpython-310.pyc,, +social_core/backends/__pycache__/beats.cpython-310.pyc,, +social_core/backends/__pycache__/behance.cpython-310.pyc,, +social_core/backends/__pycache__/belgiumeid.cpython-310.pyc,, +social_core/backends/__pycache__/bitbucket.cpython-310.pyc,, +social_core/backends/__pycache__/box.cpython-310.pyc,, +social_core/backends/__pycache__/bungie.cpython-310.pyc,, +social_core/backends/__pycache__/changetip.cpython-310.pyc,, +social_core/backends/__pycache__/chatwork.cpython-310.pyc,, +social_core/backends/__pycache__/cilogon.cpython-310.pyc,, +social_core/backends/__pycache__/classlink.cpython-310.pyc,, +social_core/backends/__pycache__/clef.cpython-310.pyc,, +social_core/backends/__pycache__/coding.cpython-310.pyc,, +social_core/backends/__pycache__/cognito.cpython-310.pyc,, +social_core/backends/__pycache__/coinbase.cpython-310.pyc,, +social_core/backends/__pycache__/coursera.cpython-310.pyc,, +social_core/backends/__pycache__/dailymotion.cpython-310.pyc,, +social_core/backends/__pycache__/deezer.cpython-310.pyc,, +social_core/backends/__pycache__/digitalocean.cpython-310.pyc,, +social_core/backends/__pycache__/discord.cpython-310.pyc,, +social_core/backends/__pycache__/discourse.cpython-310.pyc,, +social_core/backends/__pycache__/disqus.cpython-310.pyc,, +social_core/backends/__pycache__/docker.cpython-310.pyc,, +social_core/backends/__pycache__/douban.cpython-310.pyc,, +social_core/backends/__pycache__/dribbble.cpython-310.pyc,, +social_core/backends/__pycache__/drip.cpython-310.pyc,, +social_core/backends/__pycache__/dropbox.cpython-310.pyc,, +social_core/backends/__pycache__/echosign.cpython-310.pyc,, +social_core/backends/__pycache__/edmodo.cpython-310.pyc,, +social_core/backends/__pycache__/elixir.cpython-310.pyc,, +social_core/backends/__pycache__/email.cpython-310.pyc,, +social_core/backends/__pycache__/eventbrite.cpython-310.pyc,, +social_core/backends/__pycache__/eveonline.cpython-310.pyc,, +social_core/backends/__pycache__/evernote.cpython-310.pyc,, +social_core/backends/__pycache__/exacttarget.cpython-310.pyc,, +social_core/backends/__pycache__/facebook.cpython-310.pyc,, +social_core/backends/__pycache__/fedora.cpython-310.pyc,, +social_core/backends/__pycache__/fence.cpython-310.pyc,, +social_core/backends/__pycache__/fitbit.cpython-310.pyc,, +social_core/backends/__pycache__/five_hundred_px.cpython-310.pyc,, +social_core/backends/__pycache__/flat.cpython-310.pyc,, +social_core/backends/__pycache__/flickr.cpython-310.pyc,, +social_core/backends/__pycache__/foursquare.cpython-310.pyc,, +social_core/backends/__pycache__/gae.cpython-310.pyc,, +social_core/backends/__pycache__/gitea.cpython-310.pyc,, +social_core/backends/__pycache__/github.cpython-310.pyc,, +social_core/backends/__pycache__/github_enterprise.cpython-310.pyc,, +social_core/backends/__pycache__/gitlab.cpython-310.pyc,, +social_core/backends/__pycache__/globus.cpython-310.pyc,, +social_core/backends/__pycache__/goclio.cpython-310.pyc,, +social_core/backends/__pycache__/goclioeu.cpython-310.pyc,, +social_core/backends/__pycache__/google.cpython-310.pyc,, +social_core/backends/__pycache__/google_openidconnect.cpython-310.pyc,, +social_core/backends/__pycache__/grafana.cpython-310.pyc,, +social_core/backends/__pycache__/hubspot.cpython-310.pyc,, +social_core/backends/__pycache__/instagram.cpython-310.pyc,, +social_core/backends/__pycache__/itembase.cpython-310.pyc,, +social_core/backends/__pycache__/jawbone.cpython-310.pyc,, +social_core/backends/__pycache__/justgiving.cpython-310.pyc,, +social_core/backends/__pycache__/kakao.cpython-310.pyc,, +social_core/backends/__pycache__/keycloak.cpython-310.pyc,, +social_core/backends/__pycache__/khanacademy.cpython-310.pyc,, +social_core/backends/__pycache__/lastfm.cpython-310.pyc,, +social_core/backends/__pycache__/launchpad.cpython-310.pyc,, +social_core/backends/__pycache__/legacy.cpython-310.pyc,, +social_core/backends/__pycache__/line.cpython-310.pyc,, +social_core/backends/__pycache__/linkedin.cpython-310.pyc,, +social_core/backends/__pycache__/live.cpython-310.pyc,, +social_core/backends/__pycache__/livejournal.cpython-310.pyc,, +social_core/backends/__pycache__/loginradius.cpython-310.pyc,, +social_core/backends/__pycache__/lyft.cpython-310.pyc,, +social_core/backends/__pycache__/mailchimp.cpython-310.pyc,, +social_core/backends/__pycache__/mailru.cpython-310.pyc,, +social_core/backends/__pycache__/mapmyfitness.cpython-310.pyc,, +social_core/backends/__pycache__/mediawiki.cpython-310.pyc,, +social_core/backends/__pycache__/meetup.cpython-310.pyc,, +social_core/backends/__pycache__/mendeley.cpython-310.pyc,, +social_core/backends/__pycache__/microsoft.cpython-310.pyc,, +social_core/backends/__pycache__/mineid.cpython-310.pyc,, +social_core/backends/__pycache__/mixcloud.cpython-310.pyc,, +social_core/backends/__pycache__/monzo.cpython-310.pyc,, +social_core/backends/__pycache__/moves.cpython-310.pyc,, +social_core/backends/__pycache__/musicbrainz.cpython-310.pyc,, +social_core/backends/__pycache__/nationbuilder.cpython-310.pyc,, +social_core/backends/__pycache__/naver.cpython-310.pyc,, +social_core/backends/__pycache__/ngpvan.cpython-310.pyc,, +social_core/backends/__pycache__/nk.cpython-310.pyc,, +social_core/backends/__pycache__/oauth.cpython-310.pyc,, +social_core/backends/__pycache__/odnoklassniki.cpython-310.pyc,, +social_core/backends/__pycache__/okta.cpython-310.pyc,, +social_core/backends/__pycache__/okta_openidconnect.cpython-310.pyc,, +social_core/backends/__pycache__/open_id.cpython-310.pyc,, +social_core/backends/__pycache__/open_id_connect.cpython-310.pyc,, +social_core/backends/__pycache__/openinfra.cpython-310.pyc,, +social_core/backends/__pycache__/openshift.cpython-310.pyc,, +social_core/backends/__pycache__/openstack.cpython-310.pyc,, +social_core/backends/__pycache__/openstreetmap.cpython-310.pyc,, +social_core/backends/__pycache__/orbi.cpython-310.pyc,, +social_core/backends/__pycache__/orcid.cpython-310.pyc,, +social_core/backends/__pycache__/osso.cpython-310.pyc,, +social_core/backends/__pycache__/patreon.cpython-310.pyc,, +social_core/backends/__pycache__/paypal.cpython-310.pyc,, +social_core/backends/__pycache__/persona.cpython-310.pyc,, +social_core/backends/__pycache__/phabricator.cpython-310.pyc,, +social_core/backends/__pycache__/pinterest.cpython-310.pyc,, +social_core/backends/__pycache__/pixelpin.cpython-310.pyc,, +social_core/backends/__pycache__/pocket.cpython-310.pyc,, +social_core/backends/__pycache__/podio.cpython-310.pyc,, +social_core/backends/__pycache__/professionali.cpython-310.pyc,, +social_core/backends/__pycache__/pushbullet.cpython-310.pyc,, +social_core/backends/__pycache__/qiita.cpython-310.pyc,, +social_core/backends/__pycache__/qq.cpython-310.pyc,, +social_core/backends/__pycache__/quizlet.cpython-310.pyc,, +social_core/backends/__pycache__/rdio.cpython-310.pyc,, +social_core/backends/__pycache__/readability.cpython-310.pyc,, +social_core/backends/__pycache__/reddit.cpython-310.pyc,, +social_core/backends/__pycache__/runkeeper.cpython-310.pyc,, +social_core/backends/__pycache__/salesforce.cpython-310.pyc,, +social_core/backends/__pycache__/saml.cpython-310.pyc,, +social_core/backends/__pycache__/scistarter.cpython-310.pyc,, +social_core/backends/__pycache__/seznam.cpython-310.pyc,, +social_core/backends/__pycache__/shimmering.cpython-310.pyc,, +social_core/backends/__pycache__/shopify.cpython-310.pyc,, +social_core/backends/__pycache__/simplelogin.cpython-310.pyc,, +social_core/backends/__pycache__/sketchfab.cpython-310.pyc,, +social_core/backends/__pycache__/skyrock.cpython-310.pyc,, +social_core/backends/__pycache__/slack.cpython-310.pyc,, +social_core/backends/__pycache__/soundcloud.cpython-310.pyc,, +social_core/backends/__pycache__/spotify.cpython-310.pyc,, +social_core/backends/__pycache__/stackoverflow.cpython-310.pyc,, +social_core/backends/__pycache__/steam.cpython-310.pyc,, +social_core/backends/__pycache__/stocktwits.cpython-310.pyc,, +social_core/backends/__pycache__/strava.cpython-310.pyc,, +social_core/backends/__pycache__/stripe.cpython-310.pyc,, +social_core/backends/__pycache__/surveymonkey.cpython-310.pyc,, +social_core/backends/__pycache__/suse.cpython-310.pyc,, +social_core/backends/__pycache__/taobao.cpython-310.pyc,, +social_core/backends/__pycache__/telegram.cpython-310.pyc,, +social_core/backends/__pycache__/thisismyjam.cpython-310.pyc,, +social_core/backends/__pycache__/trello.cpython-310.pyc,, +social_core/backends/__pycache__/tripit.cpython-310.pyc,, +social_core/backends/__pycache__/tumblr.cpython-310.pyc,, +social_core/backends/__pycache__/twilio.cpython-310.pyc,, +social_core/backends/__pycache__/twitch.cpython-310.pyc,, +social_core/backends/__pycache__/twitter.cpython-310.pyc,, +social_core/backends/__pycache__/uber.cpython-310.pyc,, +social_core/backends/__pycache__/ubuntu.cpython-310.pyc,, +social_core/backends/__pycache__/udata.cpython-310.pyc,, +social_core/backends/__pycache__/universe.cpython-310.pyc,, +social_core/backends/__pycache__/untappd.cpython-310.pyc,, +social_core/backends/__pycache__/upwork.cpython-310.pyc,, +social_core/backends/__pycache__/username.cpython-310.pyc,, +social_core/backends/__pycache__/utils.cpython-310.pyc,, +social_core/backends/__pycache__/vault.cpython-310.pyc,, +social_core/backends/__pycache__/vend.cpython-310.pyc,, +social_core/backends/__pycache__/vimeo.cpython-310.pyc,, +social_core/backends/__pycache__/vk.cpython-310.pyc,, +social_core/backends/__pycache__/weibo.cpython-310.pyc,, +social_core/backends/__pycache__/weixin.cpython-310.pyc,, +social_core/backends/__pycache__/withings.cpython-310.pyc,, +social_core/backends/__pycache__/wunderlist.cpython-310.pyc,, +social_core/backends/__pycache__/xing.cpython-310.pyc,, +social_core/backends/__pycache__/yahoo.cpython-310.pyc,, +social_core/backends/__pycache__/yammer.cpython-310.pyc,, +social_core/backends/__pycache__/yandex.cpython-310.pyc,, +social_core/backends/__pycache__/zoom.cpython-310.pyc,, +social_core/backends/__pycache__/zotero.cpython-310.pyc,, +social_core/backends/amazon.py,sha256=DhWTBS2ZKBWUIEg7V4KiRugxZK-moDcKtviZd75DMR4,1518 +social_core/backends/angel.py,sha256=0RhlOK1QRprr3RvfPbSlIF8wZOTjAxX7kDNDnt_gSk4,1075 +social_core/backends/aol.py,sha256=avCRPEghbMaB1cm2krmXPhWzTNa_cJq73_jSUtGKZRM,225 +social_core/backends/apple.py,sha256=rtLgy1QETW4NOKckVwQ8luuAE0vLrrNNdKF0mf_EJaQ,5666 +social_core/backends/appsfuel.py,sha256=rSb2qQQSw4rCRlt3EMkWn3kc-4PSQsNq__k_qCXgEjs,1506 +social_core/backends/arcgis.py,sha256=_rCJCApQZMHn6tKFufxBAqKKtK9YBsroBC2V8J02u0E,1043 +social_core/backends/asana.py,sha256=WBbCC6plfYDzsTKNjqfVx7Rm-fb1unwO0C6RBq89fsU,1476 +social_core/backends/atlassian.py,sha256=cMMh93BqJ2tJ1ijKtROcK0HLJpIyIwfxI-BhwypDsng,1579 +social_core/backends/auth0.py,sha256=avgDiLp3fb5t1N-cblHjUq3gsFYO56SdADzanEZK_dA,1683 +social_core/backends/azuread.py,sha256=Xlwb69gPxJA25Ww0sMlq425UwldlgJ4lHY1UF4qI2AQ,5304 +social_core/backends/azuread_b2c.py,sha256=NUQS-BYytimbB88FZcBr0pDYW9IoaKzstmA2ZCoDACo,6530 +social_core/backends/azuread_tenant.py,sha256=bwY4CbyrYHFiCAal6othQ2E7jwanxUzMf77xz8H2BBI,4520 +social_core/backends/base.py,sha256=ILNlnTEI3EB0ajY-cY5lWUq2vNbYSQPJ9ENxQZSS6hc,10137 +social_core/backends/battlenet.py,sha256=hHtE6NlrciTEK8vuGiogibOS1wwsky78jgCWQYS_z9A,1788 +social_core/backends/beats.py,sha256=bQlU3t6hwL435cKbfPEdZwx-8FOrV1VFAlSDeDPTTNs,2261 +social_core/backends/behance.py,sha256=JJ60a1UIqcQWgPXvCBdEH-1NzviURqJUiz34yXfWFBM,1520 +social_core/backends/belgiumeid.py,sha256=Cg-2lJe-WEUpa9wl4Wi4o2RgqtCg2A65mqpmKUmlvN4,343 +social_core/backends/bitbucket.py,sha256=2OLgwa9VbbeqO8cJKTVO1SsVN0aoBK43shF508qUCdU,3350 +social_core/backends/box.py,sha256=ja94THzrL-WleA5TVvx0262qg5J_XJhFTnxQZNqi858,2150 +social_core/backends/bungie.py,sha256=W2hkUzNUnroAiFi6fz_tnDG7b1ygTRu5YvcfmCpUzeo,3215 +social_core/backends/changetip.py,sha256=Y3FhuW500UjHsShxk46FFDzPBxh_vRcu6gYT2FKojhk,869 +social_core/backends/chatwork.py,sha256=g-3qSssPgqHYfKz2eqUImLPykxXH6p3zgwDc49IeQ_0,2096 +social_core/backends/cilogon.py,sha256=YiT2Zbm759_5a5m8pc17pthGbVY3IBkVqK2lYfPiPIw,1526 +social_core/backends/classlink.py,sha256=JyiGlSB1C7xkWyX_42QDMPy0QplcSWjhQ-y2jeMsv6k,1461 +social_core/backends/clef.py,sha256=SqR8uGgZ548eLGLQq9Gt6nuvFZDoS-B1OY-dJI9Smbg,1675 +social_core/backends/coding.py,sha256=eCSFsHg_f15dtcW-W5A_vDNiPto0qvxZ1WM0YovFXqk,1420 +social_core/backends/cognito.py,sha256=0j2Ls80NlLVS146K65WPEFO8ymu4KSRH3-N2w0wTbZs,1718 +social_core/backends/coinbase.py,sha256=D1U9bLnCnnz9dTpHCPEBZ0y3XZnKzi194WVM0JksCyo,1387 +social_core/backends/coursera.py,sha256=Hekivf2r4CMWR5oHJZDb86hA-uV2G1PEDEFKeGJweFw,1453 +social_core/backends/dailymotion.py,sha256=6y0rEMiJhPGqHooGnkiCRh0gTf6OrVopW31LpGnvcEA,886 +social_core/backends/deezer.py,sha256=DQChghkFUmhBScq7TumQ4sRwkvkKIKssQ3_ZYEl7pHM,1646 +social_core/backends/digitalocean.py,sha256=ZN5rJWbEFp2EgJ0wnQOuNtxku12u5OTPTazJm1u5Mwo,1428 +social_core/backends/discord.py,sha256=HeKuxWHnlMuyhSFnRiVX4eCmDS7m7n0bKSwZoZDgrvI,1058 +social_core/backends/discourse.py,sha256=Im8fN-cXho3RTJluoVt1vmDLhx7PIGtDOCrVIcgz-20,3224 +social_core/backends/disqus.py,sha256=YH6_C2n90tBsGHa96ePBhJgFo4LDqocKPZG1cWXFVuE,1772 +social_core/backends/docker.py,sha256=jVwVdhuJMACWsXJ6mtwkVhBjUvkgu6c7tLEYERJvkJs,1620 +social_core/backends/douban.py,sha256=bZ5op-Eh45691yVn-zsSOKzJKtq603k0BEvGoTqyXRk,2072 +social_core/backends/dribbble.py,sha256=RMqqBdSM-xXBORior8Hd7ent6NTAbodgD4SxVkSR6A0,2177 +social_core/backends/drip.py,sha256=C6r49jT0Kt24YCH_7-yyGaRnGeO0wrKWYN-JHxwLdAU,873 +social_core/backends/dropbox.py,sha256=85khZLVcT7i7PBN_-pv0ry42qmbAg9-JwqOIbiT-2Vs,1136 +social_core/backends/echosign.py,sha256=X18dCWgE_fZWooA6fSs8yFRWwRoe-CgQF0rE3ssdoGw,854 +social_core/backends/edmodo.py,sha256=njpWDdNXVZ9PJQ_b7wiudY4ytZZkJJHbrep2qak2tqo,1102 +social_core/backends/elixir.py,sha256=BB5gRuq53Mvxsoe5gPu8m0irwRd-ZsyaBRHplIwaS48,1217 +social_core/backends/email.py,sha256=psHmRDKOQXpcLij4k6aglcXotIroSKQGL35i_NZWz2E,281 +social_core/backends/eventbrite.py,sha256=rkNGBMNvNc1mbg3MVNndb7UNOqileGYcQKj_69saW2E,1065 +social_core/backends/eveonline.py,sha256=zzE6h-Z4Kjj1levNHDcpkMy07OOa3QU4bHAGbwUmgNA,1427 +social_core/backends/evernote.py,sha256=IvZzyNuV110cZSqojRj1daf1LU7Z5HjzFE-PLheMtIk,2630 +social_core/backends/exacttarget.py,sha256=xKxf2ECj8OgVq5pWSI91wkc3x4NDsvL94q-xdhgyq9A,3958 +social_core/backends/facebook.py,sha256=ZfF3_C1XcXq64vf9zJJRrJte0-Bv9lBSibarfz6GqbU,10526 +social_core/backends/fedora.py,sha256=fo3uWO7hNzfuWi52nBBOksFKCEEcPswbdnaE5oTKo18,274 +social_core/backends/fence.py,sha256=kgrhA7TUgliY2fARty65ZTK0SmZvEoDV2EpKZpsA-Vs,1115 +social_core/backends/fitbit.py,sha256=s5SfhbOtNOOsN7hxTBxJo31yf9l2I3gomqsrNx5AS5Q,2272 +social_core/backends/five_hundred_px.py,sha256=RCslMQ3tLXHfP0ZXCdgboKccVhcjdiou9idzJqJH6UE,1140 +social_core/backends/flat.py,sha256=dCrhWrcB2pRDjnPVWAu2lwKNcdNROdvIrVxFugrB7e0,1011 +social_core/backends/flickr.py,sha256=H7-M1Tdn3STfOK7taUciZ7rZqNgDvyLKm4Pi4vNPngg,1438 +social_core/backends/foursquare.py,sha256=CFFObzZ5azEZpSNbN4R4DnDAgsCwejjKKowAa6kYQLs,1343 +social_core/backends/gae.py,sha256=ory_u216FMHFSXkQYmAN3V5PHFklVECykGwqm4wsBJ0,1241 +social_core/backends/gitea.py,sha256=jMJO4Nu22eqaa4w5q8vQj_czxJcDqyiDRBHzN--EgjA,1608 +social_core/backends/github.py,sha256=7G9FSeU4n8JUjewoNqH5MBeNj01F6DBhMqKu0g6KA-E,5113 +social_core/backends/github_enterprise.py,sha256=KFdDvsG8_P0nPMnEOBaady-PDMfTRB-GCpzk_kjSCa0,1272 +social_core/backends/gitlab.py,sha256=jSpBg7JJcGQrHRRZ4EACBIj_DQn1jC6d1bUjcLKNXfo,1835 +social_core/backends/globus.py,sha256=9l8c-xkgr-1A3z8gsKzGcbQHDvGFFcBFV-iebHyyZ7k,1036 +social_core/backends/goclio.py,sha256=XPkrkjfzps67KNh3CWvcbExrJTX6huazN488LLHzaX8,1236 +social_core/backends/goclioeu.py,sha256=97n6gNR5TCK_eoQGPKj3jrswMbdfV69O8FX-g3biiWY,468 +social_core/backends/google.py,sha256=SMIK-KfCkBiyb8QoOIglN74bNifa_He6ieAX0uEahuI,6302 +social_core/backends/google_openidconnect.py,sha256=rHLY1wxjPeaWddoneTsp6LRNTq5Lt3hf7Rf8kZPnPrI,776 +social_core/backends/grafana.py,sha256=cy49c0EDlH31pRuC83kqmV6al-NCJKVVVc_mAPDuFlw,987 +social_core/backends/hubspot.py,sha256=HBDMgtUxTzt4RYhe8Fl3JZ0F8cU7dG5B-4VSBYGKLvQ,1152 +social_core/backends/instagram.py,sha256=FGxkM9PNrLkaBxEMp4LZN8xu1pUFD0uELV8AOK2hhXs,1536 +social_core/backends/itembase.py,sha256=Uus2gGc7WycHqXpyav3dkgqAsERGLY-jcEkZ4uVJ314,3392 +social_core/backends/jawbone.py,sha256=1tUDzkfmEDz5Ri9yMQtNj5WseSldd_WmQMsbPhdTlp0,2704 +social_core/backends/justgiving.py,sha256=RC9rFNpyn00k-0ssLYqiVDCRTcEWCYkvlCumLeoLB6o,2162 +social_core/backends/kakao.py,sha256=GPyiSOTnxHcAwrbCIqceBTaIKiCBt1nG60S6ZRwh31A,1940 +social_core/backends/keycloak.py,sha256=w6K7bJw8MMiSdqEY8rGnWU7qhZuo9XLQWscKOYfXTcE,4860 +social_core/backends/khanacademy.py,sha256=gm6CMPpMmfaQzzYuV7jyoLpr9tBjdYMokM-rvxRkt0c,4641 +social_core/backends/lastfm.py,sha256=GG_m0XEVBjiDYm1WLr1hY3dTiR2UUQ4MjV8SIkAlwVQ,1958 +social_core/backends/launchpad.py,sha256=hS9rAnSZHZFanH5-asUAVk8EEpvHReYmYmuqezrrGs4,196 +social_core/backends/legacy.py,sha256=peTRWlCFznxG1zrAsiWPXjGvC9synE9vQ3g1r_JUBSI,1466 +social_core/backends/line.py,sha256=deAE6YPmrPc6bMf3ZPBrzi2UkL8kzq70ccCEjwQxfRM,3458 +social_core/backends/linkedin.py,sha256=pUagw-gIM90VvxroLSXMERnQh3lk9lYiSohJzyh7UKE,4606 +social_core/backends/live.py,sha256=mNmUdcrhRzhwszs71qOUVPJFJwkAIiwcut8LmMVQsPM,1563 +social_core/backends/livejournal.py,sha256=cGJZ2cG2Sy2jVrsOVGDqoFx_MWZxgtx1rgLXqc5L38Q,941 +social_core/backends/loginradius.py,sha256=W5egYTqfVPjHXw0Kby6uJbfN319OBLUm-Bu65Fwi0yY,2633 +social_core/backends/lyft.py,sha256=Py6EjDADeeTg0gcTXcFaOo2UAzi8dDMpMCD5I1sK-Vg,1688 +social_core/backends/mailchimp.py,sha256=eNi3hadxHJ3YP_GTwqM3SLBksVMSB7p_CWJtbxRQZvA,1109 +social_core/backends/mailru.py,sha256=GOu41iqh_iQkzAqoTuFeo2q4pmcGqkLZCfQBY6IdPiA,2697 +social_core/backends/mapmyfitness.py,sha256=jOhQAc8aTtaaD3FRFcLofJx3xtRyd2Yym9BrRK4VKwU,1454 +social_core/backends/mediawiki.py,sha256=0vC4MY_LhZ7V12-v_iCEkzqxfOSAzeL9SofnwiXxFJM,5738 +social_core/backends/meetup.py,sha256=e_oPh5HfXspeoZTyUeuQ3eU7GapHi20Ni8NRYozFkso,1189 +social_core/backends/mendeley.py,sha256=9MRPwJEYVzmqFRQ-J9uk2cVq3uEdWW_hSNel_8_OC8U,2165 +social_core/backends/microsoft.py,sha256=1z1DH7P_L4d1JzbNknuBu8xLQFZzcCKS08_iQc2UT9E,3045 +social_core/backends/mineid.py,sha256=mvIAZwA-ZJpjdecU2wmlbTgfUAbG0gDJZIe-6GIiOVI,1222 +social_core/backends/mixcloud.py,sha256=oJGLhtY7gt31JSQWMyMTeZim_38Ok2djNwD8GnG6Fwc,940 +social_core/backends/monzo.py,sha256=VG-bc9Ha11YGZb52zbgM56I7yeUHUPaHWcFfcF6ki9Q,882 +social_core/backends/moves.py,sha256=qu5RHTviDG6ANtJEDTbfjvxBZpBVaZ_q_MmjWwQKhMU,1008 +social_core/backends/musicbrainz.py,sha256=4GMWKcbrjlc-yUBu2Y-1-Uv2l9sGaLQy4SdXm8GBHyw,1071 +social_core/backends/nationbuilder.py,sha256=ycP0xogsYexQwZyEnWnbCkedJoje1tTOcZY4ol9vWac,1546 +social_core/backends/naver.py,sha256=GzyMpeZIAUuaowMkqX6QPHVr0mAOsyg_n1d6MgJ7hpE,1930 +social_core/backends/ngpvan.py,sha256=cLdl4Wui0VPI8qVa4-IamR3E2B1pFvIP_psj_xxRcdw,2254 +social_core/backends/nk.py,sha256=biOBkgJmmm5TynK9G-aQM2T6fe2DuoxFUBQ9jBD6k0I,2485 +social_core/backends/oauth.py,sha256=xbgp8Iqvk4C6jwGwkp4HmsvYD2TFGv-BpCKuvjPhZi0,16894 +social_core/backends/odnoklassniki.py,sha256=TnHgOxWvgEy1eBxrHLqzmb4Vli5JK5_maE5E4onxjkE,6782 +social_core/backends/okta.py,sha256=_hDdAOrGKIduw-T8y2OGXwmHU0iTmh6r_VMjFEvqvNs,1832 +social_core/backends/okta_openidconnect.py,sha256=k6jtJ4j3zmpu1Eftny8N-j9YLieDYIdiENC_iJujj10,421 +social_core/backends/open_id.py,sha256=ECuhDcpfHNhu7a5MaiFTIweDh_X3G3N7POqV4mflmnI,9982 +social_core/backends/open_id_connect.py,sha256=Tmn_upgHRr6HIFUMCRpWuyEanWgY5lCw81VMpZ5X0dM,9143 +social_core/backends/openinfra.py,sha256=P2ea9WFgdQNHt6xMoS-wYJAl6tAPBhAdcxI4P1rCd0o,1392 +social_core/backends/openshift.py,sha256=eYEtya5Q6GIudyq-MC8cU-agbmocaCFu7XmqFQyL8iw,1107 +social_core/backends/openstack.py,sha256=MGZMSq-73XCGrrpPy8cC5CcHuBot9bdlF0nRz02RZUY,1391 +social_core/backends/openstreetmap.py,sha256=pZ8Czs6TbdkwSuzZBSncCwSvIeQDTvO1PkX_lnafX_Q,1914 +social_core/backends/orbi.py,sha256=6gDS9t7difuBkjCxU7o7ZmBItiaVv_uBZmUCRd8wldg,1283 +social_core/backends/orcid.py,sha256=Jh7slombWaR8c_eUljEhIfoJIjIiTNZXPtFIyBJ86iY,5685 +social_core/backends/osso.py,sha256=MEs2nx1rtnnqMgsMxmUvUY27B96cuTIxnKdbiER3hdY,1718 +social_core/backends/patreon.py,sha256=cmE88OlJxgrqzetLGf44UyuxoYPLYuAvOiN_nm7VGx8,1327 +social_core/backends/paypal.py,sha256=NBoKPkO9XCr8J6tUtQZwEt1DV3rCFNPqx8eIj2kg01I,2505 +social_core/backends/persona.py,sha256=9196UX9x3xdI-U13RGNT2_ZY5eUdchd8oRN_wpEOdg0,1889 +social_core/backends/phabricator.py,sha256=8Z5DZw2XAx8zYbK_7R2ylWRLKiYBIRfxgJ6hzv65fj0,1566 +social_core/backends/pinterest.py,sha256=dsxP9AFCOfmufOYr8k3A_Yw1NQxWrb65LqUSDq_4Ers,1378 +social_core/backends/pixelpin.py,sha256=LbV7Cd4ZlGSg_xLErF2zQugbmGJE50rj1BX0wgYxJQM,1256 +social_core/backends/pocket.py,sha256=pJQ19U33zomrzGk-kXDMHoyWJhqu_axol0jW_MNk6f8,1680 +social_core/backends/podio.py,sha256=4iFhfKmxXVVhBNTeEHno6IV_URs1AdA3mb1Usxys51w,1273 +social_core/backends/professionali.py,sha256=lu_2xLGEBzGChA935x87I-gUpI0s7bU3R-rIMORKMD4,1864 +social_core/backends/pushbullet.py,sha256=0vBoAdhYt9Ndu9DIU4cf7EHcfItGm7wl5dr81cMHT7I,823 +social_core/backends/qiita.py,sha256=pfrjZsBn-L2FcvQscG-SqbnQDnNBeuLWXR9FFbAYmwg,2879 +social_core/backends/qq.py,sha256=V-M8ADSfFkSTs2GQsLRCvGkRAONUtDDrzPcMpBAZKxs,2179 +social_core/backends/quizlet.py,sha256=ON79k8Hqc7xts5mPC6BioDOXivD-H9JDxtvWDrPn-sE,663 +social_core/backends/rdio.py,sha256=CdEUAijwU4AqXGcm9qMrauFp2cdG3J90scOpPiL-pCk,2510 +social_core/backends/readability.py,sha256=wy1gF7v6Vb3GpMnHtB7yUcX83cv892wCwFIWt41ZW4A,1304 +social_core/backends/reddit.py,sha256=9aERztxOsj_yCRWcC2SA8D3jjqdsghX6fmWJrrYwEaw,1880 +social_core/backends/runkeeper.py,sha256=N8qPjZPBzc_5REmFqFqRgrk618_nvmO92Vohfuz-m2w,1809 +social_core/backends/salesforce.py,sha256=DgaSjI_ghm7L2LqkgtjEl6gp6c0uifpbrCZMRwtIGwg,1823 +social_core/backends/saml.py,sha256=1GJGioF_W_ZUagnO6K3xAQgUa6CC8DPB-GJVCebEgHg,13760 +social_core/backends/scistarter.py,sha256=Z10i3gyKW6_l-PM52-j3nC4bBC0ZVGI9HeGDMwXvRGE,1908 +social_core/backends/seznam.py,sha256=EWTUZAb5BqSwjMyFs1dJoB0AuvCUhxFbXsYnA23Msns,1721 +social_core/backends/shimmering.py,sha256=PzAAa6xEdDuZC4ry0hPXgxYqrBKKR8o8-VI_hIdnVTU,1176 +social_core/backends/shopify.py,sha256=83DV4_bcUUDTgQ8fzOCOiTGgjraHiaFnEPDM5CtQjP8,3447 +social_core/backends/simplelogin.py,sha256=EMAUnOJuYqvkO9LPxlHbXSCTuapOKBJPl7aJPb7HqrA,1336 +social_core/backends/sketchfab.py,sha256=JFJfrJwzv5SyuGtPKqzc39ED_VclA9_tLkdqi0clKCk,1350 +social_core/backends/skyrock.py,sha256=BJP2SqDeGJ5ysZo5jnePepH85L-tUGnppQprzmo6kTY,1200 +social_core/backends/slack.py,sha256=tCxNEAXdKK0heZZlpOBmLr9z5fbPHDg1pBnBymZ8msY,2026 +social_core/backends/soundcloud.py,sha256=cC8FhUtVglhrNREpN0IHsGuMlvT-V4_77MjqCXhN3DU,2143 +social_core/backends/spotify.py,sha256=n03-QhUsrsWVO2Xzfefavw0yhcDnLA8ATQ-E2D7rNKU,1518 +social_core/backends/stackoverflow.py,sha256=w4W5DXPiq8OVGdB4amysSFkpL5ir5BYIHUG5LfUTLUw,1451 +social_core/backends/steam.py,sha256=yGhgyvT6_FS8omlc3uajw_zZXLHVNB8FYsMTH_OHHcM,1594 +social_core/backends/stocktwits.py,sha256=ntNhdg9GZuRwmmsFP9VG_zttr1unCrqn7cPQs3M92vs,1373 +social_core/backends/strava.py,sha256=_AUTiFokt6kkTk-7IfpX4x1qHVItv7OD9BO49iEnke4,1857 +social_core/backends/stripe.py,sha256=HIf5Nj8lmHN1yYxr4BO5KPBd0QQu90G2RqTgOhgPoCY,2088 +social_core/backends/surveymonkey.py,sha256=88S9s4Vd96H7TYCu2v7pdCNEGLxPvDWQm-Jw2DnhyoE,1113 +social_core/backends/suse.py,sha256=i7Vs-_-HLf3PJaFkDBBvd97ITwzWo71Qycl9ajZgU5s,462 +social_core/backends/taobao.py,sha256=LHL8eUEBQzWqhz5EaK6vEPrN5jEAHI22JZKGL_zB5g8,946 +social_core/backends/telegram.py,sha256=X-cKOEM273AlACefHUm1QKbEA5WHqgfhAKhbsQoP8SY,2109 +social_core/backends/thisismyjam.py,sha256=VqfPy5S17PH5-ANhQmN_OkNAko_Cwp2vcK7QH6L54h4,1208 +social_core/backends/trello.py,sha256=yQzbkJ6fG_oOCebwaLHIo6pGwWRTICah7oIeEl8VD8Q,1504 +social_core/backends/tripit.py,sha256=DdROAI_8N0KYmzSY1swp9_6dQHbpeQ9fjM1en9GblGk,1700 +social_core/backends/tumblr.py,sha256=4-oHbqmp_zyuKNJczrb_H6DYVKOFi91TbjHal9DwfXM,1099 +social_core/backends/twilio.py,sha256=P-B6BV1NKIAU7bDi4LlzXKcR82JPYndx6OfvwUXMkp8,1384 +social_core/backends/twitch.py,sha256=nDh84mVmsjGv6Ke1SchGiss8V0rtovWmHaOZUDpE_5s,2255 +social_core/backends/twitter.py,sha256=Y0NG8UoLCFUQBwyVI9I6ZwMR303fb7N3cloHdcrlwzs,1494 +social_core/backends/uber.py,sha256=irhmo3YGxQ-651IqhlgDyUicHe5U9sjs3m4P2iu3Z1E,1351 +social_core/backends/ubuntu.py,sha256=XdMZGOLin9Gcn6lVtJHXevGM3OIzJzN0D1GlNmJeBCw,370 +social_core/backends/udata.py,sha256=fynGoP_gDVbDyUxu1hTZBcbHSV30jAJE_ypTRxhu9VY,1126 +social_core/backends/universe.py,sha256=SnBMiOLOyf4KpyDpdi0zHRN02rJ2eaMHEOWD6e2jLNM,1228 +social_core/backends/untappd.py,sha256=_od3WB8f52QHU05Nw0gMtoc0252d1cZDoiNOX2Lav4Y,3889 +social_core/backends/upwork.py,sha256=nhgdF3xvGbsGS0OgAT_7lEfEQnNms18GQF2tAZICGsk,1384 +social_core/backends/username.py,sha256=l5qKgKMZY2QKxCvDd5nHfM5Y2DmhivFQVSciRSo0QeQ,262 +social_core/backends/utils.py,sha256=D4Xr3gwkmkEehqyW0vhMGXvUcmyUhGStIIWiFIAC73s,3114 +social_core/backends/vault.py,sha256=mSB6vQric201oSBsTfGlOcjzi4iw9o5tmNR--b-Q1B4,376 +social_core/backends/vend.py,sha256=7dpOaI8ZarXVhC6aYTsTHiCEp9VGvTHdlH6BiVaJy6M,1189 +social_core/backends/vimeo.py,sha256=fdoPXLTF2Pi8ggMDAqrazcHDvi09RayidimMNG4eN_c,2804 +social_core/backends/vk.py,sha256=uQWopUoiDKPFXi9ShERmxB_bz_YybKMXG694nrc1DTY,7036 +social_core/backends/weibo.py,sha256=UlzGO59f2SFbeXUdrjaCclLBIH0cs8iGJ0F2hzPGo94,2199 +social_core/backends/weixin.py,sha256=iV6Y1MTr3Wl8fqOyXbdRzcH-aU_-xvMxcKTIbCMPkaM,6208 +social_core/backends/withings.py,sha256=wxnmsRwUGoVRTVzykndHCvn9XghbXzUQJlxBdAL6kUY,526 +social_core/backends/wunderlist.py,sha256=kuFk41LxZznHpI4_IKA23lhsTqRTVWUiVTyIeM8_y0w,1030 +social_core/backends/xing.py,sha256=tuGv5dsOhILuaz3AEks84j8dy3NhqReHOnwL5eMImag,2429 +social_core/backends/yahoo.py,sha256=g640RcT2yukiECXQlxMWXih_-83AeOgjQnZd1aS8gQM,5357 +social_core/backends/yammer.py,sha256=quwHpF-ieh1ElPtTp4FZX3AWVxx4LWcZf4k-5XwS67U,1511 +social_core/backends/yandex.py,sha256=QcN4JESfTWpTIQ2QytBYuOg8BhO4rBPk9P4LeGMFP7E,3018 +social_core/backends/zoom.py,sha256=_DpdBwtldGMX5JQlb5w8I8K7W7HJip6AVe8WnWrTKR8,1966 +social_core/backends/zotero.py,sha256=cowO8q8VO_ge9lFzxHqRHMrlAvTDfbQPqeyT9i-gHeE,946 +social_core/exceptions.py,sha256=zTYRXTdkibUeVB0yL_9jhD8RE164SqAdINA3rcA72WI,3364 +social_core/pipeline/__init__.py,sha256=P2MbFmM3jh7CMf0tbRf3qAInYLoubhY5IdGCY6FnP5g,2451 +social_core/pipeline/__pycache__/__init__.cpython-310.pyc,, +social_core/pipeline/__pycache__/debug.cpython-310.pyc,, +social_core/pipeline/__pycache__/disconnect.cpython-310.pyc,, +social_core/pipeline/__pycache__/mail.cpython-310.pyc,, +social_core/pipeline/__pycache__/partial.cpython-310.pyc,, +social_core/pipeline/__pycache__/social_auth.cpython-310.pyc,, +social_core/pipeline/__pycache__/user.cpython-310.pyc,, +social_core/pipeline/__pycache__/utils.cpython-310.pyc,, +social_core/pipeline/debug.py,sha256=4wXw4JKtrYoyzxZVQvxWK95P5mN9Yx1CnglQO3IZQdo,252 +social_core/pipeline/disconnect.py,sha256=E0J7WhjHCXbf5B_jcv2gMx7cTVO0JYCLJAVsATeoduk,987 +social_core/pipeline/mail.py,sha256=ecCc7bm9Vfh-_DEG1Vh2vmz9fsMbHoQd9pLPChsUdbo,1178 +social_core/pipeline/partial.py,sha256=PYeHOteaIImSW5sXN5KVa2IbkqHP8dvWt_N_3ok5KIU,1902 +social_core/pipeline/social_auth.py,sha256=DkC0Mlxy0lHEUWIHfBNPZMgaQEMoyQqrDag71TuhtGs,3432 +social_core/pipeline/user.py,sha256=lPXL1PrwaqZLuwxAVmsUq7H_uETtXHJhXbHa4Km-IeI,4339 +social_core/pipeline/utils.py,sha256=xa172l36mUkYkJL2Rza92M5chIUmwVf4gNk_vFGriFo,2432 +social_core/storage.py,sha256=alVzdX77Kb30bttFGgUTv_o4_WDX8gFLX6X3MYb5JQM,10495 +social_core/store.py,sha256=3LHAQ0nr4tZ-_eDWnTrC0u0svZpdNoOkJ6lz4CNLxKY,2571 +social_core/strategy.py,sha256=yvrHV-F3CfPAXbfIkhMM-cRrxz154cjaOhTT5750OvU,8613 +social_core/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_core/tests/__pycache__/__init__.cpython-310.pyc,, +social_core/tests/__pycache__/models.cpython-310.pyc,, +social_core/tests/__pycache__/pipeline.cpython-310.pyc,, +social_core/tests/__pycache__/strategy.cpython-310.pyc,, +social_core/tests/__pycache__/test_exceptions.cpython-310.pyc,, +social_core/tests/__pycache__/test_partial.cpython-310.pyc,, +social_core/tests/__pycache__/test_pipeline.cpython-310.pyc,, +social_core/tests/__pycache__/test_storage.cpython-310.pyc,, +social_core/tests/__pycache__/test_utils.cpython-310.pyc,, +social_core/tests/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_core/tests/actions/__pycache__/__init__.cpython-310.pyc,, +social_core/tests/actions/__pycache__/actions.cpython-310.pyc,, +social_core/tests/actions/__pycache__/test_associate.cpython-310.pyc,, +social_core/tests/actions/__pycache__/test_disconnect.cpython-310.pyc,, +social_core/tests/actions/__pycache__/test_login.cpython-310.pyc,, +social_core/tests/actions/actions.py,sha256=NP9VD_8pgix2VhYxpVRkpfra2RgUEfUlVAwgN8VtxM0,8624 +social_core/tests/actions/test_associate.py,sha256=8yrq2akCZ1kS0PLtON7eqa-rzOpPqtQtMAWiOzWfSeE,2924 +social_core/tests/actions/test_disconnect.py,sha256=AD82Em5TQQVr8kz1Bl34mH5VwS99pqbHT7EgC1TAyjI,2681 +social_core/tests/actions/test_login.py,sha256=JLmkVGXYnQ8tPkqoxs6PqxRJL1nGvh2dIPagJZvxYCU,3392 +social_core/tests/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +social_core/tests/backends/__pycache__/__init__.cpython-310.pyc,, +social_core/tests/backends/__pycache__/base.cpython-310.pyc,, +social_core/tests/backends/__pycache__/legacy.cpython-310.pyc,, +social_core/tests/backends/__pycache__/oauth.cpython-310.pyc,, +social_core/tests/backends/__pycache__/open_id.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_amazon.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_angel.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_apple.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_arcgis.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_asana.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_atlassian.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_auth0.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_azuread.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_azuread_b2c.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_behance.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_bitbucket.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_box.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_broken.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_chatwork.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_cilogon.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_clef.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_cognito.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_coinbase.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_coursera.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_dailymotion.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_deezer.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_digitalocean.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_discourse.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_disqus.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_dribbble.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_drip.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_dropbox.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_dummy.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_edmodo.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_elixir.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_email.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_eventbrite.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_evernote.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_facebook.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_fence.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_fitbit.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_five_hundred_px.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_flat.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_flickr.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_foursquare.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_gitea.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_github.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_github_enterprise.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_gitlab.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_globus.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_google.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_grafana.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_instagram.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_itembase.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_kakao.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_keycloak.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_khanacademy.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_linkedin.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_live.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_livejournal.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_lyft.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_mailru.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_mapmyfitness.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_microsoft.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_mineid.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_mixcloud.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_musicbrainz.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_nationbuilder.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_naver.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_ngpvan.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_okta.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_open_id_connect.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_orbi.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_orcid.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_osso.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_patreon.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_paypal.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_phabricator.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_pinterest.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_podio.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_qiita.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_quizlet.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_readability.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_reddit.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_saml.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_scistarter.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_seznam.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_simplelogin.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_sketchfab.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_skyrock.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_slack.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_soundcloud.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_spotify.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_stackoverflow.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_steam.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_stocktwits.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_strava.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_stripe.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_taobao.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_thisismyjam.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_tripit.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_tumblr.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_twitch.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_twitter.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_uber.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_udata.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_universe.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_upwork.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_username.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_utils.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_vault.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_vk.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_wunderlist.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_xing.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_yahoo.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_yammer.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_yandex.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_zoom.cpython-310.pyc,, +social_core/tests/backends/__pycache__/test_zotero.cpython-310.pyc,, +social_core/tests/backends/base.py,sha256=19XjUo5jmWSza288FVR6GIDNa0DvkqRqH7Vt-1XGJsE,6105 +social_core/tests/backends/data/saml_config.json,sha256=y77dPVkqqKLTpNp3Foc7IhQq-GxIl3O3usTJ5GBX15g,4113 +social_core/tests/backends/data/saml_response.txt,sha256=K2pUL1chyWM1ICWhjsks1GRrC8YaVnPcD29FAmfkmw8,17495 +social_core/tests/backends/legacy.py,sha256=OEqdzxs0y65nD8SfvcleL97bDZKxM43RGqp7Nd7PO6Q,1403 +social_core/tests/backends/oauth.py,sha256=utmNoz2Dmdwh9OTrz5mtLogebR24L13wNFw4b-8J5tA,4224 +social_core/tests/backends/open_id.py,sha256=o95f5HdRvjp3j7CMsDw91jHxmVgpM3s0eK40eSlJm3g,3158 +social_core/tests/backends/test_amazon.py,sha256=qShCATio3D3-JPMXOCLHAMhyLR5C3xVhZFJ-P-uMYs4,1640 +social_core/tests/backends/test_angel.py,sha256=Sy6b3OGVvNZQE1OFc-viAf16IU7LWTK5dQR5VQkpgas,1158 +social_core/tests/backends/test_apple.py,sha256=J1ibFk2ZY_DGy-qV4TT6tgZkjD1RCBCSvsIWSDod1nY,1801 +social_core/tests/backends/test_arcgis.py,sha256=PK8Loo9hiIqQJHsf3IhU51HSFG4sVJRC8UqS_eO5zqo,909 +social_core/tests/backends/test_asana.py,sha256=H3Zcqhbymp_QVQcbCY7zyL5e_VSs8b32_zRKwUD10CI,832 +social_core/tests/backends/test_atlassian.py,sha256=sqqlsv0vy8vdru-TqH0njGQmgRO-ew9JfrYQu_Mh1JI,2213 +social_core/tests/backends/test_auth0.py,sha256=zxpv7P-_N1qm7SfBjnCIdy-Z4QFPIZjX73j37ItDuN0,2461 +social_core/tests/backends/test_azuread.py,sha256=I8-XTvzZJRr2W7mwmiSnA02QPvey_pniNnxPci9hwPg,3142 +social_core/tests/backends/test_azuread_b2c.py,sha256=9vYq3VNauuSitcaqKptVbeH9GiwAQtQvAQdd4ugCo08,7777 +social_core/tests/backends/test_behance.py,sha256=FGo_2Godkaza9MsuIFSfPh97mOlYHjdLujif4sWJVNk,1728 +social_core/tests/backends/test_bitbucket.py,sha256=qetarbyA0PHnVgSosYvZ6WJCiXigb4_YFiOj9w6u080,6171 +social_core/tests/backends/test_box.py,sha256=Nm8ATUpoF01bRJWKOny4rLZFATLgOuJz6sA2YFnIiSw,2451 +social_core/tests/backends/test_broken.py,sha256=SUmOU6y0SPGLVv6ZHwELRwX4DtwIqWWRNc7NZen0S9Q,997 +social_core/tests/backends/test_chatwork.py,sha256=qNpW0krmJquj7Soib_wl5pMZzQxa62QOxRwFuqBU25w,1419 +social_core/tests/backends/test_cilogon.py,sha256=paiwXqq2zdFG-fAgZSvWm4XRDP264iZQpEMZGPdaryw,1418 +social_core/tests/backends/test_clef.py,sha256=kAyQyyZC9MbhBW6Drqc_2TgFIRvqla5BcxN2yCqqnfI,655 +social_core/tests/backends/test_cognito.py,sha256=anCpt9mBI9JPrRg9PDPm1e0OtFYDz7HcbFgYDpdtukc,1028 +social_core/tests/backends/test_coinbase.py,sha256=J0d4dzQWevmo_yC9jaM190dhZKid7vIY_Q8LTxoqWAg,973 +social_core/tests/backends/test_coursera.py,sha256=NZeRiDpFO_bB3d1UEbrEbITur2GcwQ6ogs_sFwL9br0,1141 +social_core/tests/backends/test_dailymotion.py,sha256=Y3rt8E4_a78CyiZGWQJ0TEeA3ileUKpCVtx1sw7WH1U,532 +social_core/tests/backends/test_deezer.py,sha256=kh_0d7Ux30TBS991NnSQdwkkuQAWywF-L_jUfcb3bWw,1306 +social_core/tests/backends/test_digitalocean.py,sha256=0OBPIGdDS5fH71oRP5Mq5ecbZuOfPHSsHO4barpSD5Q,1029 +social_core/tests/backends/test_discourse.py,sha256=eVpnULN7r4frPXDjUjqRsGtE4UD-8eGVMUCALaiWCDA,2733 +social_core/tests/backends/test_disqus.py,sha256=s5431CGrLB39Smr1rl9Fw4rQ6gwjTNeO1iRIH_Ri0nI,2262 +social_core/tests/backends/test_dribbble.py,sha256=YPXSPkbcP7ecAD5lr6eoPkvpjgP9wJBi90zMCGjXRcc,555 +social_core/tests/backends/test_drip.py,sha256=P-6EE7nDEIOif5xL37Xb_FIX7pHPAP6tKIGnTdSnrXA,593 +social_core/tests/backends/test_dropbox.py,sha256=qGbjtPoWKSlm8Epg_jMi9FLe6elcI1EFIW70h_h3KYQ,923 +social_core/tests/backends/test_dummy.py,sha256=tVRzbEiZ6R2_38bRnjX4TEJTFtY_E44SZwHuUKJ1raM,5018 +social_core/tests/backends/test_edmodo.py,sha256=hpL_lRGYSRu7NAuf3oENSWxxTZHS7CpqLPo3nHfJy5I,1413 +social_core/tests/backends/test_elixir.py,sha256=eY7_6KNe090Nrh5aUUz8zNtohYI19HJJo2D8SzTI288,5498 +social_core/tests/backends/test_email.py,sha256=tRAhByyLmRH4Xspie5vY4FnvO_MZNykC_DDnfYWgrOM,468 +social_core/tests/backends/test_eventbrite.py,sha256=VT0pEwpk0sCqD6czV_HOTgCq3r5n6bytwqg8Ge0jCVQ,1138 +social_core/tests/backends/test_evernote.py,sha256=mOxarWE-_peM4iTYbs5rDwrEKEBVOlxHKU6dpOokRes,1712 +social_core/tests/backends/test_facebook.py,sha256=cqkZCThP_4NBDaZ7aICOlzTqsFz5OnYPOcBJNstS5yM,3148 +social_core/tests/backends/test_fence.py,sha256=UYsKMMFiqamuaFoQ_5cs7jSOMW_tKOlX6vZAlL1w-gw,1679 +social_core/tests/backends/test_fitbit.py,sha256=07zCPruhK5GUy9fCPRCaCYWtBEYrYpGGSsCDaw1ohQ8,1703 +social_core/tests/backends/test_five_hundred_px.py,sha256=y2RZPgszfldpmRQLlYdAE8G3691AhJgzDafTWl6j6nk,4044 +social_core/tests/backends/test_flat.py,sha256=D2ecwheaFfpWKThn8Y262oSnDc-SvG4AGejdsKPIEdg,1157 +social_core/tests/backends/test_flickr.py,sha256=Wwh8DbIbl_Wwa3LBUWc92pze3jECBp81S7HFwpYY2Mo,739 +social_core/tests/backends/test_foursquare.py,sha256=u5uhbvM6Gd_8oaI6gMk6h62_PoKUh0G8fkPh0Sjypyg,4020 +social_core/tests/backends/test_gitea.py,sha256=dbcbLqpM8333VQtYoALU20uYi6UEspRfT1jeRfyNJ10,2267 +social_core/tests/backends/test_github.py,sha256=tek4d1Fbn65ksGCuq9YDMm1pZq36gSyhljLWEngKWz0,6782 +social_core/tests/backends/test_github_enterprise.py,sha256=ai8Zzz9wS1MWUOwbVnm6d4cTAhxsxUtMbS1dYKOyyKU,10862 +social_core/tests/backends/test_gitlab.py,sha256=DooCRZe25izEKKpt0a8NVpTyXIZNjNOXHD65VtQbyLw,3577 +social_core/tests/backends/test_globus.py,sha256=aQTKHLd6NIiJg56sVmvqi7mBuF9nxAOrlE8o_emSH3s,1420 +social_core/tests/backends/test_google.py,sha256=4UdMDOtK9QT7Ti00jDThg4dvRq9AV9XMpusFnhGIbwM,5336 +social_core/tests/backends/test_grafana.py,sha256=1lE7M1z140dDyme7fkSGQrGjiLjA4-W_Inigm0Mcg1A,607 +social_core/tests/backends/test_instagram.py,sha256=jCueS8U-tjPXQa4ghPp9nqdfvLTGmIM9bKH7GCdrFqo,708 +social_core/tests/backends/test_itembase.py,sha256=F9GnZyq19LcR3_3Q_awJIR27ftDCWuGfJK_fVSEaXdc,1497 +social_core/tests/backends/test_kakao.py,sha256=bALw8iPsc-tPtNZb2y9DPDOj8QAzxizuxjxavO3ySPs,894 +social_core/tests/backends/test_keycloak.py,sha256=-UjduCm9jxkPhZVqdBYE8CK5g_zs0Qwqb7HbOotxV9A,4411 +social_core/tests/backends/test_khanacademy.py,sha256=HD5-ZYA-3_Cy2Y4MWw-IgQEf9QZL3T5npWbIq3GFekU,870 +social_core/tests/backends/test_linkedin.py,sha256=syplptXflzRpgiUwWL2srl4fjZPkrybvZ7LG8-hsfXQ,1266 +social_core/tests/backends/test_live.py,sha256=yOWcbcdVlOciR-2WvNzFjHGoxoRAImsc2EL8kJ9aB84,991 +social_core/tests/backends/test_livejournal.py,sha256=-ylcyroFjhgf1EVVRFLuJuPyM_mMh1H-trFg7h_HeGA,3758 +social_core/tests/backends/test_lyft.py,sha256=CC9zqjPr0rIq6Tno4fe9tMx-uXdqYl1t2pUEGYLoCpM,720 +social_core/tests/backends/test_mailru.py,sha256=_RufazP7AegydeKduRaKZGEwDDxpCis8hfuQnl0nP44,802 +social_core/tests/backends/test_mapmyfitness.py,sha256=sJaeAKFr5qNYnlXfj7IuS8QfQA-vsJnr2hiZmpzoYe0,4534 +social_core/tests/backends/test_microsoft.py,sha256=1W04rqrDnAtGYcpxG0jhpWfBI_aNPvFbTNb1X2atelQ,1527 +social_core/tests/backends/test_mineid.py,sha256=9S0AkN9XCdR9npvjY2JBYQnHL3J691WjG6q47NwlMiY,578 +social_core/tests/backends/test_mixcloud.py,sha256=QQ05_EMbn5mBR_jUihSx7i1NXClsj1CDyyZwhQrjUZg,2394 +social_core/tests/backends/test_musicbrainz.py,sha256=hUHoHVJeylCsk4bITtQZXILch7N38_4kC78pGnmx7tI,759 +social_core/tests/backends/test_nationbuilder.py,sha256=EUCeSuJG4mAwT0PWEfWv3asG7aDbqggmd_kwjpH3pM4,9263 +social_core/tests/backends/test_naver.py,sha256=G6EyebjzbpplpTRM_ejt57He6NUips7iagjWOG_dOP4,1047 +social_core/tests/backends/test_ngpvan.py,sha256=PgQYuh9Xa1sP_Pupy7BXWKysRXOYkqCiSHSQtjRyUlA,8633 +social_core/tests/backends/test_okta.py,sha256=720WvD9upPtZapMuDMWYEPsp4Quq8h8WWVglz1VhVbQ,5997 +social_core/tests/backends/test_open_id_connect.py,sha256=SkbepRF4rKsFHXe0vhZuH76UfB4CM_7tl7EVkPwtP_k,9742 +social_core/tests/backends/test_orbi.py,sha256=zx7FgY1JN3iKrFqRvXeG_S1JSP6ZhCSlNKoe2Xh_Tqc,845 +social_core/tests/backends/test_orcid.py,sha256=S0FLukgm4aVjjE4UrmWjIcJWY1Y8rgeuo2ayim_sMSc,2728 +social_core/tests/backends/test_osso.py,sha256=z6ugNh3fJIk-wrINJ36yZ6RMZGaHtomWUkUfKuVe4AI,837 +social_core/tests/backends/test_patreon.py,sha256=RMEROIyNhMBLzHgIpGa2_3VZlYVXLo7rFzAjIu8X9j0,2375 +social_core/tests/backends/test_paypal.py,sha256=ZCgJw283Kn6DH0L9E9cXey2vgkL4qkPc5UYOGZzOsW4,2686 +social_core/tests/backends/test_phabricator.py,sha256=vASQ1lX7REbLoYI1pJDzXksbnPKgzxrWjKt_pYrB4U8,2612 +social_core/tests/backends/test_pinterest.py,sha256=rY5MxeTH0iPDKbXSNPKGfz_TM5I67-AA15qit4AGykE,1345 +social_core/tests/backends/test_podio.py,sha256=C8P0R3NaIh5NxYv3u3eBflE8Bmq94_38AjV9pNPG0jg,1881 +social_core/tests/backends/test_qiita.py,sha256=_snYcD9fQ_-DwjgeFPWRxdsngpW7mLDdIMR9NoUfCJk,3262 +social_core/tests/backends/test_quizlet.py,sha256=BbKa-jzV2_eHIsoJx_5ROIibJWpIGlf26qMZsxI40bU,561 +social_core/tests/backends/test_readability.py,sha256=prDe3hLqhq4sIq3DpZpberIL26u2BnIrotjupQaGaSw,1339 +social_core/tests/backends/test_reddit.py,sha256=oEUaKAbrxyh-VWIotLSGqkuDSGaLy0p71Zq4rRRf-kU,1915 +social_core/tests/backends/test_saml.py,sha256=gSEClfO1mVGuB7rXnwQqpVGLHyEUuozBZfcSD73wxVs,4652 +social_core/tests/backends/test_scistarter.py,sha256=LvjdmUvJwkfsuEJccTN9ZRj8-qD9XGPOVPUZAYZeRCE,799 +social_core/tests/backends/test_seznam.py,sha256=atYPqCqO3epRtJSXMgHuNdTk2Jpn8b9oR09_f6q5eDA,926 +social_core/tests/backends/test_simplelogin.py,sha256=GDW5Z7AytHERlETcsv8eZntNxxpE4JX0bI9pAJbKYh4,752 +social_core/tests/backends/test_sketchfab.py,sha256=XOUTch2lrHiZSbBPwcLwzjgAVtnbqDtWUwDU2eCQ290,675 +social_core/tests/backends/test_skyrock.py,sha256=aGxat5VOZpy8VaUzY50LqtsoPb8J1k1i6B7xHBr93iE,1441 +social_core/tests/backends/test_slack.py,sha256=9qLN_AdI0EeD5eJPp2PoHbt4zc08PBPz_w3xnMspAWo,1841 +social_core/tests/backends/test_soundcloud.py,sha256=vwqqLokxRGFi9p0mYvC6LbHaFiAWJhwRs_bHAdobhec,1731 +social_core/tests/backends/test_spotify.py,sha256=Tw-iPTT2cLWGKWFGfSoWYnMZQTjT9M6KilYdjndX9HA,857 +social_core/tests/backends/test_stackoverflow.py,sha256=HViU5A4D-2mR6NFX5jUhrtNm2gCgil0ZiUldvnkC9wg,1788 +social_core/tests/backends/test_steam.py,sha256=DcSFMqJZzPBZkdzsIE5ZZbmmwNBymtFVv2qV8bPkQH0,5588 +social_core/tests/backends/test_stocktwits.py,sha256=LjLrpojhhwVdSqAX1tyc4OUJfOEx2pUI4lCzzCw3wGw,1648 +social_core/tests/backends/test_strava.py,sha256=cxdI9IhLeQLMl0bylO87lQny0Lne4pPj7dIeoSFg7pM,2719 +social_core/tests/backends/test_stripe.py,sha256=I-tIXPOV9ap2DCMZLR1vBhTBBAf6BOIRBsQvFRFYKOk,1512 +social_core/tests/backends/test_taobao.py,sha256=32zVj6BZVRnORA1G1FmmR0DSFQxZx4oDnTeopYAhsV0,777 +social_core/tests/backends/test_thisismyjam.py,sha256=-Xk47QXTZ8o75821Bxns-mePsi6esP-DCaukgEa1kzE,816 +social_core/tests/backends/test_tripit.py,sha256=35JhTrpLPsm3eicQbY0wqYCtOPPeMNWEz-xypcAd2Z8,3410 +social_core/tests/backends/test_tumblr.py,sha256=LYtilUEmDc3NfzJJkhEF08v7-wKK3bzsRyCJAJW_B2Y,1964 +social_core/tests/backends/test_twitch.py,sha256=D0kBFo-quf6aTYJhsoVOatvQwiT8CjSjh_GCfCrM88c,2915 +social_core/tests/backends/test_twitter.py,sha256=_hfPwzNQ-A7mY4xl6O_nvLc_WgWqtI-CYVwTunsSWio,9766 +social_core/tests/backends/test_uber.py,sha256=71IAivQAoTG34KZfJ5OQhJDZRytPEqq1GgzuT3sJjbQ,948 +social_core/tests/backends/test_udata.py,sha256=cC-c5LIk1deEYw4iOO7HOG9N2XEscI-we2LGrSH6pIc,848 +social_core/tests/backends/test_universe.py,sha256=J9zoMs_DvmMB-fzg9cuALJyWA7UthEcnnwWBmQ4LUWc,898 +social_core/tests/backends/test_upwork.py,sha256=DIygHZDyqxf40lsSMPSO8ynCM8oNMwhzz88fWowpn9E,1574 +social_core/tests/backends/test_username.py,sha256=ntf-ZCYwn3jZEIXf62ek2nu1AYNfuOHyCNN9kqT3KAE,481 +social_core/tests/backends/test_utils.py,sha256=BxgH6WTdByCc34k-Mbgq_oa7sO78AJaJBnpTjx0_g94,1884 +social_core/tests/backends/test_vault.py,sha256=CsgR3Pj-qCptpmTtCNnwzN8-yWWo7uD6rD1BNQC8YO4,1773 +social_core/tests/backends/test_vk.py,sha256=7J3kO1JIaNnd-C_EkfLuj22shT7q8YdQ2g0xJOq3xxU,862 +social_core/tests/backends/test_wunderlist.py,sha256=fdQvz5W0CAZm465IC7r_2sBbxl0BgdLFgtRtfkcbh1Q,790 +social_core/tests/backends/test_xing.py,sha256=r5oBtBVcsSLgJuBd6B37nGnnrS0rk-lZJuP4exlYDjE,7675 +social_core/tests/backends/test_yahoo.py,sha256=JhotwAk0CPHW3eGZWY-dAQfdiaV3EOOcER0VzXwCLBg,2822 +social_core/tests/backends/test_yammer.py,sha256=_pUJ921Nlii48NTJ8C4XyH3LwNrHCeRSvpgUOUVO4Q8,4115 +social_core/tests/backends/test_yandex.py,sha256=iYZUV2S6IlZ8HRSwvu_Dh5SS55NI2R3DFbcGGSao9Bg,1515 +social_core/tests/backends/test_zoom.py,sha256=ctNbkNnW-vjJnoPolhLnTUDa6okxfLLeXlkhdT6jSyU,2203 +social_core/tests/backends/test_zotero.py,sha256=WkOEK6pqEZQNfAGMFSWyxDY1JPfbH_QPkELgjwxn9Bk,753 +social_core/tests/models.py,sha256=rEAgY0ZMobndR4szCBYMonYzx6HgRz_uqv2ll6cqoBQ,6219 +social_core/tests/pipeline.py,sha256=fKB485Cj_2DBEhPwWdmxD-60kH1xbjZuy9zH-KGfXQc,1198 +social_core/tests/requirements.txt,sha256=tzCtBWHbD4_tW25i_KSHW0-BfEOBp0DtbbZOl874wBA,61 +social_core/tests/strategy.py,sha256=TJvoRcNt_ZXx-237poUw6GaBc3_v1bBm_MPLkGa5QFI,3748 +social_core/tests/test_exceptions.py,sha256=9FxZmcp1LEQNjVUdoolgdYoJg-dlmJnX98Z693HgMoU,3705 +social_core/tests/test_partial.py,sha256=MfFqT9kd5UHYeEzrnz-9M4pciHS_sTCX9Br2_JssggA,4226 +social_core/tests/test_pipeline.py,sha256=oMrmTsPBmCGSy4dOPydzBdnVV8d-b_XDGg3C_Q_q3qs,8685 +social_core/tests/test_storage.py,sha256=pbgJOd_VqM9IP7wpxGlWYJu9mqO_r--Bem6eLxX_MPU,6214 +social_core/tests/test_utils.py,sha256=N1ReKZQm7QzeoO_mORaF1fSjsKx7RQFdofPubJs3nbs,6775 +social_core/tests/testkey.pem,sha256=INCfQP5gVXVTH0rvT2UpERTo6k3PPzXAhFDXVuYds5k,1679 +social_core/utils.py,sha256=MjrqqX5jrSIf5kdN32ECHC2oMrl2xiycMLkB7TV8Fng,9326 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..1f37c02f2eb2e26b306202feaccb31e522b8b169 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d5ecb092233710fea75e3f81e497351f89d465c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_auth_core-4.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +social_core diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ecdb1cef9e02d39efde3996e051ae0a1c65ad08a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__init__.py @@ -0,0 +1 @@ +__version__ = "4.4.0" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f13535de1126280b459784f5907e7ff7f11042e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/actions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/actions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..088f6d550377473496ea6ec961513473eaf090a2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/actions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..660454ba0459dfb90affbd0869312cc6f33d6f2f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/storage.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/storage.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c03a2a8bcf68a83ce4fcb73dfcfa90655ba0c85 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/storage.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/store.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/store.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92c9c008ae794e4083a0e21f562402f7c94facb2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/store.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/strategy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/strategy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ca672fe854f2298493fd796d2027918909deca9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/strategy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8bf45a4e5aeb6a7dae84ee832ee93f98eb528476 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/actions.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/actions.py new file mode 100644 index 0000000000000000000000000000000000000000..2d74149a78f7aa1fbda257d4d61403ca1c6f12ce --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/actions.py @@ -0,0 +1,148 @@ +from urllib.parse import quote + +from .utils import ( + partial_pipeline_data, + sanitize_redirect, + setting_url, + user_is_active, + user_is_authenticated, +) + + +def do_auth(backend, redirect_name="next"): + # Save any defined next value into session + data = backend.strategy.request_data(merge=False) + + # Save extra data into session. + for field_name in backend.setting("FIELDS_STORED_IN_SESSION", []): + if field_name in data: + backend.strategy.session_set(field_name, data[field_name]) + else: + backend.strategy.session_set(field_name, None) + + if redirect_name in data: + # Check and sanitize a user-defined GET/POST next field value + redirect_uri = data[redirect_name] + if backend.setting("SANITIZE_REDIRECTS", True): + allowed_hosts = backend.setting("ALLOWED_REDIRECT_HOSTS", []) + [ + backend.strategy.request_host() + ] + redirect_uri = sanitize_redirect(allowed_hosts, redirect_uri) + backend.strategy.session_set( + redirect_name, redirect_uri or backend.setting("LOGIN_REDIRECT_URL") + ) + return backend.start() + + +def do_complete(backend, login, user=None, redirect_name="next", *args, **kwargs): + data = backend.strategy.request_data() + + is_authenticated = user_is_authenticated(user) + user = user if is_authenticated else None + + partial = partial_pipeline_data(backend, user, *args, **kwargs) + if partial: + user = backend.continue_pipeline(partial) + # clean partial data after usage + backend.strategy.clean_partial_pipeline(partial.token) + else: + user = backend.complete(user=user, *args, **kwargs) + + # pop redirect value before the session is trashed on login(), but after + # the pipeline so that the pipeline can change the redirect if needed + redirect_value = backend.strategy.session_get(redirect_name, "") or data.get( + redirect_name, "" + ) + + # check if the output value is something else than a user and just + # return it to the client + user_model = backend.strategy.storage.user.user_model() + if user and not isinstance(user, user_model): + return user + + if is_authenticated: + if not user: + url = setting_url(backend, redirect_value, "LOGIN_REDIRECT_URL") + else: + url = setting_url( + backend, + redirect_value, + "NEW_ASSOCIATION_REDIRECT_URL", + "LOGIN_REDIRECT_URL", + ) + elif user: + if user_is_active(user): + # catch is_new/social_user in case login() resets the instance + is_new = getattr(user, "is_new", False) + social_user = user.social_user + login(backend, user, social_user) + # store last login backend name in session + backend.strategy.session_set( + "social_auth_last_login_backend", social_user.provider + ) + + if is_new: + url = setting_url( + backend, + "NEW_USER_REDIRECT_URL", + redirect_value, + "LOGIN_REDIRECT_URL", + ) + else: + url = setting_url(backend, redirect_value, "LOGIN_REDIRECT_URL") + else: + if backend.setting("INACTIVE_USER_LOGIN", False): + social_user = user.social_user + login(backend, user, social_user) + url = setting_url( + backend, "INACTIVE_USER_URL", "LOGIN_ERROR_URL", "LOGIN_URL" + ) + else: + url = setting_url(backend, "LOGIN_ERROR_URL", "LOGIN_URL") + + if redirect_value and redirect_value != url: + redirect_value = quote(redirect_value) + url += ("&" if "?" in url else "?") + f"{redirect_name}={redirect_value}" + + if backend.setting("SANITIZE_REDIRECTS", True): + allowed_hosts = backend.setting("ALLOWED_REDIRECT_HOSTS", []) + [ + backend.strategy.request_host() + ] + url = sanitize_redirect(allowed_hosts, url) or backend.setting( + "LOGIN_REDIRECT_URL" + ) + return backend.strategy.redirect(url) + + +def do_disconnect( + backend, user, association_id=None, redirect_name="next", *args, **kwargs +): + partial = partial_pipeline_data(backend, user, *args, **kwargs) + if partial: + if association_id and not partial.kwargs.get("association_id"): + partial.extend_kwargs({"association_id": association_id}) + response = backend.disconnect(*partial.args, **partial.kwargs) + # clean partial data after usage + backend.strategy.clean_partial_pipeline(partial.token) + else: + response = backend.disconnect( + user=user, association_id=association_id, *args, **kwargs + ) + + if isinstance(response, dict): + url = backend.strategy.absolute_uri( + backend.strategy.request_data().get(redirect_name, "") + or backend.setting("DISCONNECT_REDIRECT_URL") + or backend.setting("LOGIN_REDIRECT_URL") + ) + if backend.setting("SANITIZE_REDIRECTS", True): + allowed_hosts = backend.setting("ALLOWED_REDIRECT_HOSTS", []) + [ + backend.strategy.request_host() + ] + url = ( + sanitize_redirect(allowed_hosts, url) + or backend.setting("DISCONNECT_REDIRECT_URL") + or backend.setting("LOGIN_REDIRECT_URL") + ) + response = backend.strategy.redirect(url) + return response diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6aaf51508d4dce70b714c305a3eaa11cb297996 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/amazon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/amazon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9aa7de313587fffcc066f798a52894131478a8af Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/amazon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/angel.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/angel.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b89fc003811b87cd4599b9c83ca5c439464029de Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/angel.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/aol.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/aol.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b8fdf759fe916e53afc12983fe658da070dd561 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/aol.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/apple.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/apple.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7af867fe299a87dd7d2aca59029544afb28b6ebf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/apple.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/appsfuel.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/appsfuel.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d4d575fa520ab5c67c2b486ea71cbb173aadb13 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/appsfuel.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/arcgis.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/arcgis.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbea49c0d5d44ba4948c80d484ad71d91831c739 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/arcgis.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/asana.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/asana.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcd81373938a5bd06d248b5eff59ab612829bc74 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/asana.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/atlassian.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/atlassian.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..645310e94b514f94f3e85d8316c4cc94c2d3d669 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/atlassian.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/auth0.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/auth0.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf5cc4af02edf7c7ca3dc6133de5002d6b45b05d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/auth0.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b267e9a868127c372abae304c12ce4bf6ac69776 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_b2c.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_b2c.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef377b13a5370e372423d933fee0369c89f2a8e9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_b2c.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_tenant.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_tenant.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e17f1d9bb1b9883bbbc6079cf97eecde90ccc275 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/azuread_tenant.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5bc730ac88d8f936c50dc1713c8a5d310daa57de Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/battlenet.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/battlenet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57ee4aa045d28af989f63b1a345b6957faff8679 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/battlenet.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/beats.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/beats.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf125138b395c742bb62a462aa1aaff8997b1661 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/beats.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/behance.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/behance.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0abaaf105c0847a3590c2a347c7a3d5573aaf39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/behance.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/belgiumeid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/belgiumeid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86c12b157575c8fdbd32138f05d5422b7a40f9f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/belgiumeid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bitbucket.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bitbucket.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0016767829f27c440909e50bceb8f1c58c85f1d5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bitbucket.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/box.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/box.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae1185e2a4e108264b5ed036c13c3b4f04398135 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/box.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bungie.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bungie.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..014a93df09935133ddd4c185a35e4c0820782c97 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/bungie.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/changetip.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/changetip.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..522099ecffd13babb999d0cc663e995fcd12f8a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/changetip.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/chatwork.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/chatwork.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f6772c63e752b8021fc15952f0ab6814410ab6a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/chatwork.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cilogon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cilogon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..153f10fe133aeab298f474444ce79886cfe5276f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cilogon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/classlink.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/classlink.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1f5ba409ec3d956b62077eb3c61a4938591c166 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/classlink.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/clef.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/clef.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5c6793651dd4ba38c2e2c69f1f343947f9d7797 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/clef.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coding.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coding.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4c026beb9946500b863077f79dfae36dac17079 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coding.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cognito.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cognito.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9be94800cea6177a8c59285d3a18c907f53c3a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/cognito.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coinbase.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coinbase.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2672f4210cbd59163a82aa87e050a7a8d62f4a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coinbase.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coursera.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coursera.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84789d176f569da095eeb659504d590682fd738b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/coursera.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dailymotion.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dailymotion.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aac6920f10d2754e5765f4b862f8fd20c277022a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dailymotion.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/deezer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/deezer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5ef7d98c3a38d34bfed307a676e70a791cc7617 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/deezer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/digitalocean.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/digitalocean.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de98f5e3e7cfcec6b65649c68f0251ba95c5a850 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/digitalocean.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discord.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discord.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10f750b9e6e8f97861fe7d196b5a14e31770d2dc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discord.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discourse.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discourse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcd7c805ab5027d6a4627d5cd5942ecfddb6df23 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/discourse.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/disqus.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/disqus.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84d57769856a8f053e5ec528c1642d6911b45ed3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/disqus.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/docker.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/docker.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a80d0d42e11d741b38f14e2a5a7c90a7c9aabea8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/docker.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/douban.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/douban.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e55538d59274b366e8bf10a635e6b966b81bc83d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/douban.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dribbble.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dribbble.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de326923d2fd39e53e036d0635c4991aa22e6327 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dribbble.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/drip.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/drip.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d63b0a3158b7546420f754030a0bbe621e9b72b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/drip.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dropbox.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dropbox.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..097da84d54895f505aec8d90f90b5296c2dfb6aa Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/dropbox.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/echosign.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/echosign.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e1276b2987dbff1487734edc440f6833819bad0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/echosign.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/edmodo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/edmodo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6079357b0b2591b23b28ced9a957bdd9ed9cd04a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/edmodo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/elixir.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/elixir.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4ae13d5c5cfec5dcf0223235be5bdc615403206 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/elixir.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/email.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/email.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b933e9bc53bd2db3a05dec430f4ed07262d6d5f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/email.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eventbrite.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eventbrite.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de8e206ce1aca5c89f313ae87e7561077d4e6627 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eventbrite.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eveonline.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eveonline.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90e03dd4895b3b7a0e2cd5d16db2e38026307eee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/eveonline.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/evernote.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/evernote.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9aa003ee5ff796ddfb972e5a167ae29b7dd7aad8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/evernote.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/exacttarget.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/exacttarget.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..304167ea69db02238122bcf22dd6567ce02d1c9f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/exacttarget.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/facebook.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/facebook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2ce04914d361066deffb9da9cf61e334d80ad93 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/facebook.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fedora.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fedora.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e47db86e58380deb78826176205877d096399ad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fedora.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fence.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fence.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ea61cc9565b2831bf9d69ef6207ac43f21422fe Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fence.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fitbit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fitbit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d97493143aaf875b7210b186901005760bdf2709 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/fitbit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/five_hundred_px.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/five_hundred_px.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf03ea58ff621fc4c64bd55f271e2348706cbb30 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/five_hundred_px.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb7c8c87117615165943db912d9478601a2414d4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flickr.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flickr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f51c6b690df1bce07504f74828ce063615d8b97 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/flickr.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/foursquare.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/foursquare.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d28fa90500f6311b1b35b5c75e17da348293afcd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/foursquare.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gae.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gae.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e2635efda4cdd393bc1ef28d5eb7de3ed869f3c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gae.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitea.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitea.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c58b7b106fbae113cfc3a6871e165149bd3b8291 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitea.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fcbbc2250bcf30507d5aaf10f510e10cb7afb9f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github_enterprise.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github_enterprise.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93f507653e309e4f207004204b17b37256d4fd64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/github_enterprise.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitlab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitlab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e743c60303a364c2755f3a482728893a37fc3e67 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/gitlab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/globus.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/globus.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93e0619990e47f3df3278c4f0e3eaddcc74a23f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/globus.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclio.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc036737147a0a741a6b6cb38778eb6406417d3d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclio.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclioeu.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclioeu.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4674b0fea709a2bee5b71bd9a367db32ca972a2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/goclioeu.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b0574c84d144d0cf9d2df505f3d0c7c4a0e1985 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google_openidconnect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google_openidconnect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f6ee5854d20dc82875736f20c24d952572f32ff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/google_openidconnect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/grafana.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/grafana.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6fec701d34f09b25302380a825c734e55eeac0b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/grafana.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/hubspot.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/hubspot.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a00fb58429eae3eae689b48ad43550ebf5a3dac Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/hubspot.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/instagram.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/instagram.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46d387cf1a22e627a04fede01a234e301faffb25 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/instagram.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/itembase.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/itembase.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54486b68e2e2490deae6cb6f28442d56d308810c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/itembase.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/jawbone.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/jawbone.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a64a7132691e70f0c95b83b56782aa31be6705f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/jawbone.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/justgiving.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/justgiving.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa32a085f3a165b2ef9e76889a6b60ec05483719 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/justgiving.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/kakao.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/kakao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3eb9a48b73ea0f7f54a81ec5232221eb9082158 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/kakao.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/keycloak.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/keycloak.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f219081b39d351d1921440e697be87d4d8eb204 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/keycloak.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/khanacademy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/khanacademy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67571f04147ab59bdf9199e0991fefd93ebcdec3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/khanacademy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lastfm.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lastfm.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd26fe9ee05c471cbdaec9924c0d7e72448bb4b8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lastfm.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/launchpad.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/launchpad.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cbe24db31f2d5682b37c6e2c19ff892316763b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/launchpad.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/legacy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/legacy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c6cc5525f69fa4fe9b3597d4f1d2f8669c68af1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/legacy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/line.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/line.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6528a2683c82c74e71761880917caa517a0cec3d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/line.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/linkedin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/linkedin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7956a1a72c9d30be6d65c5b14b2234244db8e1f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/linkedin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/live.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/live.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a3e05b50697a203d7299b78f86d52ecb8a36c04 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/live.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/livejournal.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/livejournal.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5469996a865f66fe367d76007ec0daefe5b72973 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/livejournal.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/loginradius.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/loginradius.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7b3307efd739e9ca73bf6081d95ea86da5272b2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/loginradius.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lyft.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lyft.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bac4a2547af527f453e6e4c91ec5860c432f6a90 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/lyft.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailchimp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailchimp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0978b828fcd3324dbcdca9f763ea29d98847ca85 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailchimp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailru.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailru.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa4f71d6417e486a346ec552eaba71b710566162 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mailru.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mapmyfitness.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mapmyfitness.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e30b03f735cb63854646a8428f174a9a2fadbe53 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mapmyfitness.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mediawiki.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mediawiki.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..484db9e60b8048f720ff9ee90a8633cfa4bec278 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mediawiki.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/meetup.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/meetup.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83676fe34d55869e1a911632e261ecb2d30bbfb2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/meetup.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mendeley.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mendeley.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a47ca5f736150315f53574fad2b6d51fb324868b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mendeley.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/microsoft.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/microsoft.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c68a07299d382427424f054bfc1cefc5bb2ad766 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/microsoft.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mineid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mineid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e83d166b3067c94012ad9ec7caa49825bdd530da Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mineid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mixcloud.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mixcloud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39291f1b4a425c678bc94dbbba06ebcca5aa99fd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/mixcloud.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/monzo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/monzo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6a0f005579c73e256872eebb2ff66b6f3550bc4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/monzo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/moves.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/moves.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12bdc52a084757a926fcda6fea013dcdd8248a9d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/moves.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/musicbrainz.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/musicbrainz.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12328b30cc999acd65eb981610deb178aaeb3c44 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/musicbrainz.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nationbuilder.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nationbuilder.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..359e8def710c51966fa0273b97eb553ee9f8ec13 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nationbuilder.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/naver.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/naver.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9853d3ccf37beb27be312f766a4eb48df5f4b9bb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/naver.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ngpvan.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ngpvan.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..147e0f86388462ff79abd6ca1f0b21272e3eb966 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ngpvan.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nk.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nk.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd6e740d9e93c593af54070fef36fffb12a7c90e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/nk.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/oauth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/oauth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46c3ef6c68ff9779b515ec27267d03203d77c8e7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/oauth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/odnoklassniki.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/odnoklassniki.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e5b2616800ed5da7784cf8d002eadbd6f52be7e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/odnoklassniki.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36a1a96a593a4e7940bd06968d836fd629b7bf55 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta_openidconnect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta_openidconnect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd48018490c303925dc31a2192aa3f9c66de6741 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/okta_openidconnect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..256cdcfc9d3c65bfb07f51b3d290e7f23b8a41f6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id_connect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id_connect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a87ac1e7b73fe2b8fc9057eb01374719b523795f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/open_id_connect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openinfra.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openinfra.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b451125084acd4a8f91ee5ebbecf74c0734fb7b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openinfra.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openshift.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openshift.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b999b4b2ee7ef858d8b7083c05a06680ea7b8253 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openshift.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstack.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstack.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98c3569753d4618220837c8f38377918edab40db Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstack.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstreetmap.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstreetmap.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5da0800decaea4f11d3fcf2cea5a41638ce2c920 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/openstreetmap.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orbi.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orbi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21e82536bd4ed40247122465abf5ad84f69771a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orbi.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orcid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orcid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..086991e478e210707f5b367aee121fad8ae5f2d0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/orcid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/osso.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/osso.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a89bbb5c3f500bab27620e1bb6a1046346bd772 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/osso.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/patreon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/patreon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64e1175a1a3b60c99c2ff23a879ef8665ca31f6f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/patreon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/paypal.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/paypal.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1054fb5eb3c22c181b8c9b3c6786892f2e0c4131 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/paypal.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/persona.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/persona.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26135f876c9462b541c2b6fc1f72304fe33f9691 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/persona.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/phabricator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/phabricator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd89ae709f682613927cb4c9d5c7e765dd4ffc21 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/phabricator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pinterest.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pinterest.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4186720aa52793a7db4a928e9abb8854024fea80 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pinterest.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pixelpin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pixelpin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c38d39dd7fe0e0bec9f5c040ed0fc1a34c9288e2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pixelpin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pocket.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pocket.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a428e051fdc25942ab75cd260fa8788fb6c3d03 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pocket.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/podio.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/podio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ddb227121242bf83da11a7143845b0f5f2880de5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/podio.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/professionali.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/professionali.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16169be63324f5e321d84c1ceb01798eda59e3da Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/professionali.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pushbullet.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pushbullet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..892ba0be2a186260e93b57f23821535063f1edac Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/pushbullet.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qiita.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qiita.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a18c09f7b9c01743f0b7c83852f54ab1b963b9fc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qiita.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qq.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qq.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc28a3f9bb96ed201d7e6210d85782b6ab77cf16 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/qq.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/quizlet.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/quizlet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b010d8a6e96ea7cd195645463905ae31a4fa6053 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/quizlet.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/rdio.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/rdio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98734ba06876c6d92192bf63bfdc292878551ecf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/rdio.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/readability.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/readability.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51bed1abde0b3c38c8454d85cd6d54231d32506b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/readability.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/reddit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/reddit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..201c507ab7fd32af9ad0da3f59f847daa4afd8e8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/reddit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/runkeeper.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/runkeeper.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c55b971add5ba64673eca4ffd0ac8299c1d1d1c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/runkeeper.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/salesforce.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/salesforce.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2c7f0bef1e26d562e35f9a3c63a8727dfe6e172 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/salesforce.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/saml.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/saml.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..568b332712ec5de39a9f585037daa0987f10e01f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/saml.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/scistarter.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/scistarter.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0caa13856ded25d12da8a7ed55fec8071df00ebd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/scistarter.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/seznam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/seznam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49da232a04baee4dcddc42c62135ce77341007ca Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/seznam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shimmering.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shimmering.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad118b9820a7a83b4b1bc1c798b6a66b1754c492 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shimmering.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shopify.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shopify.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da33d806c2164f7ce0be4aeb9f963c535c4f5431 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/shopify.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/simplelogin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/simplelogin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..033166e4ec7e70eddfc99efc8b2848d50bf258ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/simplelogin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/sketchfab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/sketchfab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e8aa89fcd9dfc9caab531915560ee66ab9988f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/sketchfab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/skyrock.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/skyrock.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e10c58690e75b7826978a450f516f9acf529e214 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/skyrock.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/slack.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/slack.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c59f9dbc87355f44e0eb217bade240316c38d39 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/slack.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/soundcloud.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/soundcloud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..276f41359aa989aacdd08ce4e2dd04ee16440e50 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/soundcloud.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/spotify.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/spotify.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..383dda47573e06d7ac244ca3678361766a3dc22d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/spotify.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stackoverflow.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stackoverflow.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be5e3096f5f8a87fe744c49b6897b119f983f0fc Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stackoverflow.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/steam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/steam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a83f7416cae2473255f25b11eacd3c1e7acfb844 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/steam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stocktwits.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stocktwits.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0710f131f517720b58bdb3c62d0f0f347042ca48 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stocktwits.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/strava.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/strava.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9a7fe3572c24b9f89c8cec1c9e86087d5432dcf Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/strava.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stripe.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stripe.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5b7b46b2f45424efea4508a1ee88b716b6105e3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/stripe.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/surveymonkey.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/surveymonkey.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..843724701e14d4e5c6b072ba5f47326e03cdec23 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/surveymonkey.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/suse.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/suse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..329418c12705a957a1a4af235a628fa11daa1722 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/suse.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/taobao.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/taobao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f755c4a62f7192f4fa6e79fdc09108b39d404a8e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/taobao.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/telegram.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/telegram.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb6693190c663df01f195322d1263ebd2db51d4f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/telegram.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/thisismyjam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/thisismyjam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64edb856a1a4386850f9f46484ab45573afe8082 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/thisismyjam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/trello.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/trello.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ec45e61103f61a1266632a40db4566042357479 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/trello.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tripit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tripit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d430b33039e07643e9712b20f17e92c79c47c10 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tripit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tumblr.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tumblr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4502b943dc94a54d0284623ad8ace2f9ef46c7e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/tumblr.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twilio.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twilio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b35f9e352802ab219cdba4c1ed54082695ab5c7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twilio.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitch.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitch.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af5b332f33baeffada9632f3599fe6b0c6411928 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitch.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitter.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitter.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e4a51e99987125c63b11c276d7809cc536a8956 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/twitter.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/uber.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/uber.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9feaacdd83b95e8f67f9802e50ea6c7e1dfde460 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/uber.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ubuntu.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ubuntu.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..146bffc6eca91fe595ae3a3f94d8e475e20af283 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/ubuntu.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/udata.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/udata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2761c4e52141e8d67a7a7c9e2c3994ebe54f21b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/udata.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/universe.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/universe.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87e7aa79de54ab3e73a5e8f40c6fa22775f473ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/universe.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/untappd.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/untappd.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc7aad0bd1be1052ed87290df89c8cf92c06f3f5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/untappd.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/upwork.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/upwork.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a009f19b876b8217c720da969cd4b32f077ef254 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/upwork.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/username.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/username.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a53fbf075e6ec9ef4578fb86bd9a0705016951f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/username.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23d785f4fe388053135d5ff5b5003a2135630218 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vault.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vault.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b886a51dcb3be7146bef15697fb74a2765f0ce9f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vault.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vend.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vend.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c473fe712542d59b3c97357d6c9cf45e8c440f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vend.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vimeo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vimeo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf90daefa192b4a4d61497608fed88ca73abb7b7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vimeo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vk.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vk.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dd014a5a603670f721022c267845acd1c4ee603 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/vk.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weibo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weibo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ac7058c08cc1a7137ea4bdbc9252c572cdee6a9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weibo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weixin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weixin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3ec1ddf5e32685f2bed247c3ffc4b654708a234 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/weixin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/withings.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/withings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f1cba8ea8b30d0813b136dc40be01087d767a8a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/withings.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/wunderlist.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/wunderlist.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..607dfe08a0188e1b77d1491114d14a2b92ffeb0e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/wunderlist.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/xing.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/xing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd1ad3874c165603ef3d84c72b1e96d4b43dd4d1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/xing.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yahoo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yahoo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97f1c1538222905b66fdf8d170f54d8524ac2dee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yahoo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yammer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yammer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6cb37de521a3ab2eccfc3f9a839eab3566bb5ce Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yammer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yandex.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yandex.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aaed52a9050f83733cdcaf3a94436c7bd006c292 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/yandex.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zoom.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zoom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c9efa25898fa2a038764297f09ce8b47e007850 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zoom.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zotero.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zotero.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84e983a3d05df20428821dfeed2be2dd38dca839 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/__pycache__/zotero.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/amazon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/amazon.py new file mode 100644 index 0000000000000000000000000000000000000000..18b1e65110b403c2923ba20736a2c3c478516ba6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/amazon.py @@ -0,0 +1,46 @@ +""" +Amazon OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/amazon.html +""" + +from .oauth import BaseOAuth2 + + +class AmazonOAuth2(BaseOAuth2): + name = "amazon" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://www.amazon.com/ap/oa" + ACCESS_TOKEN_URL = "https://api.amazon.com/auth/o2/token" + DEFAULT_SCOPE = ["profile"] + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("user_id", "user_id"), + ("postal_code", "postal_code"), + ] + + def get_user_details(self, response): + """Return user details from amazon account""" + name = response.get("name") or "" + fullname, first_name, last_name = self.get_user_names(name) + return { + "username": name, + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Grab user profile information from amazon.""" + response = self.get_json( + "https://api.amazon.com/user/profile", params={"access_token": access_token} + ) + if "Profile" in response: + response = { + "user_id": response["Profile"]["CustomerId"], + "name": response["Profile"]["Name"], + "email": response["Profile"]["PrimaryEmail"], + } + return response diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/angel.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/angel.py new file mode 100644 index 0000000000000000000000000000000000000000..4793c4bdfcb639edcf3f8ff0f4d090c7061da018 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/angel.py @@ -0,0 +1,32 @@ +""" +Angel OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/angel.html +""" +from .oauth import BaseOAuth2 + + +class AngelOAuth2(BaseOAuth2): + name = "angel" + AUTHORIZATION_URL = "https://angel.co/api/oauth/authorize/" + ACCESS_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://angel.co/api/oauth/token/" + REDIRECT_STATE = False + + def get_user_details(self, response): + """Return user details from Angel account""" + username = response["angellist_url"].split("/")[-1] + email = response.get("email", "") + fullname, first_name, last_name = self.get_user_names(response["name"]) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.angel.co/1/me/", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/aol.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/aol.py new file mode 100644 index 0000000000000000000000000000000000000000..511c42cffccd5d4ec13bdcdaf7c32c8981f8817d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/aol.py @@ -0,0 +1,10 @@ +""" +AOL OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/aol.html +""" +from .open_id import OpenIdAuth + + +class AOLOpenId(OpenIdAuth): + name = "aol" + URL = "http://openid.aol.com" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/apple.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/apple.py new file mode 100644 index 0000000000000000000000000000000000000000..75b8349472badbfa76d201b3ecaf44861af6ce9c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/apple.py @@ -0,0 +1,167 @@ +""" +Sign In With Apple authentication backend. + +Docs: + * https://developer.apple.com/documentation/signinwithapplerestapi + * https://developer.apple.com/documentation/signinwithapplerestapi/tokenresponse + +Settings: + * `TEAM` - your team id; + * `KEY` - your key id; + * `CLIENT` - your client id; + * `AUDIENCE` - a list of authorized client IDs, defaults to [CLIENT]. + Use this if you need to accept both service and bundle id to + be able to login both via iOS and ie a web form. + * `SECRET` - your secret key; + * `SCOPE` (optional) - e.g. `['name', 'email']`; + * `EMAIL_AS_USERNAME` - use apple email is username is set, use apple id + otherwise. + * `AppleIdAuth.TOKEN_TTL_SEC` - time before JWT token expiration, seconds. + * `SOCIAL_AUTH_APPLE_ID_INACTIVE_USER_LOGIN` - allow inactive users email to + login +""" + +import json +import time + +import jwt +from jwt.algorithms import RSAAlgorithm +from jwt.exceptions import PyJWTError + +from social_core.backends.oauth import BaseOAuth2 +from social_core.exceptions import AuthFailed + + +class AppleIdAuth(BaseOAuth2): + name = "apple-id" + + JWK_URL = "https://appleid.apple.com/auth/keys" + AUTHORIZATION_URL = "https://appleid.apple.com/auth/authorize" + ACCESS_TOKEN_URL = "https://appleid.apple.com/auth/token" + ACCESS_TOKEN_METHOD = "POST" + RESPONSE_MODE = None + + ID_KEY = "sub" + TOKEN_KEY = "id_token" + STATE_PARAMETER = True + REDIRECT_STATE = False + SCOPE_SEPARATOR = "%20" + + TOKEN_AUDIENCE = "https://appleid.apple.com" + TOKEN_TTL_SEC = 6 * 30 * 24 * 60 * 60 + + def get_audience(self): + client_id = self.setting("CLIENT") + return self.setting("AUDIENCE", default=[client_id]) + + def auth_params(self, *args, **kwargs): + """ + Apple requires to set `response_mode` to `form_post` if `scope` + parameter is passed. + """ + params = super().auth_params(*args, **kwargs) + if self.RESPONSE_MODE: + params["response_mode"] = self.RESPONSE_MODE + elif self.get_scope(): + params["response_mode"] = "form_post" + return params + + def get_private_key(self): + """ + Return contents of the private key file. Override this method to provide + secret key from another source if needed. + """ + return self.setting("SECRET") + + def generate_client_secret(self): + now = int(time.time()) + client_id = self.setting("CLIENT") + team_id = self.setting("TEAM") + key_id = self.setting("KEY") + private_key = self.get_private_key() + + headers = {"kid": key_id} + payload = { + "iss": team_id, + "iat": now, + "exp": now + self.TOKEN_TTL_SEC, + "aud": self.TOKEN_AUDIENCE, + "sub": client_id, + } + + return jwt.encode(payload, key=private_key, algorithm="ES256", headers=headers) + + def get_key_and_secret(self): + client_id = self.setting("CLIENT") + client_secret = self.generate_client_secret() + return client_id, client_secret + + def get_apple_jwk(self, kid=None): + """ + Return requested Apple public key or all available. + """ + keys = self.get_json(url=self.JWK_URL).get("keys") + + if not isinstance(keys, list) or not keys: + raise AuthFailed(self, "Invalid jwk response") + + if kid: + return json.dumps([key for key in keys if key["kid"] == kid][0]) + else: + return (json.dumps(key) for key in keys) + + def decode_id_token(self, id_token): + """ + Decode and validate JWT token from apple and return payload including + user data. + """ + if not id_token: + raise AuthFailed(self, "Missing id_token parameter") + + try: + kid = jwt.get_unverified_header(id_token).get("kid") + public_key = RSAAlgorithm.from_jwk(self.get_apple_jwk(kid)) + decoded = jwt.decode( + id_token, + key=public_key, + audience=self.get_audience(), + algorithms=["RS256"], + ) + except PyJWTError as error: + raise AuthFailed(self, f"Token validation failed by {error}") + + return decoded + + def get_user_details(self, response): + name = json.loads(self.data.get("user", "{}")).get("name", {}) + fullname, first_name, last_name = self.get_user_names( + fullname="", + first_name=name.get("firstName", ""), + last_name=name.get("lastName", ""), + ) + + email = response.get("email", "") + apple_id = response.get(self.ID_KEY, "") + # prevent updating User with empty strings + user_details = { + "fullname": fullname or None, + "first_name": first_name or None, + "last_name": last_name or None, + "email": email, + } + if email and self.setting("EMAIL_AS_USERNAME"): + user_details["username"] = email + if apple_id and not self.setting("EMAIL_AS_USERNAME"): + user_details["username"] = apple_id + + return user_details + + def do_auth(self, access_token, *args, **kwargs): + response = kwargs.pop("response", None) or {} + jwt_string = response.get(self.TOKEN_KEY) or access_token + + if not jwt_string: + raise AuthFailed(self, "Missing id_token parameter") + + decoded_data = self.decode_id_token(jwt_string) + return super().do_auth(access_token, response=decoded_data, *args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/appsfuel.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/appsfuel.py new file mode 100644 index 0000000000000000000000000000000000000000..29f1e400b636ba2dc9e55f568d9fcd11d4401f82 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/appsfuel.py @@ -0,0 +1,42 @@ +""" +Appsfueld OAuth2 backend (with sandbox mode support), docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/appsfuel.html +""" +from .oauth import BaseOAuth2 + + +class AppsfuelOAuth2(BaseOAuth2): + name = "appsfuel" + ID_KEY = "user_id" + AUTHORIZATION_URL = "http://app.appsfuel.com/content/permission" + ACCESS_TOKEN_URL = "https://api.appsfuel.com/v1/live/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + USER_DETAILS_URL = "https://api.appsfuel.com/v1/live/user" + + def get_user_details(self, response): + """Return user details from Appsfuel account""" + email = response.get("email", "") + username = email.split("@")[0] if email else "" + fullname, first_name, last_name = self.get_user_names( + response.get("display_name", "") + ) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.USER_DETAILS_URL, params={"access_token": access_token} + ) + + +class AppsfuelOAuth2Sandbox(AppsfuelOAuth2): + name = "appsfuel-sandbox" + AUTHORIZATION_URL = "https://api.appsfuel.com/v1/sandbox/choose" + ACCESS_TOKEN_URL = "https://api.appsfuel.com/v1/sandbox/oauth/token" + USER_DETAILS_URL = "https://api.appsfuel.com/v1/sandbox/user" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/arcgis.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/arcgis.py new file mode 100644 index 0000000000000000000000000000000000000000..03e4e691a300a11c9153ad898f605b4d1409428d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/arcgis.py @@ -0,0 +1,30 @@ +""" +ArcGIS OAuth2 backend +""" +from .oauth import BaseOAuth2 + + +class ArcGISOAuth2(BaseOAuth2): + name = "arcgis" + ID_KEY = "username" + AUTHORIZATION_URL = "https://www.arcgis.com/sharing/rest/oauth2/authorize" + ACCESS_TOKEN_URL = "https://www.arcgis.com/sharing/rest/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("expires_in", "expires_in"), ("refresh_token", "refresh_token")] + + def get_user_details(self, response): + """Return user details from ArcGIS account""" + return { + "username": response.get("username"), + "email": response.get("email"), + "fullname": response.get("fullName"), + "first_name": response.get("firstName"), + "last_name": response.get("lastName"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://www.arcgis.com/sharing/rest/community/self", + params={"token": access_token, "f": "json"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/asana.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/asana.py new file mode 100644 index 0000000000000000000000000000000000000000..0fb413e8f2aac40f73cb800fc821095f61a27f6d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/asana.py @@ -0,0 +1,43 @@ +import datetime + +from .oauth import BaseOAuth2 + + +class AsanaOAuth2(BaseOAuth2): + name = "asana" + AUTHORIZATION_URL = "https://app.asana.com/-/oauth_authorize" + ACCESS_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://app.asana.com/-/oauth_token" + REFRESH_TOKEN_URL = "https://app.asana.com/-/oauth_token" + REDIRECT_STATE = False + USER_DATA_URL = "https://app.asana.com/api/1.0/users/me" + EXTRA_DATA = [ + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ("name", "name"), + ] + + def get_user_details(self, response): + data = response["data"] + fullname, first_name, last_name = self.get_user_names(data["name"]) + return { + "email": data["email"], + "username": data["email"], + "fullname": fullname, + "last_name": last_name, + "first_name": first_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + self.USER_DATA_URL, headers={"Authorization": f"Bearer {access_token}"} + ) + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + data = super().extra_data(user, uid, response, details) + if self.setting("ESTIMATE_EXPIRES_ON"): + expires_on = datetime.datetime.utcnow() + datetime.timedelta( + seconds=data["expires"] + ) + data["expires_on"] = expires_on.isoformat() + return data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/atlassian.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/atlassian.py new file mode 100644 index 0000000000000000000000000000000000000000..2c3e1a4c15827f95a469bf6c87a8ad03e207108e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/atlassian.py @@ -0,0 +1,44 @@ +from social_core.backends.oauth import BaseOAuth2 + + +class AtlassianOAuth2(BaseOAuth2): + name = "atlassian" + AUTHORIZATION_URL = "https://auth.atlassian.com/authorize" + ACCESS_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://auth.atlassian.com/oauth/token" + DEFAULT_SCOPE = ["read:jira-user", "offline_access"] + ID_KEY = "accountId" + EXTRA_DATA = [ + ("resources", "resources"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires_in"), + ] + + def auth_params(self, state=None): + params = super().auth_params(state) + params.update({"audience": "api.atlassian.com", "prompt": "consent"}) + return params + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names(response["displayName"]) + return { + "username": response["name"], + "email": response["emailAddress"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + resources = self.get_json( + "https://api.atlassian.com/oauth/token/accessible-resources", + headers={"Authorization": f"Bearer {access_token}"}, + ) + user_info = self.get_json( + "https://api.atlassian.com/ex/jira/{}/rest/api/2/myself".format( + resources[0]["id"] + ), + headers={"Authorization": f"Bearer {access_token}"}, + ) + user_info["resources"] = resources + return user_info diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/auth0.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/auth0.py new file mode 100644 index 0000000000000000000000000000000000000000..14eef639f7d18dfefd526961430265bc9fd635a1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/auth0.py @@ -0,0 +1,53 @@ +""" +Auth0 implementation based on: +https://auth0.com/docs/quickstart/webapp/django/01-login +""" +from jose import jwt + +from .oauth import BaseOAuth2 + + +class Auth0OAuth2(BaseOAuth2): + """Auth0 OAuth authentication backend""" + + name = "auth0" + SCOPE_SEPARATOR = " " + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("picture", "picture")] + + def api_path(self, path=""): + """Build API path for Auth0 domain""" + return "https://{domain}/{path}".format( + domain=self.setting("DOMAIN"), path=path + ) + + def authorization_url(self): + return self.api_path("authorize") + + def access_token_url(self): + return self.api_path("oauth/token") + + def get_user_id(self, details, response): + """Return current user id.""" + return details["user_id"] + + def get_user_details(self, response): + # Obtain JWT and the keys to validate the signature + id_token = response.get("id_token") + jwks = self.get_json(self.api_path(".well-known/jwks.json")) + issuer = self.api_path() + audience = self.setting("KEY") # CLIENT_ID + payload = jwt.decode( + id_token, jwks, algorithms=["RS256"], audience=audience, issuer=issuer + ) + fullname, first_name, last_name = self.get_user_names(payload["name"]) + return { + "username": payload["nickname"], + "email": payload["email"], + "email_verified": payload.get("email_verified", False), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "picture": payload["picture"], + "user_id": payload["sub"], + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread.py new file mode 100644 index 0000000000000000000000000000000000000000..837d2c54674c5039f2f6a50d0bb2becaa785721d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread.py @@ -0,0 +1,147 @@ +import time + +import jwt + +from ..exceptions import AuthTokenError +from .oauth import BaseOAuth2 + +""" +Copyright (c) 2015 Microsoft Open Technologies, Inc. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +""" +Azure AD OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/azuread.html +""" + + +class AzureADOAuth2(BaseOAuth2): + name = "azuread-oauth2" + SCOPE_SEPARATOR = " " + BASE_URL = "https://{authority_host}/{tenant_id}" + AUTHORIZATION_URL = "{base_url}/oauth2/authorize" + ACCESS_TOKEN_URL = "{base_url}/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + DEFAULT_SCOPE = ["openid", "profile", "user_impersonation", "email"] + EXTRA_DATA = [ + ("access_token", "access_token"), + ("id_token", "id_token"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires"), + ("expires_on", "expires_on"), + ("not_before", "not_before"), + ("given_name", "first_name"), + ("family_name", "last_name"), + ("token_type", "token_type"), + ] + + @property + def authority_host(self): + return self.setting("AUTHORITY_HOST", "login.microsoftonline.com") + + @property + def tenant_id(self): + return "common" + + @property + def base_url(self): + return self.BASE_URL.format( + authority_host=self.authority_host, tenant_id=self.tenant_id + ) + + def authorization_url(self): + return self.AUTHORIZATION_URL.format(base_url=self.base_url) + + def access_token_url(self): + return self.ACCESS_TOKEN_URL.format(base_url=self.base_url) + + def get_user_id(self, details, response): + """Use upn as unique id""" + return response.get("upn") + + def get_user_details(self, response): + """Return user details from Azure AD account""" + fullname, first_name, last_name = ( + response.get("name", ""), + response.get("given_name", ""), + response.get("family_name", ""), + ) + return { + "username": fullname, + "email": response.get("email", response.get("upn")), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + response = kwargs.get("response") + if response and response.get("id_token"): + id_token = response.get("id_token") + else: + id_token = access_token + + try: + decoded_id_token = jwt.decode(id_token, options={"verify_signature": False}) + except (jwt.DecodeError, jwt.ExpiredSignatureError) as de: + raise AuthTokenError(self, de) + return decoded_id_token + + def auth_extra_arguments(self): + """Return extra arguments needed on auth process. The defaults can be + overridden by GET parameters.""" + extra_arguments = super().auth_extra_arguments() + resource = self.setting("RESOURCE") + if resource: + extra_arguments.update({"resource": resource}) + return extra_arguments + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return access_token and extra defined names to store in + extra_data field""" + data = super().extra_data(user, uid, response, details, *args, **kwargs) + data["resource"] = self.setting("RESOURCE") + return data + + def refresh_token_params(self, token, *args, **kwargs): + return { + "client_id": self.setting("KEY"), + "client_secret": self.setting("SECRET"), + "refresh_token": token, + "grant_type": "refresh_token", + "resource": self.setting("RESOURCE"), + } + + def get_auth_token(self, user_id): + """Return the access token for the given user, after ensuring that it + has not expired, or refreshing it if so.""" + user = self.get_user(user_id=user_id) + access_token = user.social_user.access_token + expires_on = user.social_user.extra_data["expires_on"] + if expires_on <= int(time.time()): + new_token_response = self.refresh_token(token=access_token) + access_token = new_token_response["access_token"] + return access_token diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_b2c.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_b2c.py new file mode 100644 index 0000000000000000000000000000000000000000..fa2c3edea44d95d94570da1d4f028f7ad667c6e0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_b2c.py @@ -0,0 +1,184 @@ +""" +Copyright (c) 2018 Noderabbit Inc., d.b.a. Appsembler + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +See https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx + for verifying JWT tokens. +""" + +import json + +from cryptography.hazmat.primitives import serialization +from jwt import DecodeError, ExpiredSignatureError +from jwt import decode as jwt_decode +from jwt import get_unverified_header + +try: + from jwt.algorithms import RSAAlgorithm +except ImportError: + raise Exception( + # Python 3.3 is not supported because of compatibility in + # Cryptography package in Python3.3 You are welcome to patch + # and open a pull request. + "Cryptography library is required for this backend " + "(AzureADB2COAuth2) to work. Note that this backend is only " + "supported on Python 2 and Python 3.4+." + ) + +from ..exceptions import AuthException, AuthTokenError +from .azuread import AzureADOAuth2 + + +class AzureADB2COAuth2(AzureADOAuth2): + name = "azuread-b2c-oauth2" + + AUTHORIZATION_URL = "{base_url}/oauth2/v2.0/authorize" + OPENID_CONFIGURATION_URL = ( + "{base_url}/v2.0/.well-known/openid-configuration?p={policy}" + ) + ACCESS_TOKEN_URL = "{base_url}/oauth2/v2.0/token?p={policy}" + JWKS_URL = "{base_url}/discovery/v2.0/keys?p={policy}" + DEFAULT_SCOPE = ["openid", "email"] + EXTRA_DATA = [ + ("access_token", "access_token"), + ("id_token", "id_token"), + ("refresh_token", "refresh_token"), + ("id_token_expires_in", "expires"), + ("exp", "expires_on"), + ("not_before", "not_before"), + ("given_name", "first_name"), + ("family_name", "last_name"), + ("tfp", "policy"), + ("token_type", "token_type"), + ] + + @property + def tenant_id(self): + return self.setting("TENANT_ID", "common") + + @property + def policy(self): + policy = self.setting("POLICY") + if not policy or not policy.lower().startswith("b2c_"): + raise AuthException( + "SOCIAL_AUTH_AZUREAD_B2C_OAUTH2_POLICY is " + "required and should start with `b2c_`" + ) + return policy + + def openid_configuration_url(self): + return self.OPENID_CONFIGURATION_URL.format( + base_url=self.base_url, policy=self.policy + ) + + def authorization_url(self): + # Policy is required, but added later by `auth_extra_arguments()` + return self.AUTHORIZATION_URL.format(base_url=self.base_url) + + def access_token_url(self): + return self.ACCESS_TOKEN_URL.format(base_url=self.base_url, policy=self.policy) + + def jwks_url(self): + return self.JWKS_URL.format(base_url=self.base_url, policy=self.policy) + + def request_access_token(self, *args, **kwargs): + """ + This is probably a hack, but otherwise AzureADOAuth2 expects + `access_token`. + + However, B2C backends provides `id_token`. + """ + response = super().request_access_token(*args, **kwargs) + if "access_token" not in response: + response["access_token"] = response["id_token"] + return response + + def auth_extra_arguments(self): + """ + Return extra arguments needed on auth process. + + The defaults can be overridden by GET parameters. + """ + extra_arguments = super().auth_extra_arguments() + extra_arguments["p"] = self.policy or self.data.get("p") + return extra_arguments + + def jwt_key_to_pem(self, key_json_dict): + """ + Builds a PEM formatted key string from a JWT public key dict. + """ + pub_key = RSAAlgorithm.from_jwk(json.dumps(key_json_dict)) + return pub_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + + def get_user_id(self, details, response): + """Use subject (sub) claim as unique id.""" + return response.get("sub") + + def get_user_details(self, response): + """ + Email address is returned on a different attribute for AzureAD + B2C backends. + """ + details = super().get_user_details(response) + if not details["email"] and response.get("emails"): + details["email"] = response["emails"] + if isinstance(details.get("email"), (list, tuple)): + details["email"] = details["email"][0] + return details + + def get_public_key(self, kid): + """ + Retrieve JWT keys from the URL. + """ + resp = self.request(self.jwks_url(), method="GET") + resp.raise_for_status() + + # find the proper key for the kid + for key in resp.json()["keys"]: + if key["kid"] == kid: + return self.jwt_key_to_pem(key) + raise DecodeError(f"Cannot find kid={kid}") + + def user_data(self, access_token, *args, **kwargs): + response = kwargs.get("response") + + id_token = response.get("id_token") + + # `kid` is short for key id + kid = get_unverified_header(id_token)["kid"] + key = self.get_public_key(kid) + + try: + return jwt_decode( + id_token, + key=key, + algorithms=["RS256"], + audience=self.setting("KEY"), + leeway=self.setting("JWT_LEEWAY", default=0), + ) + except (DecodeError, ExpiredSignatureError) as error: + raise AuthTokenError(self, error) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_tenant.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_tenant.py new file mode 100644 index 0000000000000000000000000000000000000000..ab3830803b9a2d150536466817509477fabe783e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/azuread_tenant.py @@ -0,0 +1,127 @@ +import base64 + +from cryptography.hazmat.backends import default_backend +from cryptography.x509 import load_der_x509_certificate +from jwt import DecodeError, ExpiredSignatureError +from jwt import decode as jwt_decode +from jwt import get_unverified_header + +from ..exceptions import AuthTokenError +from .azuread import AzureADOAuth2 + +""" +Copyright (c) 2015 Microsoft Open Technologies, Inc. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +""" +Azure AD OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/azuread.html + +See https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx +for verifying JWT tokens. +""" + + +class AzureADTenantOAuth2(AzureADOAuth2): + name = "azuread-tenant-oauth2" + OPENID_CONFIGURATION_URL = "{base_url}/.well-known/openid-configuration" + JWKS_URL = "{base_url}/discovery/keys" + + @property + def tenant_id(self): + return self.setting("TENANT_ID", "common") + + def openid_configuration_url(self): + return self.OPENID_CONFIGURATION_URL.format(base_url=self.base_url) + + def jwks_url(self): + return self.JWKS_URL.format(base_url=self.base_url) + + def get_certificate(self, kid): + # retrieve keys from jwks_url + resp = self.request(self.jwks_url(), method="GET") + resp.raise_for_status() + + # find the proper key for the kid + for key in resp.json()["keys"]: + if key["kid"] == kid: + x5c = key["x5c"][0] + break + else: + raise DecodeError(f"Cannot find kid={kid}") + + return load_der_x509_certificate(base64.b64decode(x5c), default_backend()) + + def get_user_id(self, details, response): + """Use subject (sub) claim as unique id.""" + return response.get("sub") + + def user_data(self, access_token, *args, **kwargs): + response = kwargs.get("response") + id_token = response.get("id_token") + + # get key id and algorithm + key_id = get_unverified_header(id_token)["kid"] + + try: + # retrieve certificate for key_id + certificate = self.get_certificate(key_id) + + return jwt_decode( + id_token, + key=certificate.public_key(), + algorithms=["RS256"], + audience=self.setting("KEY"), + ) + except (DecodeError, ExpiredSignatureError) as error: + raise AuthTokenError(self, error) + + +class AzureADV2TenantOAuth2(AzureADTenantOAuth2): + name = "azuread-v2-tenant-oauth2" + OPENID_CONFIGURATION_URL = "{base_url}/v2.0/.well-known/openid-configuration" + AUTHORIZATION_URL = "{base_url}/oauth2/v2.0/authorize" + ACCESS_TOKEN_URL = "{base_url}/oauth2/v2.0/token" + JWKS_URL = "{base_url}/discovery/v2.0/keys" + DEFAULT_SCOPE = ["openid", "profile", "offline_access"] + + def get_user_id(self, details, response): + """Use upn as unique id""" + return response.get("preferred_username") + + def get_user_details(self, response): + """Return user details from Azure AD account""" + fullname, first_name, last_name = ( + response.get("name", ""), + response.get("given_name", ""), + response.get("family_name", ""), + ) + return { + "username": fullname, + "email": response.get("preferred_username"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/base.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/base.py new file mode 100644 index 0000000000000000000000000000000000000000..ba924e42e11f5f6f87e7e53ccd7a69c691a96b60 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/base.py @@ -0,0 +1,259 @@ +import time + +from requests import ConnectionError, request + +from ..exceptions import AuthFailed +from ..utils import SSLHttpAdapter, module_member, parse_qs, user_agent + + +class BaseAuth: + """A authentication backend that authenticates the user based on + the provider response""" + + name = "" # provider name, it's stored in database + supports_inactive_user = False # Django auth + ID_KEY = None + EXTRA_DATA = None + GET_ALL_EXTRA_DATA = False + REQUIRES_EMAIL_VALIDATION = False + SEND_USER_AGENT = False + SSL_PROTOCOL = None + + def __init__(self, strategy, redirect_uri=None): + self.strategy = strategy + self.redirect_uri = redirect_uri + self.data = self.strategy.request_data() + self.redirect_uri = self.strategy.absolute_uri(self.redirect_uri) + + def setting(self, name, default=None): + """Return setting value from strategy""" + return self.strategy.setting(name, default=default, backend=self) + + def start(self): + if self.uses_redirect(): + return self.strategy.redirect(self.auth_url()) + else: + return self.strategy.html(self.auth_html()) + + def complete(self, *args, **kwargs): + return self.auth_complete(*args, **kwargs) + + def auth_url(self): + """Must return redirect URL to auth provider""" + raise NotImplementedError("Implement in subclass") + + def auth_html(self): + """Must return login HTML content returned by provider""" + raise NotImplementedError("Implement in subclass") + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + raise NotImplementedError("Implement in subclass") + + def process_error(self, data): + """Process data for errors, raise exception if needed. + Call this method on any override of auth_complete.""" + pass + + def authenticate(self, *args, **kwargs): + """Authenticate user using social credentials + + Authentication is made if this is the correct backend, backend + verification is made by kwargs inspection for current backend + name presence. + """ + # Validate backend and arguments. Require that the Social Auth + # response be passed in as a keyword argument, to make sure we + # don't match the username/password calling conventions of + # authenticate. + if ( + "backend" not in kwargs + or kwargs["backend"].name != self.name + or "strategy" not in kwargs + or "response" not in kwargs + ): + return None + + self.strategy = kwargs.get("strategy") or self.strategy + self.redirect_uri = kwargs.get("redirect_uri") or self.redirect_uri + self.data = self.strategy.request_data() + kwargs.setdefault("is_new", False) + pipeline = self.strategy.get_pipeline(self) + args, kwargs = self.strategy.clean_authenticate_args(*args, **kwargs) + return self.pipeline(pipeline, *args, **kwargs) + + def pipeline(self, pipeline, pipeline_index=0, *args, **kwargs): + out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs) + if not isinstance(out, dict): + return out + user = out.get("user") + if user: + user.social_user = out.get("social") + user.is_new = out.get("is_new") + return user + + def disconnect(self, *args, **kwargs): + pipeline = self.strategy.get_disconnect_pipeline(self) + kwargs["name"] = self.name + kwargs["user_storage"] = self.strategy.storage.user + return self.run_pipeline(pipeline, *args, **kwargs) + + def run_pipeline(self, pipeline, pipeline_index=0, *args, **kwargs): + out = kwargs.copy() + out.setdefault("strategy", self.strategy) + out.setdefault("backend", out.pop(self.name, None) or self) + out.setdefault("request", self.strategy.request_data()) + out.setdefault("details", {}) + + if ( + not isinstance(pipeline_index, int) + or pipeline_index < 0 + or pipeline_index >= len(pipeline) + ): + pipeline_index = 0 + + for idx, name in enumerate(pipeline[pipeline_index:]): + out["pipeline_index"] = pipeline_index + idx + func = module_member(name) + result = func(*args, **out) or {} + if not isinstance(result, dict): + return result + out.update(result) + return out + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return default extra data to store in extra_data field""" + data = { + # store the last time authentication toke place + "auth_time": int(time.time()) + } + extra_data_entries = [] + if self.GET_ALL_EXTRA_DATA or self.setting("GET_ALL_EXTRA_DATA", False): + extra_data_entries = response.keys() + else: + extra_data_entries = (self.EXTRA_DATA or []) + self.setting( + "EXTRA_DATA", [] + ) + for entry in extra_data_entries: + if not isinstance(entry, (list, tuple)): + entry = (entry,) + size = len(entry) + if size >= 1 and size <= 3: + if size == 3: + name, alias, discard = entry + elif size == 2: + (name, alias), discard = entry, False + elif size == 1: + name = alias = entry[0] + discard = False + value = response.get(name) or details.get(name) or details.get(alias) + if discard and not value: + continue + data[alias] = value + return data + + def auth_allowed(self, response, details): + """Return True if the user should be allowed to authenticate, by + default check if email is whitelisted (if there's a whitelist)""" + emails = [email.lower() for email in self.setting("WHITELISTED_EMAILS", [])] + domains = [domain.lower() for domain in self.setting("WHITELISTED_DOMAINS", [])] + email = details.get("email") + allowed = True + if email and (emails or domains): + email = email.lower() + domain = email.split("@", 1)[1] + allowed = email in emails or domain in domains + return allowed + + def get_user_id(self, details, response): + """Return a unique ID for the current user, by default from server + response.""" + return response.get(self.ID_KEY) + + def get_user_details(self, response): + """Must return user details in a know internal struct: + {'username': <username if any>, + 'email': <user email if any>, + 'fullname': <user full name if any>, + 'first_name': <user first name if any>, + 'last_name': <user last name if any>} + """ + raise NotImplementedError("Implement in subclass") + + def get_user_names(self, fullname="", first_name="", last_name=""): + # Avoid None values + fullname = fullname or "" + first_name = first_name or "" + last_name = last_name or "" + if fullname and not (first_name or last_name): + try: + first_name, last_name = fullname.split(" ", 1) + except ValueError: + first_name = first_name or fullname or "" + last_name = last_name or "" + fullname = fullname or " ".join((first_name, last_name)) + return fullname.strip(), first_name.strip(), last_name.strip() + + def get_user(self, user_id): + """ + Return user with given ID from the User model used by this backend. + This is called by django.contrib.auth.middleware. + """ + return self.strategy.get_user(user_id) + + def continue_pipeline(self, partial): + """Continue previous halted pipeline""" + return self.strategy.authenticate( + self, pipeline_index=partial.next_step, *partial.args, **partial.kwargs + ) + + def auth_extra_arguments(self): + """Return extra arguments needed on auth process. The defaults can be + overridden by GET parameters.""" + extra_arguments = self.setting("AUTH_EXTRA_ARGUMENTS", {}).copy() + extra_arguments.update( + (key, self.data[key]) for key in extra_arguments if key in self.data + ) + return extra_arguments + + def uses_redirect(self): + """Return True if this provider uses redirect url method, + otherwise return false.""" + return True + + def request(self, url, method="GET", *args, **kwargs): + kwargs.setdefault("headers", {}) + if self.setting("PROXIES") is not None: + kwargs.setdefault("proxies", self.setting("PROXIES")) + + if self.setting("VERIFY_SSL") is not None: + kwargs.setdefault("verify", self.setting("VERIFY_SSL")) + kwargs.setdefault( + "timeout", + self.setting("REQUESTS_TIMEOUT") or self.setting("URLOPEN_TIMEOUT"), + ) + if self.SEND_USER_AGENT and "User-Agent" not in kwargs["headers"]: + kwargs["headers"]["User-Agent"] = self.setting("USER_AGENT") or user_agent() + + try: + if self.SSL_PROTOCOL: + session = SSLHttpAdapter.ssl_adapter_session(self.SSL_PROTOCOL) + response = session.request(method, url, *args, **kwargs) + else: + response = request(method, url, *args, **kwargs) + except ConnectionError as err: + raise AuthFailed(self, str(err)) + response.raise_for_status() + return response + + def get_json(self, url, *args, **kwargs): + return self.request(url, *args, **kwargs).json() + + def get_querystring(self, url, *args, **kwargs): + return parse_qs(self.request(url, *args, **kwargs).text) + + def get_key_and_secret(self): + """Return tuple with Consumer Key and Consumer Secret for current + service provider. Must return (key, secret), order *must* be respected. + """ + return self.setting("KEY"), self.setting("SECRET") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/battlenet.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/battlenet.py new file mode 100644 index 0000000000000000000000000000000000000000..7ed578021a83ab06755581d52e91e73a8d9e9ea2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/battlenet.py @@ -0,0 +1,49 @@ +from .oauth import BaseOAuth2 + +# This provides a backend for python-social-auth. This should not be confused +# with officially battle.net offerings. This piece of code is not officially +# affiliated with Blizzard Entertainment, copyrights to their respective +# owners. See http://us.battle.net/en/forum/topic/13979588015 for more details. + + +class BattleNetOAuth2(BaseOAuth2): + """battle.net Oauth2 backend""" + + name = "battlenet-oauth2" + ID_KEY = "accountId" + REDIRECT_STATE = False + AUTHORIZATION_URL = "https://eu.battle.net/oauth/authorize" + ACCESS_TOKEN_URL = "https://eu.battle.net/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REVOKE_TOKEN_METHOD = "GET" + DEFAULT_SCOPE = ["wow.profile"] + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("expires_in", "expires"), + ("token_type", "token_type", True), + ] + + def get_characters(self, access_token): + """ + Fetches the character list from the battle.net API. Returns list of + characters or empty list if the request fails. + """ + params = {"access_token": access_token} + if self.setting("API_LOCALE"): + params["locale"] = self.setting("API_LOCALE") + + response = self.get_json( + "https://eu.api.battle.net/wow/user/characters", params=params + ) + return response.get("characters") or [] + + def get_user_details(self, response): + """Return user details from Battle.net account""" + return {"battletag": response.get("battletag")} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://eu.api.battle.net/account/user", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/beats.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/beats.py new file mode 100644 index 0000000000000000000000000000000000000000..7e70c7618ce6c9bb894c85ffd5998ebb710d23bd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/beats.py @@ -0,0 +1,69 @@ +""" +Beats backend, docs at: + https://developer.beatsmusic.com/docs +""" +import base64 + +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class BeatsOAuth2(BaseOAuth2): + name = "beats" + SCOPE_SEPARATOR = " " + ID_KEY = "user_context" + AUTHORIZATION_URL = "https://partner.api.beatsmusic.com/v1/oauth2/authorize" + ACCESS_TOKEN_URL = "https://partner.api.beatsmusic.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_id(self, details, response): + return response["result"][BeatsOAuth2.ID_KEY] + + def auth_headers(self): + return { + "Authorization": "Basic {}".format( + base64.urlsafe_b64encode( + "{}:{}".format(*self.get_key_and_secret()).encode() + ) + ) + } + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + # mashery wraps in jsonrpc + if response.get("jsonrpc", None): + response = response.get("result", None) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + def get_user_details(self, response): + """Return user details from Beats account""" + response = response["result"] + fullname, first_name, last_name = self.get_user_names( + response.get("display_name") + ) + return { + "username": response.get("id"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://partner.api.beatsmusic.com/v1/api/me", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/behance.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/behance.py new file mode 100644 index 0000000000000000000000000000000000000000..b04552dc73e37218f91890b4e1da52902c5e2d5b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/behance.py @@ -0,0 +1,42 @@ +""" +Behance OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/behance.html +""" +from .oauth import BaseOAuth2 + + +class BehanceOAuth2(BaseOAuth2): + """Behance OAuth authentication backend""" + + name = "behance" + AUTHORIZATION_URL = "https://www.behance.net/v2/oauth/authenticate" + ACCESS_TOKEN_URL = "https://www.behance.net/v2/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "|" + EXTRA_DATA = [("username", "username")] + REDIRECT_STATE = False + + def get_user_id(self, details, response): + return response["user"]["id"] + + def get_user_details(self, response): + """Return user details from Behance account""" + user = response["user"] + fullname, first_name, last_name = self.get_user_names( + user["display_name"], user["first_name"], user["last_name"] + ) + return { + "username": user["username"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": "", + } + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + # Pull up the embedded user attributes so they can be found as extra + # data. See the example token response for possible attributes: + # http://www.behance.net/dev/authentication#step-by-step + data = response.copy() + data.update(response["user"]) + return super().extra_data(user, uid, data, details, *args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/belgiumeid.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/belgiumeid.py new file mode 100644 index 0000000000000000000000000000000000000000..1cfc29722506f5d805188c20f57ba4ab59d9b358 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/belgiumeid.py @@ -0,0 +1,12 @@ +""" +Belgium EID OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/belgium_eid.html +""" +from .open_id import OpenIdAuth + + +class BelgiumEIDOpenId(OpenIdAuth): + """Belgium e-ID OpenID authentication backend""" + + name = "belgiumeid" + URL = "https://www.e-contract.be/eid-idp/endpoints/openid/auth" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bitbucket.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bitbucket.py new file mode 100644 index 0000000000000000000000000000000000000000..7289131404e1b55249cd04ddeb77ef2e565c0985 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bitbucket.py @@ -0,0 +1,101 @@ +""" +Bitbucket OAuth2 and OAuth1 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/bitbucket.html +""" +from ..exceptions import AuthForbidden +from .oauth import BaseOAuth1, BaseOAuth2 + + +class BitbucketOAuthBase: + ID_KEY = "uuid" + + def get_user_id(self, details, response): + id_key = self.ID_KEY + if self.setting("USERNAME_AS_ID", False): + id_key = "username" + return response.get(id_key) + + def get_user_details(self, response): + """Return user details from Bitbucket account""" + fullname, first_name, last_name = self.get_user_names(response["display_name"]) + + return { + "username": response.get("username", ""), + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + emails = self._get_emails(access_token) + email = None + + for address in reversed(emails["values"]): + email = address["email"] + if address["is_primary"]: + break + + if self.setting("VERIFIED_EMAILS_ONLY", False) and not address["is_confirmed"]: + raise AuthForbidden(self, "Bitbucket account has no verified email") + + user = self._get_user(access_token) + if email: + user["email"] = email + return user + + def _get_user(self, access_token=None): + raise NotImplementedError("Implement in subclass") + + def _get_emails(self, access_token=None): + raise NotImplementedError("Implement in subclass") + + +class BitbucketOAuth2(BitbucketOAuthBase, BaseOAuth2): + name = "bitbucket-oauth2" + SCOPE_SEPARATOR = " " + AUTHORIZATION_URL = "https://bitbucket.org/site/oauth2/authorize" + ACCESS_TOKEN_URL = "https://bitbucket.org/site/oauth2/access_token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("scopes", "scopes"), + ("expires_in", "expires"), + ("token_type", "token_type"), + ("refresh_token", "refresh_token"), + ] + + def auth_complete_credentials(self): + return self.get_key_and_secret() + + def _get_user(self, access_token=None): + return self.get_json( + "https://api.bitbucket.org/2.0/user", params={"access_token": access_token} + ) + + def _get_emails(self, access_token=None): + return self.get_json( + "https://api.bitbucket.org/2.0/user/emails", + params={"access_token": access_token}, + ) + + +class BitbucketOAuth(BitbucketOAuthBase, BaseOAuth1): + """Bitbucket OAuth authentication backend""" + + name = "bitbucket" + AUTHORIZATION_URL = "https://bitbucket.org/api/1.0/oauth/authenticate" + REQUEST_TOKEN_URL = "https://bitbucket.org/api/1.0/oauth/request_token" + ACCESS_TOKEN_URL = "https://bitbucket.org/api/1.0/oauth/access_token" + + def _get_user(self, access_token=None): + return self.get_json( + "https://api.bitbucket.org/2.0/user", auth=self.oauth_auth(access_token) + ) + + def _get_emails(self, access_token=None): + return self.get_json( + "https://api.bitbucket.org/2.0/user/emails", + auth=self.oauth_auth(access_token), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/box.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/box.py new file mode 100644 index 0000000000000000000000000000000000000000..2fc86dd285a752049f4c069642a4ab8c3fca6bb0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/box.py @@ -0,0 +1,58 @@ +""" +Box.net OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/box.html +""" +from .oauth import BaseOAuth2 + + +class BoxOAuth2(BaseOAuth2): + """Box.net OAuth authentication backend""" + + name = "box" + AUTHORIZATION_URL = "https://www.box.com/api/oauth2/authorize" + ACCESS_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://www.box.com/api/oauth2/token" + REVOKE_TOKEN_URL = "https://www.box.com/api/oauth2/revoke" + SCOPE_SEPARATOR = "," + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("id", "id"), + ("expires", "expires"), + ] + + def do_auth(self, access_token, response=None, *args, **kwargs): + response = response or {} + data = self.user_data(access_token) + + data["access_token"] = response.get("access_token") + data["refresh_token"] = response.get("refresh_token") + data["expires"] = response.get("expires_in") + kwargs.update({"backend": self, "response": data}) + return self.strategy.authenticate(*args, **kwargs) + + def get_user_details(self, response): + """Return user details Box.net account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("login"), + "email": response.get("login") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + params = self.setting("PROFILE_EXTRA_PARAMS", {}) + params["access_token"] = access_token + return self.get_json("https://api.box.com/2.0/users/me", params=params) + + def refresh_token(self, token, *args, **kwargs): + params = self.refresh_token_params(token, *args, **kwargs) + request = self.request( + self.REFRESH_TOKEN_URL or self.ACCESS_TOKEN_URL, + data=params, + headers=self.auth_headers(), + method="POST", + ) + return self.process_refresh_token_response(request, *args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bungie.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bungie.py new file mode 100644 index 0000000000000000000000000000000000000000..cba20e402e0c046b8373c43d2a3075edc86304d8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/bungie.py @@ -0,0 +1,83 @@ +""" +Bungie OAuth2 backend +""" +from social_core.backends.oauth import BaseOAuth2 + + +class BungieOAuth2(BaseOAuth2): + name = "bungie" + ID_KEY = "membership_id" + AUTHORIZATION_URL = "https://www.bungie.net/en/oauth/authorize/" + ACCESS_TOKEN_URL = "https://www.bungie.net/platform/app/oauth/token/" + REFRESH_TOKEN_URL = "https://www.bungie.net/platform/app/oauth/token/" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("access_token", "access_token", True), + ("expires_in", "expires"), + ("membership_id", "membership_id"), + ("refresh_expires_in", "refresh_expires_in"), + ] + + def auth_html(self): + """Abstract Method Inclusion""" + pass + + def auth_headers(self): + """Adds X-API-KEY and Origin""" + return { + "X-API-KEY": self.setting("API_KEY"), + "Content-Type": "application/x-www-form-urlencoded", + "Origin": self.setting("ORIGIN"), + "Accept": "application/json", + } + + def make_bungie_request(self, url, access_token, kwargs): + """Helper function to get username data keyed off displayName""" + headers = self.auth_headers() + headers["Authorization"] = "Bearer " + access_token + return self.get_json(url, headers=headers) + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + state = self.validate_state() + response = self.request_access_token( + self.access_token_url(), + data=self.auth_complete_params(state), + headers=self.auth_headers(), + auth=self.auth_complete_credentials(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + def do_auth(self, access_token, *args, **kwargs): + """Finish the auth process once the access_token was retrieved""" + data = self.user_data(access_token, *args, **kwargs) + response = kwargs.get("response") or {} + response.update(data or {}) + if "access_token" not in response: + response["Response"]["access_token"]["value"] = access_token + kwargs.update({"response": response, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def user_data(self, access_token, *args, **kwargs): + """Grab user profile information from Bunige""" + membership_id = kwargs["response"]["membership_id"] + url = "https://www.bungie.net/Platform/User/GetBungieNetUser/" + response = self.make_bungie_request(url, access_token, kwargs) + username = response["Response"]["user"]["displayName"] + return {"username": username, "uid": membership_id} + + def get_user_details(self, response, *args, **kwargs): + """Return user details from Bungie account""" + username = response["username"] + return { + "first_name": username, + "username": username, + "uid": response["uid"], + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/changetip.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/changetip.py new file mode 100644 index 0000000000000000000000000000000000000000..056aa710b56c96185e980cdf5c670ab82ffa0af5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/changetip.py @@ -0,0 +1,28 @@ +from .oauth import BaseOAuth2 + + +class ChangeTipOAuth2(BaseOAuth2): + """ChangeTip OAuth authentication backend + https://www.changetip.com/api + """ + + name = "changetip" + AUTHORIZATION_URL = "https://www.changetip.com/o/authorize/" + ACCESS_TOKEN_URL = "https://www.changetip.com/o/token/" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + + def get_user_details(self, response): + """Return user details from ChangeTip account""" + return { + "username": response["username"], + "email": response.get("email", ""), + "first_name": "", + "last_name": "", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.changetip.com/v2/me/", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/chatwork.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/chatwork.py new file mode 100644 index 0000000000000000000000000000000000000000..43efd0367a500c75185fc5a9bf2290ed0070a723 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/chatwork.py @@ -0,0 +1,62 @@ +""" +Chatwork OAuth2 backend +""" +import base64 + +from .oauth import BaseOAuth2 + + +class ChatworkOAuth2(BaseOAuth2): + """Chatwork OAuth authentication backend""" + + name = "chatwork" + API_URL = "https://api.chatwork.com/v2" + AUTHORIZATION_URL = "https://www.chatwork.com/packages/oauth2/login.php" + ACCESS_TOKEN_URL = "https://oauth.chatwork.com/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = True + DEFAULT_SCOPE = ["users.profile.me:read"] + ID_KEY = "account_id" + EXTRA_DATA = [("expires_in", "expires"), ("refresh_token", "refresh_token")] + + def api_url(self, path): + api_url = self.setting("API_URL") or self.API_URL + return "{}{}".format(api_url.rstrip("/"), path) + + def auth_headers(self): + return { + "Authorization": b"Basic " + + base64.b64encode("{}:{}".format(*self.get_key_and_secret()).encode()) + } + + def auth_complete_params(self, state=None): + return { + "grant_type": "authorization_code", + "code": self.data.get("code", ""), + "redirect_uri": self.get_redirect_uri(state), + } + + def get_user_details(self, response): + """Return user details from Chatwork account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + username = ( + response.get("chatwork_id") + or response.get("login_mail") + or response.get("account_id") + ) + email = response.get("mail") or response.get("login_mail") or "" + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = {"Authorization": "Bearer " + access_token} + return self.get_json(self.api_url("/me"), headers=headers) + + def refresh_token_params(self, token, *args, **kwargs): + return {"refresh_token": token, "grant_type": "refresh_token"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cilogon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cilogon.py new file mode 100644 index 0000000000000000000000000000000000000000..e9e5dd6ccc35c751b83b8b206cc0bc02548d7be1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cilogon.py @@ -0,0 +1,45 @@ +from .oauth import BaseOAuth2 + + +class CILogonOAuth2(BaseOAuth2): + """ + CI Logon Authentication Backend + + Docs: https://www.cilogon.org/oidc + """ + + name = "cilogon-oauth2" + AUTHORIZATION_URL = "https://cilogon.org/authorize" + ACCESS_TOKEN_URL = "https://cilogon.org/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["openid", "email", "profile", "org.cilogon.userinfo"] + REDIRECT_STATE = False + SCOPE_SEPARATOR = "+" + + def user_data(self, token, *args, **kwargs): + """Loads user data from endpoint""" + url = "https://cilogon.org/oauth2/userinfo" + data = {"access_token": token} + try: + return self.get_json(url, method="POST", data=data) + except ValueError: + return None + + def get_user_id(self, details, response): + """Return user unique id provided by service + In this case it is a combination of the `sub` + and `iss` respective values.""" + return response.get("sub", "") + " " + response.get("iss", "") + + def get_user_details(self, response): + """Return user details from CI Logon service""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("given_name"), last_name=response.get("family_name") + ) + return { + "username": response.get("email"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/classlink.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/classlink.py new file mode 100644 index 0000000000000000000000000000000000000000..b08756adc2cd40df9a1bdaa99d6ce8799ded4cc9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/classlink.py @@ -0,0 +1,44 @@ +from .oauth import BaseOAuth2 + + +class ClasslinkOAuth(BaseOAuth2): + """ + Classlink OAuth authentication backend. + + Docs: https://developer.classlink.com/docs/oauth2-workflow + """ + + name = "classlink" + AUTHORIZATION_URL = "https://launchpad.classlink.com/oauth2/v2/auth" + ACCESS_TOKEN_URL = "https://launchpad.classlink.com/oauth2/v2/token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["profile"] + REDIRECT_STATE = False + SCOPE_SEPARATOR = " " + + def get_user_id(self, details, response): + """Return user unique id provided by service""" + return response["UserId"] + + def get_user_details(self, response): + """Return user details from Classlink account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("FirstName"), last_name=response.get("LastName") + ) + + return { + "username": response.get("Email") or response.get("LoginId"), + "email": response.get("Email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, token, *args, **kwargs): + """Loads user data from service""" + url = "https://nodeapi.classlink.com/v2/my/info" + auth_header = {"Authorization": "Bearer %s" % token} + try: + return self.get_json(url, headers=auth_header) + except ValueError: + return None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/clef.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/clef.py new file mode 100644 index 0000000000000000000000000000000000000000..f6e792d0b4d7db406acd1d04328ed5b2b4bd38f1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/clef.py @@ -0,0 +1,52 @@ +""" +Clef OAuth support. + +This contribution adds support for Clef OAuth service. The settings +SOCIAL_AUTH_CLEF_KEY and SOCIAL_AUTH_CLEF_SECRET must be defined with the +values given by Clef application registration process. +""" + +from .oauth import BaseOAuth2 + + +class ClefOAuth2(BaseOAuth2): + """Clef OAuth authentication backend""" + + name = "clef" + AUTHORIZATION_URL = "https://clef.io/iframes/qr" + ACCESS_TOKEN_URL = "https://clef.io/api/v1/authorize" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + + def auth_params(self, *args, **kwargs): + params = super().auth_params(*args, **kwargs) + params["app_id"] = params.pop("client_id") + params["redirect_url"] = params.pop("redirect_uri") + return params + + def get_user_id(self, response, details): + return details.get("info").get("id") + + def get_user_details(self, response): + """Return user details from Github account""" + info = response.get("info") + fullname, first_name, last_name = self.get_user_names( + first_name=info.get("first_name"), last_name=info.get("last_name") + ) + + email = info.get("email", "") + username = email.split("@", 1)[0] if email else info.get("id") + + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "phone_number": info.get("phone_number", ""), + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://clef.io/api/v1/info", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coding.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coding.py new file mode 100644 index 0000000000000000000000000000000000000000..10dd8f0ea550e5172d9eb160b2ef76cf5756539e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coding.py @@ -0,0 +1,45 @@ +""" +Coding OAuth2 backend, docs at: +""" +from urllib.parse import urljoin + +from .oauth import BaseOAuth2 + + +class CodingOAuth2(BaseOAuth2): + """Coding OAuth authentication backend""" + + name = "coding" + API_URL = "https://coding.net/api/" + AUTHORIZATION_URL = "https://coding.net/oauth_authorize.html" + ACCESS_TOKEN_URL = "https://coding.net/api/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + DEFAULT_SCOPE = ["user"] + REDIRECT_STATE = False + + def api_url(self): + return self.API_URL + + def get_user_details(self, response): + """Return user details from Github account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("name"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + data = self._user_data(access_token) + if data.get("code") != 0: + # 获取失败 + pass + return data.get("data") + + def _user_data(self, access_token, path=None): + url = urljoin(self.api_url(), "account/current_user{}".format(path or "")) + return self.get_json(url, params={"access_token": access_token}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cognito.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cognito.py new file mode 100644 index 0000000000000000000000000000000000000000..85402c9dfc5173a5266ec734a7dd039d8d5a41a4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/cognito.py @@ -0,0 +1,53 @@ +from social_core.backends.oauth import BaseOAuth2 + + +class CognitoOAuth2(BaseOAuth2): + name = "cognito" + ID_KEY = "username" + DEFAULT_SCOPE = ["openid", "profile", "email"] + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def user_pool_domain(self): + return self.setting("POOL_DOMAIN") + + def authorization_url(self): + return f"{self.user_pool_domain()}/login" + + def access_token_url(self): + return f"{self.user_pool_domain()}/oauth2/token" + + def user_data_url(self): + return f"{self.user_pool_domain()}/oauth2/userInfo" + + def get_user_details(self, response): + """Return user details from their cognito pool account""" + first_name = response.get("given_name") or "" + last_name = response.get("family_name") or "" + fullname, first_name, last_name = self.get_user_names( + first_name=first_name, + last_name=last_name, + ) + return { + "username": response.get("username") or response.get("email"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Grab user profile information from cognito.""" + response = self.get_json( + url=self.user_data_url(), + headers={"Authorization": f"Bearer {access_token}"}, + ) + + user_data = { + "given_name": response.get("given_name"), + "family_name": response.get("family_name"), + "username": response.get("username"), + "email": response.get("email"), + } + + return user_data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coinbase.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coinbase.py new file mode 100644 index 0000000000000000000000000000000000000000..2f5cf1527917fc9444d131d05e3055a73a01dd7d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coinbase.py @@ -0,0 +1,41 @@ +""" +Coinbase OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/coinbase.html +""" +from .oauth import BaseOAuth2 + + +class CoinbaseOAuth2(BaseOAuth2): + name = "coinbase" + SCOPE_SEPARATOR = "+" + DEFAULT_SCOPE = ["user", "balance"] + AUTHORIZATION_URL = "https://www.coinbase.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.coinbase.com/oauth/token" + REVOKE_TOKEN_URL = "https://api.coinbase.com/oauth/revoke" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_id(self, details, response): + return response["data"]["id"] + + def get_user_details(self, response): + """Return user details from Coinbase account""" + user_data = response["data"] + email = user_data.get("email", "") + name = user_data["name"] + username = user_data.get("username") + fullname, first_name, last_name = self.get_user_names(name) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.coinbase.com/v2/user", + headers={"Authorization": "Bearer " + access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coursera.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coursera.py new file mode 100644 index 0000000000000000000000000000000000000000..ede3220b2a4dad2f68af81a4f0bbeb3856e90bd2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/coursera.py @@ -0,0 +1,44 @@ +""" +Coursera OAuth2 backend, docs at: + https://tech.coursera.org/app-platform/oauth2/ +""" +from .oauth import BaseOAuth2 + + +class CourseraOAuth2(BaseOAuth2): + """Coursera OAuth2 authentication backend""" + + name = "coursera" + ID_KEY = "username" + AUTHORIZATION_URL = "https://accounts.coursera.org/oauth2/v1/auth" + ACCESS_TOKEN_URL = "https://accounts.coursera.org/oauth2/v1/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + SCOPE_SEPARATOR = "," + DEFAULT_SCOPE = ["view_profile"] + + def _get_username_from_response(self, response): + elements = response.get("elements", []) + for element in elements: + if "id" in element: + return element.get("id") + + return None + + def get_user_details(self, response): + """Return user details from Coursera account""" + return {"username": self._get_username_from_response(response)} + + def get_user_id(self, details, response): + """Return a username prepared in get_user_details as uid""" + return details.get(self.ID_KEY) + + def user_data(self, access_token, *args, **kwargs): + """Load user data from the service""" + return self.get_json( + "https://api.coursera.org/api/externalBasicProfiles.v1?q=me", + headers=self.get_auth_header(access_token), + ) + + def get_auth_header(self, access_token): + return {"Authorization": f"Bearer {access_token}"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dailymotion.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dailymotion.py new file mode 100644 index 0000000000000000000000000000000000000000..90c77b2fb3deaeaf0be53cbf04544a653b3ecdc6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dailymotion.py @@ -0,0 +1,26 @@ +""" +DailyMotion OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/dailymotion.html +""" +from .oauth import BaseOAuth2 + + +class DailymotionOAuth2(BaseOAuth2): + """Dailymotion OAuth authentication backend""" + + name = "dailymotion" + EXTRA_DATA = [("id", "id")] + ID_KEY = "username" + AUTHORIZATION_URL = "https://api.dailymotion.com/oauth/authorize" + REQUEST_TOKEN_URL = "https://api.dailymotion.com/oauth/token" + ACCESS_TOKEN_URL = "https://api.dailymotion.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_details(self, response): + return {"username": response.get("screenname")} + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "https://api.dailymotion.com/auth/", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/deezer.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/deezer.py new file mode 100644 index 0000000000000000000000000000000000000000..334de4b5dcc607e5baea9232a2c3d5f01290fc84 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/deezer.py @@ -0,0 +1,51 @@ +""" +Deezer backend, docs at: + https://developers.deezer.com/api/oauth + https://developers.deezer.com/api/permissions +""" +from urllib.parse import parse_qsl + +from .oauth import BaseOAuth2 + + +class DeezerOAuth2(BaseOAuth2): + """Deezer OAuth2 authentication backend""" + + name = "deezer" + ID_KEY = "name" + AUTHORIZATION_URL = "https://connect.deezer.com/oauth/auth.php" + ACCESS_TOKEN_URL = "https://connect.deezer.com/oauth/access_token.php" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "app_id": client_id, + "secret": client_secret, + "code": self.data.get("code"), + } + + def request_access_token(self, *args, **kwargs): + response = self.request(*args, **kwargs) + return dict(parse_qsl(response.text)) + + def get_user_details(self, response): + """Return user details from Deezer account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("firstname"), last_name=response.get("lastname") + ) + return { + "username": response.get("name"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "http://api.deezer.com/user/me", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/digitalocean.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/digitalocean.py new file mode 100644 index 0000000000000000000000000000000000000000..f0f373150ccd2e7a1bb1c1fa33e523809ebca9e9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/digitalocean.py @@ -0,0 +1,43 @@ +from .oauth import BaseOAuth2 + + +class DigitalOceanOAuth(BaseOAuth2): + """ + DigitalOcean OAuth authentication backend. + + Docs: https://developers.digitalocean.com/documentation/oauth/ + """ + + name = "digitalocean" + AUTHORIZATION_URL = "https://cloud.digitalocean.com/v1/oauth/authorize" + ACCESS_TOKEN_URL = "https://cloud.digitalocean.com/v1/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + EXTRA_DATA = [("expires_in", "expires_in")] + + def get_user_id(self, details, response): + """Return user unique id provided by service""" + return response["account"].get("uuid") + + def get_user_details(self, response): + """Return user details from DigitalOcean account""" + fullname, first_name, last_name = self.get_user_names( + response.get("name") or "" + ) + + return { + "username": response["account"].get("email"), + "email": response["account"].get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, token, *args, **kwargs): + """Loads user data from service""" + url = "https://api.digitalocean.com/v2/account" + auth_header = {"Authorization": "Bearer %s" % token} + try: + return self.get_json(url, headers=auth_header) + except ValueError: + return None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discord.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discord.py new file mode 100644 index 0000000000000000000000000000000000000000..a8cb7dc74bf42872f34a80ed87af1152f0dafd0e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discord.py @@ -0,0 +1,30 @@ +""" +Discord Auth OAuth2 backend, docs at: + https://discord.com/developers/docs/topics/oauth2 +""" +from .oauth import BaseOAuth2 + + +class DiscordOAuth2(BaseOAuth2): + name = "discord" + HOSTNAME = "discord.com" + AUTHORIZATION_URL = "https://%s/api/oauth2/authorize" % HOSTNAME + ACCESS_TOKEN_URL = "https://%s/api/oauth2/token" % HOSTNAME + ACCESS_TOKEN_METHOD = "POST" + REVOKE_TOKEN_URL = "https://%s/api/oauth2/token/revoke" % HOSTNAME + REVOKE_TOKEN_METHOD = "GET" + DEFAULT_SCOPE = ["identify"] + SCOPE_SEPARATOR = "+" + REDIRECT_STATE = False + EXTRA_DATA = [("expires_in", "expires"), ("refresh_token", "refresh_token")] + + def get_user_details(self, response): + return { + "username": response.get("username"), + "email": response.get("email") or "", + } + + def user_data(self, access_token, *args, **kwargs): + url = "https://%s/api/users/@me" % self.HOSTNAME + auth_header = {"Authorization": "Bearer %s" % access_token} + return self.get_json(url, headers=auth_header) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discourse.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discourse.py new file mode 100644 index 0000000000000000000000000000000000000000..e2baf024b171754285e644e7f17251a26b15c8a4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/discourse.py @@ -0,0 +1,90 @@ +import hmac +import time +from base64 import urlsafe_b64decode, urlsafe_b64encode +from hashlib import sha256 +from urllib.parse import urlencode + +from ..exceptions import AuthException, AuthTokenError +from ..utils import parse_qs +from .base import BaseAuth + + +class DiscourseAuth(BaseAuth): + name = "discourse" + EXTRA_DATA = ["username", "name", "avatar_url"] + + def auth_url(self): + """ + Get the URL to which we must redirect in order to authenticate the user + """ + return_url = self.redirect_uri + nonce = self.strategy.random_string(64) + self.add_nonce(nonce) + + payload = urlencode({"nonce": nonce, "return_sso_url": return_url}) + base_64_payload = urlsafe_b64encode(payload.encode("utf8")).decode("ascii") + + payload_signature = hmac.new( + self.setting("SECRET").encode("utf8"), + base_64_payload.encode("utf8"), + sha256, + ).hexdigest() + encoded_params = urlencode({"sso": base_64_payload, "sig": payload_signature}) + return f"{self.get_idp_url()}?{encoded_params}" + + def get_idp_url(self): + return self.setting("SERVER_URL") + "/session/sso_provider" + + def get_user_id(self, details, response): + return response["email"] + + def get_user_details(self, response): + results = { + "username": response.get("username"), + "email": response.get("email"), + "name": response.get("name"), + "groups": response.get("groups", "").split(","), + "is_staff": response.get("admin") == "true" + or response.get("moderator") == "true", + "is_superuser": response.get("admin") == "true", + } + return results + + def add_nonce(self, nonce): + self.strategy.storage.nonce.use(self.setting("SERVER_URL"), time.time(), nonce) + + def get_nonce(self, nonce): + return self.strategy.storage.nonce.get(self.setting("SERVER_URL"), nonce) + + def delete_nonce(self, nonce): + self.strategy.storage.nonce.delete(nonce) + + def auth_complete(self, *args, **kwargs): + """ + The user has been redirected back from the IdP and we should + now log them in, if everything checks out. + """ + request_data = self.strategy.request_data() + + sso_params = request_data.get("sso") + sso_signature = request_data.get("sig") + + param_signature = hmac.new( + self.setting("SECRET").encode("utf8"), sso_params.encode("utf8"), sha256 + ).hexdigest() + + if not hmac.compare_digest(str(sso_signature), str(param_signature)): + raise AuthException("Could not verify discourse login") + + decoded_params = urlsafe_b64decode(sso_params.encode("utf8")).decode("ascii") + + # Validate the nonce to ensure the request was not modified + response = parse_qs(decoded_params) + nonce_obj = self.get_nonce(response.get("nonce")) + if nonce_obj: + self.delete_nonce(nonce_obj) + else: + raise AuthTokenError(self, "Incorrect id_token: nonce") + + kwargs.update({"sso": "", "sig": "", "backend": self, "response": response}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/disqus.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/disqus.py new file mode 100644 index 0000000000000000000000000000000000000000..a6da5947a59c0e2caac74b9f6ce004edbc2371cd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/disqus.py @@ -0,0 +1,51 @@ +""" +Disqus OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/disqus.html +""" +from .oauth import BaseOAuth2 + + +class DisqusOAuth2(BaseOAuth2): + name = "disqus" + AUTHORIZATION_URL = "https://disqus.com/api/oauth/2.0/authorize/" + ACCESS_TOKEN_URL = "https://disqus.com/api/oauth/2.0/access_token/" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + SCOPE_SEPARATOR = "," + EXTRA_DATA = [ + ("avatar", "avatar"), + ("connections", "connections"), + ("user_id", "user_id"), + ("email", "email"), + ("email_hash", "emailHash"), + ("expires", "expires"), + ("location", "location"), + ("meta", "response"), + ("name", "name"), + ("username", "username"), + ] + + def get_user_id(self, details, response): + return response["response"]["id"] + + def get_user_details(self, response): + """Return user details from Disqus account""" + rr = response.get("response", {}) + return { + "username": rr.get("username", ""), + "user_id": response.get("user_id", ""), + "email": rr.get("email", ""), + "name": rr.get("name", ""), + } + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + meta_response = dict(response, **response.get("response", {})) + return super().extra_data(user, uid, meta_response, details, *args, **kwargs) + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + key, secret = self.get_key_and_secret() + return self.get_json( + "https://disqus.com/api/3.0/users/details.json", + params={"access_token": access_token, "api_secret": secret}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/docker.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/docker.py new file mode 100644 index 0000000000000000000000000000000000000000..df3642e5f88166cb622c66e3d12c19c799f4a3d9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/docker.py @@ -0,0 +1,46 @@ +""" +Docker Hub OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/docker.html +""" +from .oauth import BaseOAuth2 + + +class DockerOAuth2(BaseOAuth2): + name = "docker" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://hub.docker.com/api/v1.1/o/authorize/" + ACCESS_TOKEN_URL = "https://hub.docker.com/api/v1.1/o/token/" + REFRESH_TOKEN_URL = "https://hub.docker.com/api/v1.1/o/token/" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("user_id", "user_id"), + ("email", "email"), + ("full_name", "fullname"), + ("location", "location"), + ("url", "url"), + ("company", "company"), + ("gravatar_email", "gravatar_email"), + ] + + def get_user_details(self, response): + """Return user details from Docker Hub account""" + fullname, first_name, last_name = self.get_user_names( + response.get("full_name") or response.get("username") or "" + ) + return { + "username": response.get("username"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": response.get("email", ""), + } + + def user_data(self, access_token, *args, **kwargs): + """Grab user profile information from Docker Hub.""" + username = kwargs["response"]["username"] + return self.get_json( + "https://hub.docker.com/api/v1.1/users/%s/" % username, + headers={"Authorization": "Bearer %s" % access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/douban.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/douban.py new file mode 100644 index 0000000000000000000000000000000000000000..d021f0e405ce0dd1985322c75828b6c0dca6249a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/douban.py @@ -0,0 +1,62 @@ +""" +Douban OAuth1 and OAuth2 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/douban.html +""" +from .oauth import BaseOAuth1, BaseOAuth2 + + +class DoubanOAuth(BaseOAuth1): + """Douban OAuth authentication backend""" + + name = "douban" + EXTRA_DATA = [("id", "id")] + AUTHORIZATION_URL = "http://www.douban.com/service/auth/authorize" + REQUEST_TOKEN_URL = "http://www.douban.com/service/auth/request_token" + ACCESS_TOKEN_URL = "http://www.douban.com/service/auth/access_token" + + def get_user_id(self, details, response): + return response["db:uid"]["$t"] + + def get_user_details(self, response): + """Return user details from Douban""" + return {"username": response["db:uid"]["$t"], "email": ""} + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "http://api.douban.com/people/%40me?&alt=json", + auth=self.oauth_auth(access_token), + ) + + +class DoubanOAuth2(BaseOAuth2): + """Douban OAuth authentication backend""" + + name = "douban-oauth2" + AUTHORIZATION_URL = "https://www.douban.com/service/auth2/auth" + ACCESS_TOKEN_URL = "https://www.douban.com/service/auth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("id", "id"), + ("uid", "username"), + ("refresh_token", "refresh_token"), + ] + + def get_user_details(self, response): + """Return user details from Douban""" + fullname, first_name, last_name = self.get_user_names(response.get("name", "")) + return { + "username": response.get("uid", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": "", + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "https://api.douban.com/v2/user/~me", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dribbble.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dribbble.py new file mode 100644 index 0000000000000000000000000000000000000000..d824e86cfa6bbfd0c52fe8fc0e9958d51e98a29d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dribbble.py @@ -0,0 +1,62 @@ +""" +Dribbble OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/dribbble.html + http://developer.dribbble.com/v1/oauth/ +""" + +from .oauth import BaseOAuth2 + + +class DribbbleOAuth2(BaseOAuth2): + """Dribbble OAuth authentication backend""" + + name = "dribbble" + AUTHORIZATION_URL = "https://dribbble.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://dribbble.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + EXTRA_DATA = [ + ("id", "id"), + ("name", "name"), + ("html_url", "html_url"), + ("avatar_url", "avatar_url"), + ("bio", "bio"), + ("location", "location"), + ("links", "links"), + ("buckets_count", "buckets_count"), + ("comments_received_count", "comments_received_count"), + ("followers_count", "followers_count"), + ("followings_count", "followings_count"), + ("likes_count", "likes_count"), + ("likes_received_count", "likes_received_count"), + ("projects_count", "projects_count"), + ("rebounds_received_count", "rebounds_received_count"), + ("shots_count", "shots_count"), + ("teams_count", "teams_count"), + ("pro", "pro"), + ("buckets_url", "buckets_url"), + ("followers_url", "followers_url"), + ("following_url", "following_url"), + ("likes_url", "shots_url"), + ("teams_url", "teams_url"), + ("created_at", "created_at"), + ("updated_at", "updated_at"), + ] + + def get_user_details(self, response): + """Return user details from Dribbble account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("username"), + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.dribbble.com/v1/user", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/drip.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/drip.py new file mode 100644 index 0000000000000000000000000000000000000000..3d57418940e1da06c2fc4192adaa5f1cb12a0145 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/drip.py @@ -0,0 +1,28 @@ +""" +Drip OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/drip.html +""" +from .oauth import BaseOAuth2 + + +class DripOAuth(BaseOAuth2): + name = "drip" + AUTHORIZATION_URL = "https://www.getdrip.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.getdrip.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_id(self, details, response): + return details["email"] + + def get_user_details(self, response): + return { + "email": response["users"][0]["email"], + "fullname": response["users"][0]["name"], + "username": response["users"][0]["email"], + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://api.getdrip.com/v2/user", + headers={"Authorization": "Bearer %s" % access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dropbox.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dropbox.py new file mode 100644 index 0000000000000000000000000000000000000000..53fe8b25fdab169d632e15a22c75f83d5c1b3f7d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/dropbox.py @@ -0,0 +1,34 @@ +""" +Dropbox OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/dropbox.html +""" + +from .oauth import BaseOAuth2 + + +class DropboxOAuth2V2(BaseOAuth2): + name = "dropbox-oauth2" + ID_KEY = "uid" + AUTHORIZATION_URL = "https://www.dropbox.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://api.dropboxapi.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_details(self, response): + """Return user details from Dropbox account""" + name = response.get("name") + return { + "username": str(response.get("account_id")), + "email": response.get("email"), + "fullname": name.get("display_name"), + "first_name": name.get("given_name"), + "last_name": name.get("surname"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.dropboxapi.com/2/users/get_current_account", + headers={"Authorization": f"Bearer {access_token}"}, + method="POST", + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/echosign.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/echosign.py new file mode 100644 index 0000000000000000000000000000000000000000..7ff33e7fc008fee9db651f73b615359b789ef22e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/echosign.py @@ -0,0 +1,25 @@ +from .oauth import BaseOAuth2 + + +class EchosignOAuth2(BaseOAuth2): + name = "echosign" + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_METHOD = "POST" + REVOKE_TOKEN_METHOD = "POST" + AUTHORIZATION_URL = "https://secure.echosign.com/public/oauth" + ACCESS_TOKEN_URL = "https://secure.echosign.com/oauth/token" + REFRESH_TOKEN_URL = "https://secure.echosign.com/oauth/refresh" + REVOKE_TOKEN_URL = "https://secure.echosign.com/oauth/revoke" + + def get_user_details(self, response): + return response + + def get_user_id(self, details, response): + return details["userInfoList"][0]["userId"] + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://api.echosign.com/api/rest/v3/users", + headers={"Access-Token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/edmodo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/edmodo.py new file mode 100644 index 0000000000000000000000000000000000000000..3ec29e71ed3c8793b8fee858cf23aaf636f2c487 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/edmodo.py @@ -0,0 +1,33 @@ +""" +Edmodo OAuth2 Sign-in backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/edmodo.html +""" +from .oauth import BaseOAuth2 + + +class EdmodoOAuth2(BaseOAuth2): + """Edmodo OAuth2""" + + name = "edmodo" + AUTHORIZATION_URL = "https://api.edmodo.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.edmodo.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_details(self, response): + """Return user details from Edmodo account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("first_name"), last_name=response.get("last_name") + ) + return { + "username": response.get("username"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from Edmodo""" + return self.get_json( + "https://api.edmodo.com/users/me", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/elixir.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/elixir.py new file mode 100644 index 0000000000000000000000000000000000000000..ffe0c32fb1f26455c8271a62751c2b7685e5365a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/elixir.py @@ -0,0 +1,34 @@ +""" +Backend for OpenID Connect ELIXIR AAI +https://www.elixir-europe.org/services/compute/aai +""" + +from social_core.backends.open_id_connect import OpenIdConnectAuth + + +class ElixirOpenIdConnect(OpenIdConnectAuth): + name = "elixir" + OIDC_ENDPOINT = "https://login.elixir-czech.org/oidc" + EXTRA_DATA = [ + ("expires_in", "expires_in", True), + ("refresh_token", "refresh_token", True), + ("id_token", "id_token", True), + ("other_tokens", "other_tokens", True), + ] + # In order to get any scopes, you have to register your service with + # ELIXIR, see documentation at + # https://www.elixir-europe.org/services/compute/aai + DEFAULT_SCOPE = ["openid", "email"] + JWT_DECODE_OPTIONS = {"verify_at_hash": False} + + def get_user_details(self, response): + username_key = self.setting("USERNAME_KEY", default=self.USERNAME_KEY) + name = response.get("name") or "" + fullname, first_name, last_name = self.get_user_names(name) + return { + "username": response.get(username_key), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/email.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/email.py new file mode 100644 index 0000000000000000000000000000000000000000..c41f0c2e4829fdd7112f70b7f09639f3a3ad4af0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/email.py @@ -0,0 +1,12 @@ +""" +Legacy Email backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/email.html +""" +from .legacy import LegacyAuth + + +class EmailAuth(LegacyAuth): + name = "email" + ID_KEY = "email" + REQUIRES_EMAIL_VALIDATION = True + EXTRA_DATA = ["email"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eventbrite.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eventbrite.py new file mode 100644 index 0000000000000000000000000000000000000000..7f31d5c4f820db27056923c46c5116deefd28965 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eventbrite.py @@ -0,0 +1,30 @@ +from .oauth import BaseOAuth2 + + +class EventbriteOAuth2(BaseOAuth2): + """Eventbrite OAuth2 authentication backend""" + + name = "eventbrite" + AUTHORIZATION_URL = "https://www.eventbrite.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.eventbrite.com/oauth/token" + METADATA_URL = "https://www.eventbriteapi.com/v3/users/me" + ACCESS_TOKEN_METHOD = "POST" + STATE_PARAMETER = False + REDIRECT_STATE = False + + def get_user_details(self, response): + """Return user details from an Eventbrite metadata response""" + email = next(iter(filter(lambda x: x["primary"], response["emails"])))["email"] + + return { + "username": email, + "email": email, + "first_name": response["first_name"], + "last_name": response["last_name"], + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data and datacenter information from service""" + return self.get_json( + self.METADATA_URL, headers={"Authorization": "Bearer " + access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eveonline.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eveonline.py new file mode 100644 index 0000000000000000000000000000000000000000..2487355b48cb034b34c73c21e615519b43a0855b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/eveonline.py @@ -0,0 +1,43 @@ +""" +EVE Online Single Sign-On (SSO) OAuth2 backend +Documentation at https://eveonline-third-party-documentation.readthedocs.io/en/latest/sso/index.html +""" +from .oauth import BaseOAuth2 + + +class EVEOnlineOAuth2(BaseOAuth2): + """EVE Online OAuth authentication backend""" + + name = "eveonline" + BASE_URL = "https://login.eveonline.com/oauth" + AUTHORIZATION_URL = BASE_URL + "/authorize" + ACCESS_TOKEN_URL = BASE_URL + "/token" + ID_KEY = "CharacterID" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("CharacterID", "id"), + ("expires_in", "expires"), + ("CharacterOwnerHash", "owner_hash", True), + ("refresh_token", "refresh_token", True), + ] + + def get_user_details(self, response): + """Return user details from EVE Online account""" + user_data = self.user_data(response["access_token"]) + fullname, first_name, last_name = self.get_user_names( + user_data["CharacterName"] + ) + return { + "email": "", + "username": fullname, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Get Character data from EVE server""" + return self.get_json( + "https://login.eveonline.com/oauth/verify", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/evernote.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/evernote.py new file mode 100644 index 0000000000000000000000000000000000000000..768478743d73a1176f4c1bd29cefd32c3e555709 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/evernote.py @@ -0,0 +1,75 @@ +""" +Evernote OAuth1 backend (with sandbox mode support), docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/evernote.html +""" +from requests import HTTPError + +from ..exceptions import AuthCanceled +from .oauth import BaseOAuth1 + + +class EvernoteOAuth(BaseOAuth1): + """ + Evernote OAuth authentication backend. + + Possible Values: + {'edam_expires': ['1367525289541'], + 'edam_noteStoreUrl': [ + 'https://sandbox.evernote.com/shard/s1/notestore' + ], + 'edam_shard': ['s1'], + 'edam_userId': ['123841'], + 'edam_webApiUrlPrefix': ['https://sandbox.evernote.com/shard/s1/'], + 'oauth_token': [ + 'S=s1:U=1e3c1:E=13e66dbee45:C=1370f2ac245:P=185:A=my_user:' \ + 'H=411443c5e8b20f8718ed382a19d4ae38' + ]} + """ + + name = "evernote" + ID_KEY = "edam_userId" + AUTHORIZATION_URL = "https://www.evernote.com/OAuth.action" + REQUEST_TOKEN_URL = "https://www.evernote.com/oauth" + ACCESS_TOKEN_URL = "https://www.evernote.com/oauth" + EXTRA_DATA = [ + ("access_token", "access_token"), + ("oauth_token", "oauth_token"), + ("edam_noteStoreUrl", "store_url"), + ("edam_expires", "expires"), + ] + + def get_user_details(self, response): + """Return user details from Evernote account""" + return {"username": response["edam_userId"], "email": ""} + + def access_token(self, token): + """Return request for access token value""" + try: + return self.get_querystring( + self.ACCESS_TOKEN_URL, auth=self.oauth_auth(token) + ) + except HTTPError as err: + # Evernote returns a 401 error when AuthCanceled + if err.response.status_code == 401: + raise AuthCanceled(self, response=err.response) + else: + raise + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + data = super().extra_data(user, uid, response, details, *args, **kwargs) + # Evernote returns expiration timestamp in milliseconds, so it needs to + # be normalized. + if "expires" in data: + data["expires"] = int(data["expires"]) / 1000 + return data + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return access_token.copy() + + +class EvernoteSandboxOAuth(EvernoteOAuth): + name = "evernote-sandbox" + AUTHORIZATION_URL = "https://sandbox.evernote.com/OAuth.action" + REQUEST_TOKEN_URL = "https://sandbox.evernote.com/oauth" + ACCESS_TOKEN_URL = "https://sandbox.evernote.com/oauth" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/exacttarget.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/exacttarget.py new file mode 100644 index 0000000000000000000000000000000000000000..cdaf7ca877101369c353d84dbaced205825bc3aa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/exacttarget.py @@ -0,0 +1,102 @@ +""" +ExactTarget OAuth support. +Support Authentication from IMH using JWT token and pre-shared key. +Requires package pyjwt +""" +from datetime import datetime, timedelta + +import jwt + +from ..exceptions import AuthCanceled, AuthFailed +from .oauth import BaseOAuth2 + + +class ExactTargetOAuth2(BaseOAuth2): + name = "exacttarget" + + def get_user_details(self, response): + """Use the email address of the user, suffixed by _et""" + user = response.get("token", {}).get("request", {}).get("user", {}) + if "email" in user: + user["username"] = user["email"] + return user + + def get_user_id(self, details, response): + """ + Create a user ID from the ET user ID. Uses details rather than the + default response, as only the token is available in response. details + is much richer: + { + 'expiresIn': 1200, + 'username': 'example@example.com', + 'refreshToken': '1234567890abcdef', + 'internalOauthToken': 'jwttoken.......', + 'oauthToken': 'yetanothertoken', + 'id': 123456, + 'culture': 'en-US', + 'timezone': { + 'shortName': 'CST', + 'offset': -6.0, + 'dst': False, + 'longName': '(GMT-06:00) Central Time (No Daylight Saving)' + }, + 'email': 'example@example.com' + } + """ + return "{}".format(details.get("id")) + + def uses_redirect(self): + return False + + def auth_url(self): + return None + + def process_error(self, data): + if data.get("error"): + error = self.data.get("error_description") or self.data["error"] + raise AuthFailed(self, error) + + def do_auth(self, token, *args, **kwargs): + dummy, secret = self.get_key_and_secret() + try: # Decode the token, using the Application Signature from settings + decoded = jwt.decode(token, secret, algorithms=["HS256"]) + except jwt.DecodeError: # Wrong signature, fail authentication + raise AuthCanceled(self) + kwargs.update({"response": {"token": decoded}, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + token = self.data.get("jwt", {}) + if not token: + raise AuthFailed(self, "Authentication Failed") + return self.do_auth(token, *args, **kwargs) + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Load extra details from the JWT token""" + data = { + "id": details.get("id"), + "email": details.get("email"), + # OAuth token, for use with legacy SOAP API calls: + # http://bit.ly/13pRHfo + "internalOauthToken": details.get("internalOauthToken"), + # Token for use with the Application ClientID for the FUEL API + "oauthToken": details.get("oauthToken"), + # If the token has expired, use the FUEL API to get a new token see + # http://bit.ly/10v1K5l and http://bit.ly/11IbI6F - set legacy=1 + "refreshToken": details.get("refreshToken"), + } + + # The expiresIn value determines how long the tokens are valid for. + # Take a bit off, then convert to an int timestamp + expiresSeconds = details.get("expiresIn", 0) - 30 + expires = datetime.utcnow() + timedelta(seconds=expiresSeconds) + data["expires"] = (expires - datetime(1970, 1, 1)).total_seconds() + + if response.get("token"): + token = response["token"] + org = token.get("request", {}).get("organization") + if org: + data["stack"] = org.get("stackKey") + data["enterpriseId"] = org.get("enterpriseId") + return data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/facebook.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/facebook.py new file mode 100644 index 0000000000000000000000000000000000000000..210062d6396fc4d6c6d9a6510bc1700680ff069f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/facebook.py @@ -0,0 +1,294 @@ +""" +Facebook OAuth2, Canvas Application and Limited Login backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/facebook.html +""" +import base64 +import hashlib +import hmac +import json +import time + +from ..exceptions import ( + AuthCanceled, + AuthException, + AuthMissingParameter, + AuthTokenError, + AuthUnknownError, +) +from ..utils import constant_time_compare, handle_http_errors, parse_qs +from .oauth import BaseOAuth2 +from .open_id_connect import OpenIdConnectAuth + +API_VERSION = 12.0 + + +class FacebookOAuth2(BaseOAuth2): + """Facebook OAuth2 authentication backend""" + + name = "facebook" + REDIRECT_STATE = False + RESPONSE_TYPE = None + SCOPE_SEPARATOR = "," + AUTHORIZATION_URL = "https://www.facebook.com/v{version}/dialog/oauth" + ACCESS_TOKEN_URL = "https://graph.facebook.com/v{version}/oauth/access_token" + REVOKE_TOKEN_URL = "https://graph.facebook.com/v{version}/{uid}/permissions" + REVOKE_TOKEN_METHOD = "DELETE" + USER_DATA_URL = "https://graph.facebook.com/v{version}/me" + EXTRA_DATA = [ + ("id", "id"), + ("expires", "expires"), + ("granted_scopes", "granted_scopes"), + ("denied_scopes", "denied_scopes"), + ] + + def auth_params(self, state=None): + params = super().auth_params(state) + params["return_scopes"] = "true" + return params + + def authorization_url(self): + version = self.setting("API_VERSION", API_VERSION) + return self.AUTHORIZATION_URL.format(version=version) + + def access_token_url(self): + version = self.setting("API_VERSION", API_VERSION) + return self.ACCESS_TOKEN_URL.format(version=version) + + def get_user_details(self, response): + """Return user details from Facebook account""" + fullname, first_name, last_name = self.get_user_names( + response.get("name", ""), + response.get("first_name", ""), + response.get("last_name", ""), + ) + return { + "username": response.get("username", response.get("name")), + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + params = self.setting("PROFILE_EXTRA_PARAMS", {}).copy() + params["access_token"] = access_token + + if self.setting("APPSECRET_PROOF", True): + _, secret = self.get_key_and_secret() + params["appsecret_proof"] = hmac.new( + secret.encode("utf8"), + msg=access_token.encode("utf8"), + digestmod=hashlib.sha256, + ).hexdigest() + + version = self.setting("API_VERSION", API_VERSION) + return self.get_json(self.USER_DATA_URL.format(version=version), params=params) + + def process_error(self, data): + super().process_error(data) + if data.get("error_code"): + raise AuthCanceled( + self, data.get("error_message") or data.get("error_code") + ) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + if not self.data.get("code"): + raise AuthMissingParameter(self, "code") + state = self.validate_state() + key, secret = self.get_key_and_secret() + response = self.request( + self.access_token_url(), + params={ + "client_id": key, + "redirect_uri": self.get_redirect_uri(state), + "client_secret": secret, + "code": self.data["code"], + }, + ) + # API v2.3 returns a JSON, according to the documents linked at issue + # #592, but it seems that this needs to be enabled(?), otherwise the + # usual querystring type response is returned. + try: + response = response.json() + except ValueError: + response = parse_qs(response.text) + access_token = response["access_token"] + return self.do_auth(access_token, response, *args, **kwargs) + + def process_refresh_token_response(self, response, *args, **kwargs): + try: + return response.json() + except ValueError: + return parse_qs(response.content) + + def refresh_token_params(self, token, *args, **kwargs): + client_id, client_secret = self.get_key_and_secret() + return { + "fb_exchange_token": token, + "grant_type": "fb_exchange_token", + "client_id": client_id, + "client_secret": client_secret, + } + + @handle_http_errors + def do_auth(self, access_token, response=None, *args, **kwargs): + response = response or {} + + data = self.user_data(access_token) + + if not isinstance(data, dict): + # From time to time Facebook responds back a JSON with just + # False as value, the reason is still unknown, but since the + # data is needed (it contains the user ID used to identify the + # account on further logins), this app cannot allow it to + # continue with the auth process. + raise AuthUnknownError( + self, "An error occurred while retrieving " "users Facebook data" + ) + + data["access_token"] = access_token + if "expires_in" in response: + data["expires"] = response["expires_in"] + + if self.data.get("granted_scopes"): + data["granted_scopes"] = self.data["granted_scopes"].split(",") + + if self.data.get("denied_scopes"): + data["denied_scopes"] = self.data["denied_scopes"].split(",") + + kwargs.update({"backend": self, "response": data}) + return self.strategy.authenticate(*args, **kwargs) + + def revoke_token_url(self, token, uid): + version = self.setting("API_VERSION", API_VERSION) + return self.REVOKE_TOKEN_URL.format(version=version, uid=uid) + + def revoke_token_params(self, token, uid): + return {"access_token": token} + + def process_revoke_token_response(self, response): + return ( + super().process_revoke_token_response(response) + and response.content == "true" + ) + + +class FacebookAppOAuth2(FacebookOAuth2): + """Facebook Application Authentication support""" + + name = "facebook-app" + + def uses_redirect(self): + return False + + def auth_complete(self, *args, **kwargs): + access_token = self.data.get("access_token") + response = {} + + if "signed_request" in self.data: + key, secret = self.get_key_and_secret() + response = self.load_signed_request(self.data["signed_request"]) + if "user_id" not in response and "oauth_token" not in response: + raise AuthException(self) + + if response is not None: + access_token = ( + response.get("access_token") + or response.get("oauth_token") + or self.data.get("access_token") + ) + + if access_token is None: + if self.data.get("error") == "access_denied": + raise AuthCanceled(self) + else: + raise AuthException(self) + return self.do_auth(access_token, response, *args, **kwargs) + + def auth_html(self): + key, secret = self.get_key_and_secret() + namespace = self.setting("NAMESPACE", None) + scope = self.setting("SCOPE", "") + if scope: + scope = self.SCOPE_SEPARATOR.join(scope) + ctx = { + "FACEBOOK_APP_NAMESPACE": namespace or key, + "FACEBOOK_KEY": key, + "FACEBOOK_EXTENDED_PERMISSIONS": scope, + "FACEBOOK_COMPLETE_URI": self.redirect_uri, + } + tpl = self.setting("LOCAL_HTML", "facebook.html") + return self.strategy.render_html(tpl=tpl, context=ctx) + + def load_signed_request(self, signed_request): + def base64_url_decode(data): + data = data.encode("ascii") + data += b"=" * (4 - (len(data) % 4)) + return base64.urlsafe_b64decode(data) + + key, secret = self.get_key_and_secret() + try: + sig, payload = signed_request.split(".", 1) + except ValueError: + pass # ignore if can't split on dot + else: + sig = base64_url_decode(sig) + payload_json_bytes = base64_url_decode(payload) + data = json.loads(payload_json_bytes.decode("utf-8", "replace")) + expected_sig = hmac.new( + secret.encode("ascii"), + msg=payload.encode("ascii"), + digestmod=hashlib.sha256, + ).digest() + # allow the signed_request to function for upto 1 day + if constant_time_compare(sig, expected_sig) and data["issued_at"] > ( + time.time() - 86400 + ): + return data + + +class FacebookLimitedLogin(OpenIdConnectAuth): + """Facebook Limited Login (OIDC) backend""" + + name = "facebook-limited-login" + OIDC_ENDPOINT = "https://www.facebook.com" + ACCESS_TOKEN_URL = "https://facebook.com/dialog/oauth/" + ID_TOKEN_MAX_AGE = 3600 + + def authenticate(self, *args, **kwargs): + if ( + "backend" not in kwargs + or kwargs["backend"].name != self.name + or "strategy" not in kwargs + or "response" not in kwargs + ): + return None + + # Replace response with the decoded JWT + raw_jwt = kwargs.get("response", {}).get("access_token") + kwargs["response"] = self.validate_and_return_id_token(raw_jwt, "") + return super().authenticate(*args, **kwargs) + + def get_user_details(self, response): + return { + "fullname": response.get("name"), + "email": response.get("email"), + "picture": response.get("picture"), + } + + def user_data(self, access_token, *args, **kwargs): + # We don't have an access token to call any API for the user details. + return None + + def validate_claims(self, id_token): + try: + super().validate_claims(id_token) + except AuthTokenError as e: + if "Incorrect id_token: nonce" in e.args: + # Ignore errors about nonce. We can't validate it since it's not generated server-side. + return + raise diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fedora.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fedora.py new file mode 100644 index 0000000000000000000000000000000000000000..b212581cd10244d443e863c7a0565ad8ac2a5e81 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fedora.py @@ -0,0 +1,11 @@ +""" +Fedora OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/fedora.html +""" +from .open_id import OpenIdAuth + + +class FedoraOpenId(OpenIdAuth): + name = "fedora" + URL = "https://id.fedoraproject.org" + USERNAME_KEY = "nickname" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fence.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fence.py new file mode 100644 index 0000000000000000000000000000000000000000..1e66ad4aacfb11e002e3b43e8d503c5564c11997 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fence.py @@ -0,0 +1,37 @@ +from urllib.parse import urljoin + +from social_core.utils import cache + +from ..utils import append_slash +from .open_id_connect import OpenIdConnectAuth + + +class Fence(OpenIdConnectAuth): + name = "fence" + OIDC_ENDPOINT = "https://nci-crdc.datacommons.io" + ID_KEY = "username" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["openid", "user"] + JWT_DECODE_OPTIONS = {"verify_at_hash": False} + + def _url(self, path): + return urljoin(append_slash(self.OIDC_ENDPOINT), path) + + def authorization_url(self): + return self._url("user/oauth2/authorize") + + def access_token_url(self): + return self._url("user/oauth2/token") + + @cache(ttl=86400) + def oidc_config(self): + return self.get_json(self._url(".well-known/openid-configuration")) + + def get_user_details(self, response): + return { + "username": response.get("preferred_username"), + "email": response.get("username"), + "fullname": response.get("name"), + "first_name": response.get("given_name"), + "last_name": response.get("family_name"), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fitbit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fitbit.py new file mode 100644 index 0000000000000000000000000000000000000000..024d3c2191da5f458455d40a55894a055efec18e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/fitbit.py @@ -0,0 +1,65 @@ +""" +Fitbit OAuth backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/fitbit.html +""" +import base64 + +from .oauth import BaseOAuth1, BaseOAuth2 + + +class FitbitOAuth1(BaseOAuth1): + """Fitbit OAuth1 authentication backend""" + + name = "fitbit" + AUTHORIZATION_URL = "https://www.fitbit.com/oauth/authorize" + REQUEST_TOKEN_URL = "https://api.fitbit.com/oauth/request_token" + ACCESS_TOKEN_URL = "https://api.fitbit.com/oauth/access_token" + ID_KEY = "encodedId" + EXTRA_DATA = [("encodedId", "id"), ("displayName", "username")] + + def get_user_details(self, response): + """Return user details from Fitbit account""" + return {"username": response.get("displayName"), "email": ""} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.fitbit.com/1/user/-/profile.json", + auth=self.oauth_auth(access_token), + )["user"] + + +class FitbitOAuth2(BaseOAuth2): + """Fitbit OAuth2 authentication backend""" + + name = "fitbit" + AUTHORIZATION_URL = "https://www.fitbit.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://api.fitbit.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_URL = "https://api.fitbit.com/oauth2/token" + DEFAULT_SCOPE = ["profile"] + ID_KEY = "encodedId" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("expires_in", "expires"), + ("refresh_token", "refresh_token", True), + ("encodedId", "id"), + ("displayName", "username"), + ] + + def get_user_details(self, response): + """Return user details from Fitbit account""" + return {"username": response.get("displayName"), "email": ""} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + auth_header = {"Authorization": "Bearer %s" % access_token} + return self.get_json( + "https://api.fitbit.com/1/user/-/profile.json", headers=auth_header + )["user"] + + def auth_headers(self): + tokens = "{}:{}".format(*self.get_key_and_secret()) + tokens = base64.urlsafe_b64encode(tokens.encode()) + tokens = tokens.decode() + return {"Authorization": f"Basic {tokens}"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/five_hundred_px.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/five_hundred_px.py new file mode 100644 index 0000000000000000000000000000000000000000..30fb87fbe6e66073f51c44abfc6cfa8355855964 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/five_hundred_px.py @@ -0,0 +1,32 @@ +""" +500px OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/five_hundred_px.html +""" +from .oauth import BaseOAuth1 + + +class FiveHundredPxOAuth(BaseOAuth1): + """500px OAuth authentication backend""" + + name = "500px" + AUTHORIZATION_URL = "https://api.500px.com/v1/oauth/authorize" + REQUEST_TOKEN_URL = "https://api.500px.com/v1/oauth/request_token" + ACCESS_TOKEN_URL = "https://api.500px.com/v1/oauth/access_token" + + def get_user_details(self, user): + """Return user details from 500px account""" + fullname, first_name, last_name = self.get_user_names(user.get("fullname")) + return { + "username": user.get("username") or user.get("id"), + "email": user.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + response = self.get_json( + "https://api.500px.com/v1/users", auth=self.oauth_auth(access_token) + ) + return response.get("user") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flat.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flat.py new file mode 100644 index 0000000000000000000000000000000000000000..f14755bdaac9fa8043464e9bfcd6889610ae7290 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flat.py @@ -0,0 +1,33 @@ +""" +Flat OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/flat.html +""" +from .oauth import BaseOAuth2 + + +class FlatOAuth2(BaseOAuth2): + """Flat OAuth2""" + + name = "flat" + DEFAULT_SCOPE = ["account.public_profile"] + AUTHORIZATION_URL = "https://flat.io/auth/oauth" + ACCESS_TOKEN_URL = "https://api.flat.io/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_id(self, details, response): + return response.get("id") + + def get_user_details(self, response): + """Return user details from Flat account""" + return { + "email": response.get("email"), + "username": response.get("username"), + "fullname": response.get("printableName"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.flat.io/v2/me", + headers={"Authorization": "Bearer " + access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flickr.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flickr.py new file mode 100644 index 0000000000000000000000000000000000000000..a2e5b4117a6309eaf4699a42474c023ff5e1261f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/flickr.py @@ -0,0 +1,40 @@ +""" +Flickr OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/flickr.html +""" +from .oauth import BaseOAuth1 + + +class FlickrOAuth(BaseOAuth1): + """Flickr OAuth authentication backend""" + + name = "flickr" + AUTHORIZATION_URL = "https://www.flickr.com/services/oauth/authorize" + REQUEST_TOKEN_URL = "https://www.flickr.com/services/oauth/request_token" + ACCESS_TOKEN_URL = "https://www.flickr.com/services/oauth/access_token" + EXTRA_DATA = [("id", "id"), ("username", "username"), ("expires", "expires")] + + def get_user_details(self, response): + """Return user details from Flickr account""" + fullname, first_name, last_name = self.get_user_names(response.get("fullname")) + return { + "username": response.get("username") or response.get("id"), + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return { + "id": access_token["user_nsid"], + "username": access_token["username"], + "fullname": access_token.get("fullname", ""), + } + + def auth_extra_arguments(self): + params = super().auth_extra_arguments() or {} + if "perms" not in params: + params["perms"] = "read" + return params diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/foursquare.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/foursquare.py new file mode 100644 index 0000000000000000000000000000000000000000..cf87a2c745ab796ef9a8a7833e8439980d5bfc59 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/foursquare.py @@ -0,0 +1,38 @@ +""" +Foursquare OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/foursquare.html +""" +from .oauth import BaseOAuth2 + + +class FoursquareOAuth2(BaseOAuth2): + name = "foursquare" + AUTHORIZATION_URL = "https://foursquare.com/oauth2/authenticate" + ACCESS_TOKEN_URL = "https://foursquare.com/oauth2/access_token" + ACCESS_TOKEN_METHOD = "POST" + API_VERSION = "20140128" + + def get_user_id(self, details, response): + return response["response"]["user"]["id"] + + def get_user_details(self, response): + """Return user details from Foursquare account""" + info = response["response"]["user"] + email = info["contact"]["email"] + fullname, first_name, last_name = self.get_user_names( + first_name=info.get("firstName", ""), last_name=info.get("lastName", "") + ) + return { + "username": first_name + " " + last_name, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.foursquare.com/v2/users/self", + params={"oauth_token": access_token, "v": self.API_VERSION}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gae.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gae.py new file mode 100644 index 0000000000000000000000000000000000000000..fc67fba1b20f272c92dc0f34ecf4801970e8ae35 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gae.py @@ -0,0 +1,42 @@ +""" +Google App Engine support using User API +""" + +from google.appengine.api import users + +from ..exceptions import AuthException +from .base import BaseAuth + + +class GoogleAppEngineAuth(BaseAuth): + """GoogleAppengine authentication backend""" + + name = "google-appengine" + + def get_user_id(self, details, response): + """Return current user id.""" + user = users.get_current_user() + if user: + return user.user_id() + + def get_user_details(self, response): + """Return user basic information (id and email only).""" + user = users.get_current_user() + return { + "username": user.user_id(), + "email": user.email(), + "fullname": "", + "first_name": "", + "last_name": "", + } + + def auth_url(self): + """Build and return complete URL.""" + return users.create_login_url(self.redirect_uri) + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance.""" + if not users.get_current_user(): + raise AuthException("Authentication error") + kwargs.update({"response": "", "backend": self}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitea.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitea.py new file mode 100644 index 0000000000000000000000000000000000000000..3c67d8e264c056c5d8343519a3527bff516af880 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitea.py @@ -0,0 +1,50 @@ +""" +Gitea OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/gitea.html +""" +from .oauth import BaseOAuth2 + + +class GiteaOAuth2(BaseOAuth2): + """Gitea OAuth authentication backend""" + + name = "gitea" + API_URL = "https://gitea.com" + AUTHORIZATION_URL = "https://gitea.com/login/oauth/authorize" + ACCESS_TOKEN_URL = "https://gitea.com/login/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + STATE_PARAMETER = True + EXTRA_DATA = [ + ("id", "id"), + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ] + + def api_url(self, path): + api_url = self.setting("API_URL") or self.API_URL + return "{}{}".format(api_url.rstrip("/"), path) + + def authorization_url(self): + return self.api_url("/login/oauth/authorize") + + def access_token_url(self): + return self.api_url("/login/oauth/access_token") + + def get_user_details(self, response): + """Return user details from Gitea account""" + fullname, first_name, last_name = self.get_user_names(response.get("fullname")) + return { + "username": response.get("login"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.api_url("/api/v1/user"), params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github.py new file mode 100644 index 0000000000000000000000000000000000000000..40b0396922bf85435fe7a8929092beb90cf5f8e6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github.py @@ -0,0 +1,143 @@ +""" +Github OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/github.html +""" +from urllib.parse import urljoin + +from requests import HTTPError + +from ..exceptions import AuthFailed +from .oauth import BaseOAuth2 + + +class GithubOAuth2(BaseOAuth2): + """Github OAuth authentication backend""" + + name = "github" + API_URL = "https://api.github.com/" + AUTHORIZATION_URL = "https://github.com/login/oauth/authorize" + ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + STATE_PARAMETER = True + SEND_USER_AGENT = True + EXTRA_DATA = [("id", "id"), ("expires", "expires"), ("login", "login")] + + def api_url(self): + return self.API_URL + + def get_user_details(self, response): + """Return user details from Github account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("login"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + data = self._user_data(access_token) + if not data.get("email"): + try: + emails = self._user_data(access_token, "/emails") + except (HTTPError, ValueError, TypeError): + emails = [] + + if emails: + email = emails[0] + primary_emails = [ + e for e in emails if not isinstance(e, dict) or e.get("primary") + ] + if primary_emails: + email = primary_emails[0] + if isinstance(email, dict): + email = email.get("email", "") + data["email"] = email + return data + + def _user_data(self, access_token, path=None): + url = urljoin(self.api_url(), "user{}".format(path or "")) + return self.get_json(url, headers={"Authorization": f"token {access_token}"}) + + +class GithubMemberOAuth2(GithubOAuth2): + no_member_string = "" + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + user_data = super().user_data(access_token, *args, **kwargs) + headers = {"Authorization": f"token {access_token}"} + try: + self.request(self.member_url(user_data), headers=headers) + except HTTPError as err: + # if the user is a member of the organization, response code + # will be 204, see http://bit.ly/ZS6vFl + if err.response.status_code != 204: + raise AuthFailed(self, "User doesn't belong to the organization") + return user_data + + def member_url(self, user_data): + raise NotImplementedError("Implement in subclass") + + +class GithubOrganizationOAuth2(GithubMemberOAuth2): + """Github OAuth2 authentication backend for organizations""" + + name = "github-org" + no_member_string = "User doesn't belong to the organization" + + def member_url(self, user_data): + return urljoin( + self.api_url(), + "orgs/{org}/members/{username}".format( + org=self.setting("NAME"), username=user_data.get("login") + ), + ) + + +class GithubTeamOAuth2(GithubMemberOAuth2): + """Github OAuth2 authentication backend for teams""" + + name = "github-team" + no_member_string = "User doesn't belong to the team" + + def member_url(self, user_data): + return urljoin( + self.api_url(), + "teams/{team_id}/members/{username}".format( + team_id=self.setting("ID"), username=user_data.get("login") + ), + ) + + +class GithubAppAuth(GithubOAuth2): + """GitHub App OAuth authentication backend""" + + name = "github-app" + + def validate_state(self): + """ + Scenario 1: user clicks an icon/button on your website and initiates + social login. This works exacltly like standard OAuth and we + have `state` and `redirect_uri`. + + Scenario 2: user starts from http://github.com/apps/your-app and clicks + 'Install & Authorize' button! They still get a temporary + `code` (used to fetch `access_token`) but there's no `state` + or `redirect_uri` here. + + Note: Scenario 2 only happens when your GitHub App is configured + with `Request user authorization (OAuth) during installation` + turned on! This causes GitHub to redirect the person back to + `/complete/github/`. If the above setting is turned off then + GitHub will redirect to another URL called Setup URL and the + person may need to login first before they can continue! + """ + if self.data.get("installation_id") and self.data.get("setup_action"): + return None + + return super().validate_state() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github_enterprise.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github_enterprise.py new file mode 100644 index 0000000000000000000000000000000000000000..7c1d0daafaab9aab89a68b90628cb92cbcac0c6c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/github_enterprise.py @@ -0,0 +1,45 @@ +""" +Github Enterprise OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/github_enterprise.html +""" +from urllib.parse import urljoin + +from ..utils import append_slash +from .github import GithubOAuth2, GithubOrganizationOAuth2, GithubTeamOAuth2 + + +class GithubEnterpriseMixin: + def api_url(self): + return append_slash(self.setting("API_URL")) + + def authorization_url(self): + return self._url("login/oauth/authorize") + + def access_token_url(self): + return self._url("login/oauth/access_token") + + def _url(self, path): + return urljoin(append_slash(self.setting("URL")), path) + + +class GithubEnterpriseOAuth2(GithubEnterpriseMixin, GithubOAuth2): + """Github Enterprise OAuth authentication backend""" + + name = "github-enterprise" + + +class GithubEnterpriseOrganizationOAuth2( + GithubEnterpriseMixin, GithubOrganizationOAuth2 +): + """Github Enterprise OAuth2 authentication backend for + organizations""" + + name = "github-enterprise-org" + DEFAULT_SCOPE = ["read:org"] + + +class GithubEnterpriseTeamOAuth2(GithubEnterpriseMixin, GithubTeamOAuth2): + """Github Enterprise OAuth2 authentication backend for teams""" + + name = "github-enterprise-team" + DEFAULT_SCOPE = ["read:org"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitlab.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitlab.py new file mode 100644 index 0000000000000000000000000000000000000000..fbb8797d06b29532759580be26eaaeadbd12d1e7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/gitlab.py @@ -0,0 +1,54 @@ +""" +GitLab OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/gitlab.html + +Thanks to [@saily](https://github.com/saily) who published an +implementation for GitLab support on his blog post [Weblate with +GitLab as OAuth provider](http://widerin.net/blog/weblate-gitlab-oauth-login/). +His code was a great reference when working on this implementation. +""" +from .oauth import BaseOAuth2 + + +class GitLabOAuth2(BaseOAuth2): + """GitLab OAuth authentication backend""" + + name = "gitlab" + API_URL = "https://gitlab.com" + AUTHORIZATION_URL = "https://gitlab.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://gitlab.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + DEFAULT_SCOPE = ["read_user"] + EXTRA_DATA = [ + ("id", "id"), + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ] + + def api_url(self, path): + api_url = self.setting("API_URL") or self.API_URL + return "{}{}".format(api_url.rstrip("/"), path) + + def authorization_url(self): + return self.api_url("/oauth/authorize") + + def access_token_url(self): + return self.api_url("/oauth/token") + + def get_user_details(self, response): + """Return user details from GitLab account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("username"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.api_url("/api/v4/user"), params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/globus.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/globus.py new file mode 100644 index 0000000000000000000000000000000000000000..4a651799463889d095b08b451cc4ef2ccf0e7375 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/globus.py @@ -0,0 +1,31 @@ +""" +Globus Auth OpenID Connect backend, docs at: + https://docs.globus.org/api/auth + http://globus-integration-examples.readthedocs.io +""" + +from social_core.backends.open_id_connect import OpenIdConnectAuth + + +class GlobusOpenIdConnect(OpenIdConnectAuth): + name = "globus" + OIDC_ENDPOINT = "https://auth.globus.org" + JWT_ALGORITHMS = ["RS256", "RS512"] + EXTRA_DATA = [ + ("expires_in", "expires_in", True), + ("refresh_token", "refresh_token", True), + ("id_token", "id_token", True), + ("other_tokens", "other_tokens", True), + ] + + def get_user_details(self, response): + username_key = self.setting("USERNAME_KEY", default=self.USERNAME_KEY) + name = response.get("name") or "" + fullname, first_name, last_name = self.get_user_names(name) + return { + "username": response.get(username_key), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclio.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclio.py new file mode 100644 index 0000000000000000000000000000000000000000..a14df9d1cd540464a044ca6cb2a4d28875e9f09a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclio.py @@ -0,0 +1,39 @@ +from .oauth import BaseOAuth2 + + +class GoClioOAuth2(BaseOAuth2): + name = "goclio" + AUTHORIZATION_URL = "https://app.goclio.com/oauth/authorize/" + ACCESS_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://app.goclio.com/oauth/token/" + REDIRECT_STATE = False + STATE_PARAMETER = False + + def get_user_details(self, response): + """Return user details from GoClio account""" + user = response.get("user", {}) + username = user.get("id", None) + email = user.get("email", None) + first_name, last_name = ( + user.get("first_name", None), + user.get("last_name", None), + ) + fullname = f"{first_name} {last_name}" + + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://app.goclio.com/api/v2/users/who_am_i", + params={"access_token": access_token}, + ) + + def get_user_id(self, details, response): + return response.get("user", {}).get("id") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclioeu.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclioeu.py new file mode 100644 index 0000000000000000000000000000000000000000..c9029ada1da0afe570acf1c9b11eaf1e0fcc8f48 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/goclioeu.py @@ -0,0 +1,14 @@ +from .goclio import GoClioOAuth2 + + +class GoClioEuOAuth2(GoClioOAuth2): + name = "goclioeu" + AUTHORIZATION_URL = "https://app.goclio.eu/oauth/authorize/" + ACCESS_TOKEN_URL = "https://app.goclio.eu/oauth/token/" + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://app.goclio.eu/api/v2/users/who_am_i", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google.py new file mode 100644 index 0000000000000000000000000000000000000000..211313cfa3747186b0dfc98db5d0976d8559cedc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google.py @@ -0,0 +1,170 @@ +""" +Google OpenId, OAuth2, OAuth1, Google+ Sign-in backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/google.html +""" +from ..exceptions import AuthMissingParameter +from ..utils import handle_http_errors +from .oauth import BaseOAuth1, BaseOAuth2 + + +class BaseGoogleAuth: + def get_user_id(self, details, response): + """Use google email as unique id""" + if self.setting("USE_UNIQUE_USER_ID", False): + if "sub" in response: + return response["sub"] + else: + return response["id"] + else: + return details["email"] + + def get_user_details(self, response): + """Return user details from Google API account""" + email = response.get("email", "") + + name, given_name, family_name = ( + response.get("name", ""), + response.get("given_name", ""), + response.get("family_name", ""), + ) + + fullname, first_name, last_name = self.get_user_names( + name, given_name, family_name + ) + return { + "username": email.split("@", 1)[0], + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + +class BaseGoogleOAuth2API(BaseGoogleAuth): + def user_data(self, access_token, *args, **kwargs): + """Return user data from Google API""" + return self.get_json( + "https://www.googleapis.com/oauth2/v3/userinfo", + headers={ + "Authorization": "Bearer %s" % access_token, + }, + ) + + def revoke_token_params(self, token, uid): + return {"token": token} + + def revoke_token_headers(self, token, uid): + return {"Content-type": "application/json"} + + +class GoogleOAuth2(BaseGoogleOAuth2API, BaseOAuth2): + """Google OAuth2 authentication backend""" + + name = "google-oauth2" + REDIRECT_STATE = False + AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/auth" + ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REVOKE_TOKEN_URL = "https://accounts.google.com/o/oauth2/revoke" + REVOKE_TOKEN_METHOD = "GET" + # The order of the default scope is important + DEFAULT_SCOPE = ["openid", "email", "profile"] + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("expires_in", "expires"), + ("token_type", "token_type", True), + ] + + +class GooglePlusAuth(BaseGoogleOAuth2API, BaseOAuth2): + name = "google-plus" + REDIRECT_STATE = False + STATE_PARAMETER = False + AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/auth" + ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REVOKE_TOKEN_URL = "https://accounts.google.com/o/oauth2/revoke" + REVOKE_TOKEN_METHOD = "GET" + DEFAULT_SCOPE = [ + "https://www.googleapis.com/auth/plus.login", + "https://www.googleapis.com/auth/plus.me", + ] + EXTRA_DATA = [ + ("id", "user_id"), + ("refresh_token", "refresh_token", True), + ("expires_in", "expires"), + ("access_type", "access_type", True), + ("code", "code"), + ] + + def auth_complete_params(self, state=None): + params = super().auth_complete_params(state) + if self.data.get("access_token"): + # Don't add postmessage if this is plain server-side workflow + params["redirect_uri"] = "postmessage" + return params + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + if "access_token" in self.data: # Client-side workflow + token = self.data.get("access_token") + response = self.get_json( + "https://www.googleapis.com/oauth2/v3/tokeninfo", + params={"access_token": token}, + ) + self.process_error(response) + return self.do_auth(token, response=response, *args, **kwargs) + elif "code" in self.data: # Server-side workflow + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + data=self.auth_complete_params(), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + elif "id_token" in self.data: # Client-side workflow + token = self.data.get("id_token") + return self.do_auth(token, *args, **kwargs) + else: + raise AuthMissingParameter(self, "access_token, id_token, or code") + + def user_data(self, access_token, *args, **kwargs): + if "id_token" not in self.data: + return super().user_data(access_token, *args, **kwargs) + response = self.get_json( + "https://www.googleapis.com/oauth2/v3/tokeninfo", + params={"id_token": access_token}, + ) + self.process_error(response) + return response + + +class GoogleOAuth(BaseGoogleAuth, BaseOAuth1): + """Google OAuth authorization mechanism""" + + name = "google-oauth" + AUTHORIZATION_URL = "https://www.google.com/accounts/OAuthAuthorizeToken" + REQUEST_TOKEN_URL = "https://www.google.com/accounts/OAuthGetRequestToken" + ACCESS_TOKEN_URL = "https://www.google.com/accounts/OAuthGetAccessToken" + DEFAULT_SCOPE = ["https://www.googleapis.com/auth/userinfo#email"] + + def user_data(self, access_token, *args, **kwargs): + """Return user data from Google API""" + return self.get_querystring( + "https://www.googleapis.com/userinfo/email", + auth=self.oauth_auth(access_token), + ) + + def get_key_and_secret(self): + """Return Google OAuth Consumer Key and Consumer Secret pair, uses + anonymous by default, beware that this marks the application as not + registered and a security badge is displayed on authorization page. + http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth + """ + key_secret = super().get_key_and_secret() + if key_secret == (None, None): + key_secret = ("anonymous", "anonymous") + return key_secret diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google_openidconnect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google_openidconnect.py new file mode 100644 index 0000000000000000000000000000000000000000..6d1fbf6380b36f86d49613a95032c7dcff3b111d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/google_openidconnect.py @@ -0,0 +1,21 @@ +""" +Google OpenIdConnect: + https://python-social-auth.readthedocs.io/en/latest/backends/google.html +""" +from .google import GoogleOAuth2 +from .open_id_connect import OpenIdConnectAuth + + +class GoogleOpenIdConnect(GoogleOAuth2, OpenIdConnectAuth): + name = "google-openidconnect" + OIDC_ENDPOINT = "https://accounts.google.com" + # differs from value in discovery document + # http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.15.6.2 + ID_TOKEN_ISSUER = "accounts.google.com" + + def user_data(self, access_token, *args, **kwargs): + """Return user data from Google API""" + return self.get_json( + "https://openidconnect.googleapis.com/v1/userinfo", + params={"access_token": access_token, "alt": "json"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/grafana.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/grafana.py new file mode 100644 index 0000000000000000000000000000000000000000..1c74981b919ca4fa801e559300160104456d14d7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/grafana.py @@ -0,0 +1,29 @@ +from social_core.backends.oauth import BaseOAuth2 + + +class GrafanaOAuth2(BaseOAuth2): + """Grafana OAuth authentication backend""" + + name = "grafana" + AUTHORIZATION_URL = "https://grafana.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://grafana.com/api/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["profile", "email"] + SCOPE_SEPARATOR = "," + USER_DETAILS_URL = "https://grafana.com/api/oauth2/user" + + def get_user_details(self, response): + """Return user details from Grafana account""" + return { + "username": response.get("login"), + "email": response.get("email") or "", + "first_name": response.get("name"), + "last_name": "-", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.USER_DETAILS_URL, + **{"headers": {"Authorization": f"Bearer {access_token}"}}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/hubspot.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/hubspot.py new file mode 100644 index 0000000000000000000000000000000000000000..8c47a6fd4beaf5858a8498887521518f36956c45 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/hubspot.py @@ -0,0 +1,36 @@ +""" +HubSpot OAuth2 backend, docs at: + https://developers.hubspot.com/docs/methods/oauth2/oauth2-overview +""" +from .oauth import BaseOAuth2 + + +class HubSpotOAuth2(BaseOAuth2): + """HubSpot OAuth2 authentication backend""" + + name = "hubspot" + AUTHORIZATION_URL = "https://app.hubspot.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.hubapi.com/oauth/v1/token" + ACCESS_TOKEN_METHOD = "POST" + USER_DATA_URL = "https://api.hubapi.com/oauth/v1/access-tokens/" + DEFAULT_SCOPE = ["oauth"] + EXTRA_DATA = [ + ("hub_domain", "hub_domain"), + ("hub_id", "hub_id"), + ("app_id", "app_id"), + ("user_id", "user_id"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires"), + ] + + def get_user_details(self, response): + """Return user details""" + response["email"] = response["user"] + return response + + def user_data(self, access_token, *args, **kwargs): + """Loads user data information from service""" + return self.get_json( + self.USER_DATA_URL + access_token, + headers={"Authorization": "Bearer " + access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/instagram.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/instagram.py new file mode 100644 index 0000000000000000000000000000000000000000..1dbb777c5fa38f7442044b14ebb3680323611a97 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/instagram.py @@ -0,0 +1,43 @@ +""" +Instagram OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/instagram.html +""" +from .oauth import BaseOAuth2 + + +class InstagramOAuth2(BaseOAuth2): + name = "instagram" + AUTHORIZATION_URL = "https://api.instagram.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.instagram.com/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_id(self, details, response): + user = response.get("user") or {} + return user.get("id") + + def get_user_details(self, response): + """Return user details from Instagram account""" + user = response.get("user") or {} + username = user["username"] + email = user.get("email", "") + fullname, first_name, last_name = self.get_user_names(user.get("full_name", "")) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + # For more fields see: + # https://developers.facebook.com/docs/instagram-basic-display-api/reference/user#fields + # In fact there are not very many of them. + fields = "id,username" + params = {"access_token": access_token, "fields": fields} + response = self.get_json("https://graph.instagram.com/me", params=params) + return {"user": response} + + def auth_html(self): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/itembase.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/itembase.py new file mode 100644 index 0000000000000000000000000000000000000000..6635d4dee87f1036b5e437aaa87af1ea64cbba8c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/itembase.py @@ -0,0 +1,89 @@ +import time + +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class ItembaseOAuth2(BaseOAuth2): + name = "itembase" + ID_KEY = "uuid" + AUTHORIZATION_URL = "https://accounts.itembase.com/oauth/v2/auth" + ACCESS_TOKEN_URL = "https://accounts.itembase.com/oauth/v2/token" + USER_DETAILS_URL = "https://users.itembase.com/v1/me" + ACTIVATION_ENDPOINT = "https://solutionservice.itembase.com/activate" + DEFAULT_SCOPE = ["user.minimal"] + EXTRA_DATA = [ + ("access_token", "access_token"), + ("token_type", "token_type"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires_in"), # seconds to expiration + ("expires", "expires"), # expiration timestamp in UTC + ("uuid", "uuid"), + ("username", "username"), + ("email", "email"), + ("first_name", "first_name"), + ("middle_name", "middle_name"), + ("last_name", "last_name"), + ("name_format", "name_format"), + ("locale", "locale"), + ("preferred_currency", "preferred_currency"), + ] + + def add_expires(self, data): + data["expires"] = int(time.time()) + data.get("expires_in", 0) + return data + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + data = BaseOAuth2.extra_data( + self, user, uid, response, details=details, *args, **kwargs + ) + return self.add_expires(data) + + def process_refresh_token_response(self, response, *args, **kwargs): + data = BaseOAuth2.process_refresh_token_response( + self, response, *args, **kwargs + ) + return self.add_expires(data) + + def get_user_details(self, response): + """Return user details from Itembase account""" + return response + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + self.USER_DETAILS_URL, headers={"Authorization": f"Bearer {access_token}"} + ) + + def activation_data(self, response): + # returns activation_data dict with activation_url inside + # see http://developers.itembase.com/authentication/activation + return self.get_json( + self.ACTIVATION_ENDPOINT, + headers={"Authorization": "Bearer {}".format(response["access_token"])}, + ) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + state = self.validate_state() + self.process_error(self.data) + # itembase needs GET request with params instead of just data + response = self.request_access_token( + self.access_token_url(), + params=self.auth_complete_params(state), + headers=self.auth_headers(), + auth=self.auth_complete_credentials(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + +class ItembaseOAuth2Sandbox(ItembaseOAuth2): + name = "itembase-sandbox" + AUTHORIZATION_URL = "http://sandbox.accounts.itembase.io/oauth/v2/auth" + ACCESS_TOKEN_URL = "http://sandbox.accounts.itembase.io/oauth/v2/token" + USER_DETAILS_URL = "http://sandbox.users.itembase.io/v1/me" + ACTIVATION_ENDPOINT = "http://sandbox.solutionservice.itembase.io/activate" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/jawbone.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/jawbone.py new file mode 100644 index 0000000000000000000000000000000000000000..4fe2440c15029deceb9c8049a9d56502c3751e64 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/jawbone.py @@ -0,0 +1,75 @@ +""" +Jawbone OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/jawbone.html +""" +from ..exceptions import AuthCanceled, AuthUnknownError +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class JawboneOAuth2(BaseOAuth2): + name = "jawbone" + AUTHORIZATION_URL = "https://jawbone.com/auth/oauth2/auth" + ACCESS_TOKEN_URL = "https://jawbone.com/auth/oauth2/token" + SCOPE_SEPARATOR = " " + REDIRECT_STATE = False + + def get_user_id(self, details, response): + return response["data"]["xid"] + + def get_user_details(self, response): + """Return user details from Jawbone account""" + data = response["data"] + fullname, first_name, last_name = self.get_user_names( + first_name=data.get("first", ""), last_name=data.get("last", "") + ) + return { + "username": first_name + " " + last_name, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "dob": data.get("dob", ""), + "gender": data.get("gender", ""), + "height": data.get("height", ""), + "weight": data.get("weight", ""), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://jawbone.com/nudge/api/users/@me", + headers={"Authorization": "Bearer " + access_token}, + ) + + def process_error(self, data): + error = data.get("error") + if error: + if error == "access_denied": + raise AuthCanceled(self) + else: + raise AuthUnknownError(self, f"Jawbone error was {error}") + return super().process_error(data) + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "client_id": client_id, + "client_secret": client_secret, + } + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + params=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/justgiving.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/justgiving.py new file mode 100644 index 0000000000000000000000000000000000000000..0c78a4627f7150423874a3757815413f38892fc2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/justgiving.py @@ -0,0 +1,61 @@ +from requests.auth import HTTPBasicAuth + +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class JustGivingOAuth2(BaseOAuth2): + """Just Giving OAuth authentication backend""" + + name = "justgiving" + ID_KEY = "userId" + AUTHORIZATION_URL = "https://identity.justgiving.com/connect/authorize" + ACCESS_TOKEN_URL = "https://identity.justgiving.com/connect/token" + ACCESS_TOKEN_METHOD = "POST" + USER_DATA_URL = "https://api.justgiving.com/v1/account" + DEFAULT_SCOPE = ["openid", "account", "profile", "email", "fundraise"] + + def get_user_details(self, response): + """Return user details from Just Giving account""" + fullname, first_name, last_name = self.get_user_names( + "", response.get("firstName"), response.get("lastName") + ) + return { + "username": response.get("email"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + key, secret = self.get_key_and_secret() + return self.get_json( + self.USER_DATA_URL, + headers={ + "Authorization": f"Bearer {access_token}", + "Content-Type": "application/json", + "x-application-key": secret, + "x-api-key": key, + }, + ) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + state = self.validate_state() + self.process_error(self.data) + + key, secret = self.get_key_and_secret() + response = self.request_access_token( + self.access_token_url(), + data=self.auth_complete_params(state), + headers=self.auth_headers(), + auth=HTTPBasicAuth(key, secret), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/kakao.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/kakao.py new file mode 100644 index 0000000000000000000000000000000000000000..717719c2fb31d2477aeb0734551a3e16d0cacd2d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/kakao.py @@ -0,0 +1,58 @@ +""" +Kakao OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/kakao.html +""" +from .oauth import BaseOAuth2 + + +class KakaoOAuth2(BaseOAuth2): + """Kakao OAuth authentication backend""" + + name = "kakao" + AUTHORIZATION_URL = "https://kauth.kakao.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://kauth.kakao.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("properties", "properties"), + ] + + def get_user_id(self, details, response): + return response["id"] + + def get_user_details(self, response): + """Return user details from Kakao account""" + + kaccount_email = "" + kakao_account = response.get("kakao_account", "") + if kakao_account: + kaccount_email = kakao_account.get("email", "") + properties = response.get("properties", "") + nickname = properties.get("nickname") if properties else "" + return { + "username": nickname, + "email": kaccount_email, + "fullname": nickname, + "first_name": nickname[1:] if nickname else "", + "last_name": nickname[0] if nickname else "", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://kapi.kakao.com/v2/user/me", + headers={ + "Authorization": f"Bearer {access_token}", + "Content_Type": "application/x-www-form-urlencoded;charset=utf-8", + }, + params={"access_token": access_token}, + ) + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", + "code": self.data.get("code", ""), + "client_id": client_id, + "client_secret": client_secret, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/keycloak.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/keycloak.py new file mode 100644 index 0000000000000000000000000000000000000000..9d02aeea536dcf77eee6ce291d07e5d5d9881cd6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/keycloak.py @@ -0,0 +1,143 @@ +import jwt + +from social_core.backends.oauth import BaseOAuth2 + + +class KeycloakOAuth2(BaseOAuth2): # pylint: disable=abstract-method + """Keycloak OAuth2 authentication backend + + This backend has been tested working with a standard Keycloak installation, + but you might have to specialize it and tune the parameters per your + configuration. + + This setup specializes the OAuth2 backend which, strictly speaking, offers + authorization without authentication capabilities. + + Keycloak does offer a full OpenID Connect implementation, but the + implementation is rather labor intensive to implement. + + This backend is configured to get an access token instead, and assume that + the access token contains the necessary user details for authentication. + + The integrity of the authentication process is followed by public key + verification for the `access_token` along with OpenID Connect specification + `aud` field checking. + + To set up, please take the following steps: + + 1. Create a new Keycloak client in the Clients section. + + 2. Configure the following parameters in the Client setup: + + Settings > + Client ID (copy to settings as `KEY` value) + Credentials > + Client Authenticator > + Secret (copy to settings as `SECRET` value) + + 3. For the tokens to work with the JWT setup the following configuration has + to be made in Keycloak: + + Settings > + Access Type > + confidential + Settings > + Fine Grain OpenID Connect Configuration > + User Info Signed + Response Algorithm > + RS256 + Settings > + Fine Grain OpenID Connect Configuration > + Request Object Signature Algorithm > RS256 + + 4. Get the public key (copy to settings as `PUBLIC_KEY` value) to be used + with the backend: + + Realm Settings > Keys > Public key + + 5. Configure access token fields are configured via the Keycloak Client + mappers: + + Clients > Client ID > Mappers + + They have to include at least the `ID_KEY` value and the dictionary keys + defined in the `get_user_details` method. + + 6. Configure your web backend. Example setting values for Django settings + could be: + + SOCIAL_AUTH_KEYCLOAK_KEY = 'example' + SOCIAL_AUTH_KEYCLOAK_SECRET = '1234abcd-1234-abcd-1234-abcd1234adcd' + SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = \ + 'pempublickeythatis2048bitsinbase64andhaseg392characters' + SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = \ + 'https://sso.com/auth/realms/example/protocol/openid-connect/auth' + SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = \ + 'https://sso.com/auth/realms/example/protocol/openid-connect/token' + + 7. The default behaviour is to associate users via username field, but you + can change the key with e.g. + + SOCIAL_AUTH_KEYCLOAK_ID_KEY = 'email' + + Please make sure your Keycloak user database and Django user database do not + conflict and that there is no risk of user account hijacking by false + account association. + """ + + name = "keycloak" + ID_KEY = "username" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def authorization_url(self): + return self.setting("AUTHORIZATION_URL") + + def access_token_url(self): + return self.setting("ACCESS_TOKEN_URL") + + def audience(self): + return self.setting("KEY") + + def algorithm(self): + return self.setting("ALGORITHM", default="RS256") + + def public_key(self): + return "\n".join( + [ + "-----BEGIN PUBLIC KEY-----", + self.setting("PUBLIC_KEY"), + "-----END PUBLIC KEY-----", + ] + ) + + def user_data( + self, access_token, *args, **kwargs + ): # pylint: disable=unused-argument + """Decode user data from the access_token + + You can specialize this method to e.g. get information + from the Keycloak backend if you do not want to include + the user information in the access_token. + """ + + return jwt.decode( + access_token, + key=self.public_key(), + algorithms=self.algorithm(), + audience=self.audience(), + ) + + def get_user_details(self, response): + """Map fields in user_data into Django User fields""" + return { + "username": response.get("preferred_username"), + "email": response.get("email"), + "fullname": response.get("name"), + "first_name": response.get("given_name"), + "last_name": response.get("family_name"), + } + + def get_user_id(self, details, response): + """Get and associate Django User by the field indicated by ID_KEY""" + return details.get(self.ID_KEY) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/khanacademy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/khanacademy.py new file mode 100644 index 0000000000000000000000000000000000000000..00015bb5c6ffc02de894e15b9ceaba2294fefc84 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/khanacademy.py @@ -0,0 +1,123 @@ +""" +Khan Academy OAuth backend, docs at: + https://github.com/Khan/khan-api/wiki/Khan-Academy-API-Authentication +""" +from urllib.parse import urlencode + +from oauthlib.oauth1 import SIGNATURE_HMAC, SIGNATURE_TYPE_QUERY +from requests_oauthlib import OAuth1 + +from .oauth import BaseOAuth1 + + +class BrowserBasedOAuth1(BaseOAuth1): + """Browser based mechanism OAuth authentication, fill the needed + parameters to communicate properly with authentication service. + + REQUEST_TOKEN_URL Request token URL (opened in web browser) + ACCESS_TOKEN_URL Access token URL + """ + + REQUEST_TOKEN_URL = "" + OAUTH_TOKEN_PARAMETER_NAME = "oauth_token" + REDIRECT_URI_PARAMETER_NAME = "redirect_uri" + ACCESS_TOKEN_URL = "" + + def auth_url(self): + """Return redirect url""" + return self.unauthorized_token_request() + + def get_unauthorized_token(self): + return self.strategy.request_data() + + def unauthorized_token_request(self): + """Return request for unauthorized token (first stage)""" + + params = self.request_token_extra_arguments() + params.update(self.get_scope_argument()) + key, secret = self.get_key_and_secret() + state = self.get_or_create_state() + auth = OAuth1( + key, + secret, + callback_uri=self.get_redirect_uri(state), + signature_method=SIGNATURE_HMAC, + signature_type=SIGNATURE_TYPE_QUERY, + decoding=None, + ) + url = self.REQUEST_TOKEN_URL + "?" + urlencode(params) + url, _, _ = auth.client.sign(url) + return url + + def oauth_auth(self, token=None, oauth_verifier=None): + key, secret = self.get_key_and_secret() + oauth_verifier = oauth_verifier or self.data.get("oauth_verifier") + token = token or {} + state = self.get_or_create_state() + return OAuth1( + key, + secret, + resource_owner_key=token.get("oauth_token"), + resource_owner_secret=token.get("oauth_token_secret"), + callback_uri=self.get_redirect_uri(state), + verifier=oauth_verifier, + signature_method=SIGNATURE_HMAC, + signature_type=SIGNATURE_TYPE_QUERY, + decoding=None, + ) + + +class KhanAcademyOAuth1(BrowserBasedOAuth1): + """ + Class used for autorising with Khan Academy. + + Flow of Khan Academy is a bit different than most OAuth 1.0 and consinsts + of the following steps: + 1. Create signed params to attach to the REQUEST_TOKEN_URL + 2. Redirect user to the REQUEST_TOKEN_URL that will respond with + oauth_secret, oauth_token, oauth_verifier that should be used with + ACCESS_TOKEN_URL + 3. Go to ACCESS_TOKEN_URL and grab oauth_token_secret. + + Note that we don't use the AUTHORIZATION_URL. + + REQUEST_TOKEN_URL requires the following arguments: + oauth_consumer_key - Your app's consumer key + oauth_nonce - Random 64-bit, unsigned number encoded as an ASCII string + in decimal format. The nonce/timestamp pair should always be unique. + oauth_version - OAuth version used by your app. Must be "1.0" for now. + oauth_signature - String generated using the referenced signature method. + oauth_signature_method - Signature algorithm (currently only support + "HMAC-SHA1") + oauth_timestamp - Integer representing the time the request is sent. + The timestamp should be expressed in number of seconds + after January 1, 1970 00:00:00 GMT. + oauth_callback (optional) - URL to redirect to after request token is + received and authorized by the user's chosen identity provider. + """ + + name = "khanacademy-oauth1" + ID_KEY = "user_id" + REQUEST_TOKEN_URL = "http://www.khanacademy.org/api/auth/request_token" + ACCESS_TOKEN_URL = "https://www.khanacademy.org/api/auth/access_token" + REDIRECT_URI_PARAMETER_NAME = "oauth_callback" + USER_DATA_URL = "https://www.khanacademy.org/api/v1/user" + + EXTRA_DATA = [("user_id", "user_id")] + + def get_user_details(self, response): + """Return user details from Khan Academy account""" + return { + "username": response.get("email"), + "email": response.get("email"), + "fullname": response.get("nickname"), + "first_name": "", + "last_name": "", + "user_id": response.get("user_id"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + auth = self.oauth_auth(access_token) + url, _, _ = auth.client.sign(self.USER_DATA_URL) + return self.get_json(url) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lastfm.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lastfm.py new file mode 100644 index 0000000000000000000000000000000000000000..735d3d422b02ddc32f7545b7b893e1ec5c2535b7 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lastfm.py @@ -0,0 +1,64 @@ +import hashlib + +from ..utils import handle_http_errors +from .base import BaseAuth + + +class LastFmAuth(BaseAuth): + """ + Last.Fm authentication backend. Requires two settings: + SOCIAL_AUTH_LASTFM_KEY + SOCIAL_AUTH_LASTFM_SECRET + + Don't forget to set the Last.fm callback to something sensible like + http://your.site/lastfm/complete + """ + + name = "lastfm" + AUTH_URL = "http://www.last.fm/api/auth/?api_key={api_key}" + EXTRA_DATA = [("key", "session_key")] + + def auth_url(self): + return self.AUTH_URL.format(api_key=self.setting("KEY")) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + key, secret = self.get_key_and_secret() + token = self.data["token"] + + signature = hashlib.md5( + "".join( + ("api_key", key, "methodauth.getSession", "token", token, secret) + ).encode() + ).hexdigest() + + response = self.get_json( + "http://ws.audioscrobbler.com/2.0/", + data={ + "method": "auth.getSession", + "api_key": key, + "token": token, + "api_sig": signature, + "format": "json", + }, + method="POST", + ) + + kwargs.update({"response": response["session"], "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def get_user_id(self, details, response): + """Return a unique ID for the current user, by default from server + response.""" + return response.get("name") + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names(response["name"]) + return { + "username": response["name"], + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/launchpad.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/launchpad.py new file mode 100644 index 0000000000000000000000000000000000000000..ba88aee3e132a940a074db943b05062026f65456 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/launchpad.py @@ -0,0 +1,11 @@ +""" +Launchpad OpenId backend +""" + +from .open_id import OpenIdAuth + + +class LaunchpadOpenId(OpenIdAuth): + name = "launchpad" + URL = "https://login.launchpad.net" + USERNAME_KEY = "nickname" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/legacy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/legacy.py new file mode 100644 index 0000000000000000000000000000000000000000..856b0ffc7e2f28f300cfb6e9df870247acd5500f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/legacy.py @@ -0,0 +1,42 @@ +from ..exceptions import AuthMissingParameter +from .base import BaseAuth + + +class LegacyAuth(BaseAuth): + def get_user_id(self, details, response): + return details.get(self.ID_KEY) or response.get(self.ID_KEY) + + def auth_url(self): + return self.setting("FORM_URL") + + def auth_html(self): + return self.strategy.render_html(tpl=self.setting("FORM_HTML")) + + def uses_redirect(self): + return self.setting("FORM_URL") and not self.setting("FORM_HTML") + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + if self.ID_KEY not in self.data: + raise AuthMissingParameter(self, self.ID_KEY) + kwargs.update({"response": self.data, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def get_user_details(self, response): + """Return user details""" + email = response.get("email", "") + username = response.get("username", "") + fullname, first_name, last_name = self.get_user_names( + response.get("fullname", ""), + response.get("first_name", ""), + response.get("last_name", ""), + ) + if email and not username: + username = email.split("@", 1)[0] + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/line.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/line.py new file mode 100644 index 0000000000000000000000000000000000000000..d9ff989c5235fd7c7800a406f1ed2d5ed553a4fd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/line.py @@ -0,0 +1,103 @@ +""" +LINE Login OAuth2 backend, docs at: + https://developers.line.me/en/docs/line-login/ +""" +import json + +import requests + +from ..exceptions import AuthFailed +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class LineOAuth2(BaseOAuth2): + name = "line" + AUTHORIZATION_URL = "https://access.line.me/oauth2/v2.1/authorize" + ACCESS_TOKEN_URL = "https://api.line.me/oauth2/v2.1/token" + BASE_API_URL = "https://api.line.me" + USER_INFO_URL = BASE_API_URL + "/v2/profile" + ACCESS_TOKEN_METHOD = "POST" + STATE_PARAMETER = True + DEFAULT_SCOPE = ["profile"] + REDIRECT_STATE = True + ID_KEY = "userId" + EXTRA_DATA = [ + ("userId", "id"), + ("picture_url", "picture_url"), + ("status_message", "status_message"), + ("expires_in", "expire"), + ("refresh_token", "refresh_token"), + ] + + def auth_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "response_type": self.RESPONSE_TYPE, + "client_id": client_id, + "redirect_uri": self.get_redirect_uri(), + "state": self.get_or_create_state(), + "scope": self.get_scope(), + } + + def process_error(self, data): + error_code = ( + data.get("errorCode") or data.get("statusCode") or data.get("error") + ) + error_message = data.get("errorMessage") or data.get("error_description") + if error_code is not None or error_message is not None: + raise AuthFailed(self, error_message or error_code) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + + try: + response = self.request_access_token( + self.access_token_url(), + method=self.ACCESS_TOKEN_METHOD, + headers=self.auth_headers(), + data=self.auth_complete_params(), + ) + self.process_error(response) + + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + except requests.HTTPError as err: + self.process_error(json.loads(err.response.content)) + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response.get("displayName") + ) + username = response.get("userId") + picture_url = response.get("pictureUrl") + status_message = response.get("statusMessage") + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "picture_url": picture_url, + "status_message": status_message, + } + + def get_user_id(self, details, response): + """ + Return a unique ID for the current user, by default from + server response. + """ + return response.get(self.ID_KEY) + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + try: + response = self.get_json( + self.USER_INFO_URL, headers={"Authorization": f"Bearer {access_token}"} + ) + self.process_error(response) + return response + except requests.HTTPError as err: + self.process_error(err.response.json()) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/linkedin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/linkedin.py new file mode 100644 index 0000000000000000000000000000000000000000..624dc21bceb1621866cd188c8f9962d547c621f4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/linkedin.py @@ -0,0 +1,129 @@ +""" +LinkedIn OAuth1 and OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/linkedin.html +""" +from social_core.exceptions import AuthCanceled + +from .oauth import BaseOAuth2 + + +class LinkedinOAuth2(BaseOAuth2): + name = "linkedin-oauth2" + AUTHORIZATION_URL = "https://www.linkedin.com/oauth/v2/authorization" + ACCESS_TOKEN_URL = "https://www.linkedin.com/oauth/v2/accessToken" + USER_DETAILS_URL = "https://api.linkedin.com/v2/me?projection=({projection})" + USER_EMAILS_URL = ( + "https://api.linkedin.com/v2/emailAddress" + "?q=members&projection=(elements*(handle~))" + ) + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + DEFAULT_SCOPE = ["r_liteprofile"] + EXTRA_DATA = [ + ("id", "id"), + ("expires_in", "expires"), + ("firstName", "first_name"), + ("lastName", "last_name"), + ] + + def user_details_url(self): + # use set() since LinkedIn fails when values are duplicated + fields_selectors = list( + set(["id", "firstName", "lastName"] + self.setting("FIELD_SELECTORS", [])) + ) + # user sort to ease the tests URL mocking + fields_selectors.sort() + fields_selectors = ",".join(fields_selectors) + return self.USER_DETAILS_URL.format(projection=fields_selectors) + + def user_emails_url(self): + return self.USER_EMAILS_URL + + def user_data(self, access_token, *args, **kwargs): + response = self.get_json( + self.user_details_url(), headers=self.user_data_headers(access_token) + ) + + if "emailAddress" in set(self.setting("FIELD_SELECTORS", [])): + emails = self.email_data(access_token, *args, **kwargs) + if emails: + response["emailAddress"] = emails[0] + + return response + + def email_data(self, access_token, *args, **kwargs): + response = self.get_json( + self.user_emails_url(), headers=self.user_data_headers(access_token) + ) + email_addresses = [] + for element in response.get("elements", []): + email_address = element.get("handle~", {}).get("emailAddress") + email_addresses.append(email_address) + return list(filter(None, email_addresses)) + + def get_user_details(self, response): + """Return user details from Linkedin account""" + + def get_localized_name(name): + """ + FirstName & Last Name object + { + 'localized': { + 'en_US': 'Smith' + }, + 'preferredLocale': { + 'country': 'US', + 'language': 'en' + } + } + :return the localizedName from the lastName object + """ + locale = "{}_{}".format( + name["preferredLocale"]["language"], name["preferredLocale"]["country"] + ) + return name["localized"].get(locale, "") + + fullname, first_name, last_name = self.get_user_names( + first_name=get_localized_name(response["firstName"]), + last_name=get_localized_name(response["lastName"]), + ) + email = response.get("emailAddress", "") + return { + "username": first_name + last_name, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data_headers(self, access_token): + headers = {} + lang = self.setting("FORCE_PROFILE_LANGUAGE") + if lang: + headers["Accept-Language"] = ( + lang if lang is not True else self.strategy.get_language() + ) + headers["Authorization"] = "Bearer {access_token}".format( + access_token=access_token + ) + return headers + + def request_access_token(self, *args, **kwargs): + # LinkedIn expects a POST request with querystring parameters, despite + # the spec http://tools.ietf.org/html/rfc6749#section-4.1.3 + kwargs["params"] = kwargs.pop("data") + return super().request_access_token(*args, **kwargs) + + def process_error(self, data): + super().process_error(data) + if data.get("serviceErrorCode"): + raise AuthCanceled(self, data.get("message") or data.get("status")) + + +class LinkedinMobileOAuth2(LinkedinOAuth2): + name = "linkedin-mobile-oauth2" + + def user_data_headers(self, access_token): + headers = super().user_data_headers(access_token) + headers["x-li-src"] = "msdk" + return headers diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/live.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/live.py new file mode 100644 index 0000000000000000000000000000000000000000..d075ccc3630e855a84c64bff3697204716f8bcd5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/live.py @@ -0,0 +1,45 @@ +""" +Live OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/live.html +""" +from .oauth import BaseOAuth2 + + +class LiveOAuth2(BaseOAuth2): + name = "live" + AUTHORIZATION_URL = "https://login.live.com/oauth20_authorize.srf" + ACCESS_TOKEN_URL = "https://login.live.com/oauth20_token.srf" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + DEFAULT_SCOPE = ["wl.basic", "wl.emails"] + EXTRA_DATA = [ + ("id", "id"), + ("access_token", "access_token"), + ("authentication_token", "authentication_token"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires"), + ("email", "email"), + ("first_name", "first_name"), + ("last_name", "last_name"), + ("token_type", "token_type"), + ] + REDIRECT_STATE = False + + def get_user_details(self, response): + """Return user details from Live Connect account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("first_name"), last_name=response.get("last_name") + ) + return { + "username": response.get("name"), + "email": response.get("emails", {}).get("account", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://apis.live.net/v5.0/me", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/livejournal.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/livejournal.py new file mode 100644 index 0000000000000000000000000000000000000000..6f367bb50f43ca2fb9566b36feda64c9089a6a24 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/livejournal.py @@ -0,0 +1,29 @@ +""" +LiveJournal OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/livejournal.html +""" +from urllib.parse import urlsplit + +from ..exceptions import AuthMissingParameter +from .open_id import OpenIdAuth + + +class LiveJournalOpenId(OpenIdAuth): + """LiveJournal OpenID authentication backend""" + + name = "livejournal" + + def get_user_details(self, response): + """Generate username from identity url""" + values = super().get_user_details(response) + values["username"] = ( + values.get("username") + or urlsplit(response.identity_url).netloc.split(".", 1)[0] + ) + return values + + def openid_url(self): + """Returns LiveJournal authentication URL""" + if not self.data.get("openid_lj_user"): + raise AuthMissingParameter(self, "openid_lj_user") + return "http://{}.livejournal.com".format(self.data["openid_lj_user"]) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/loginradius.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/loginradius.py new file mode 100644 index 0000000000000000000000000000000000000000..42bd574cf3ae60f03409036f8efbe6a65324e3e2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/loginradius.py @@ -0,0 +1,73 @@ +""" +LoginRadius BaseOAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/loginradius.html +""" +from .oauth import BaseOAuth2 + + +class LoginRadiusAuth(BaseOAuth2): + """LoginRadius BaseOAuth2 authentication backend.""" + + name = "loginradius" + ID_KEY = "ID" + ACCESS_TOKEN_URL = "https://api.loginradius.com/api/v2/access_token" + PROFILE_URL = "https://api.loginradius.com/api/v2/userprofile" + ACCESS_TOKEN_METHOD = "GET" + REDIRECT_STATE = False + STATE_PARAMETER = False + + def uses_redirect(self): + """Return False because we return HTML instead.""" + return False + + def auth_html(self): + key, secret = self.get_key_and_secret() + tpl = self.setting("TEMPLATE", "loginradius.html") + return self.strategy.render_html( + tpl=tpl, + context={ + "backend": self, + "LOGINRADIUS_KEY": key, + "LOGINRADIUS_REDIRECT_URL": self.get_redirect_uri(), + }, + ) + + def request_access_token(self, *args, **kwargs): + return self.get_json( + params={"token": self.data.get("token"), "secret": self.setting("SECRET")}, + *args, + **kwargs + ) + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service. Implement in subclass.""" + return self.get_json( + self.PROFILE_URL, + params={"access_token": access_token}, + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + + def get_user_details(self, response): + """Must return user details in a know internal struct: + {'username': <username if any>, + 'email': <user email if any>, + 'fullname': <user full name if any>, + 'first_name': <user first name if any>, + 'last_name': <user last name if any>} + """ + profile = { + "username": response["NickName"] or "", + "email": response["Email"][0]["Value"] or "", + "fullname": response["FullName"] or "", + "first_name": response["FirstName"] or "", + "last_name": response["LastName"] or "", + } + return profile + + def get_user_id(self, details, response): + """Return a unique ID for the current user, by default from server + response. Since LoginRadius handles multiple providers, we need to + distinguish them to prevent conflicts.""" + return "{}-{}".format(response.get("Provider"), response.get(self.ID_KEY)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lyft.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lyft.py new file mode 100644 index 0000000000000000000000000000000000000000..f48170315e8ae7469bb896585a3d832b4828cf63 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/lyft.py @@ -0,0 +1,48 @@ +""" +Lyft OAuth2 backend. Read more about the + API at https://developer.lyft.com/docs +""" +from .oauth import BaseOAuth2 + + +class LyftOAuth2(BaseOAuth2): + name = "lyft" + ID_KEY = "id" + SCOPE_SEPARATOR = " " + AUTHORIZATION_URL = "https://api.lyft.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.lyft.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_URL = "https://api.lyft.com/oauth/token" + USER_DATA_URL = "https://api.lyft.com/v1/profile" + DEFAULT_SCOPE = ["public", "profile", "rides.read", "rides.request"] + RESPONSE_TYPE = "code" + STATE_PARAMETER = "asdf" + EXTRA_DATA = [ + ("id", "id"), + ("username", "username"), + ("access_token", "access_token"), + ("refresh_token", "refresh_token"), + ("token_type", "token_type"), + ("expires_in", "expires_in"), + ("scope", "scope"), + ] + + def get_user_details(self, response): + """Return user details from Lyft account""" + return {"id": response["id"], "username": response["id"]} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.USER_DATA_URL, headers={"Authorization": f"Bearer {access_token}"} + ) + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return {"grant_type": "authorization_code", "code": self.data["code"]} + + def auth_complete_credentials(self): + return self.get_key_and_secret() + + def refresh_token_params(self, refresh_token, *args, **kwargs): + return {"refresh_token": refresh_token, "grant_type": "refresh_token"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailchimp.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailchimp.py new file mode 100644 index 0000000000000000000000000000000000000000..920db34748e8b102bc0ba2c6d6b26ec41f0f0215 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailchimp.py @@ -0,0 +1,33 @@ +from .oauth import BaseOAuth2 + + +class MailChimpOAuth2(BaseOAuth2): + """MailChimp OAuth2 authentication backend""" + + name = "mailchimp" + AUTHORIZATION_URL = "https://login.mailchimp.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://login.mailchimp.com/oauth2/token" + METADATA_URL = "https://login.mailchimp.com/oauth2/metadata" + ACCESS_TOKEN_METHOD = "POST" + STATE_PARAMETER = False + REDIRECT_STATE = False + ID_KEY = "user_id" + EXTRA_DATA = [ + ("accountname", "accountname"), + ("api_endpoint", "api_endpoint"), + ("role", "role"), + ("login", "login"), + ] + + def get_user_details(self, response): + """Return user details from a Mailchimp metadata response""" + return { + "username": response["login"]["login_name"], + "email": response["login"]["email"], + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data and datacenter information from service""" + return self.get_json( + self.METADATA_URL, headers={"Authorization": "OAuth " + access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailru.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailru.py new file mode 100644 index 0000000000000000000000000000000000000000..cabf9a550fd23c044b03531b5830281489139588 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mailru.py @@ -0,0 +1,75 @@ +""" +Mail.ru OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/mailru.html +""" +from hashlib import md5 +from urllib.parse import unquote + +from .oauth import BaseOAuth2 + + +class MailruOAuth2(BaseOAuth2): + """Mail.ru authentication backend""" + + name = "mailru-oauth2" + ID_KEY = "uid" + AUTHORIZATION_URL = "https://connect.mail.ru/oauth/authorize" + ACCESS_TOKEN_URL = "https://connect.mail.ru/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("refresh_token", "refresh_token"), ("expires_in", "expires")] + + def get_user_details(self, response): + """Return user details from Mail.ru request""" + fullname, first_name, last_name = self.get_user_names( + first_name=unquote(response["first_name"]), + last_name=unquote(response["last_name"]), + ) + return { + "username": unquote(response["nick"]), + "email": unquote(response["email"]), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data from Mail.ru REST API""" + key, secret = self.get_key_and_secret() + data = { + "method": "users.getInfo", + "session_key": access_token, + "app_id": key, + "secure": "1", + } + param_list = sorted(list(item + "=" + data[item] for item in data)) + data["sig"] = md5(("".join(param_list) + secret).encode("utf-8")).hexdigest() + return self.get_json("http://www.appsmail.ru/platform/api", params=data)[0] + + +class MRGOAuth2(BaseOAuth2): + name = "mailru" + ID_KEY = "email" + AUTHORIZATION_URL = "https://oauth.mail.ru/login" + ACCESS_TOKEN_URL = "https://oauth.mail.ru/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("refresh_token", "refresh_token"), ("expires_in", "expires")] + REDIRECT_STATE = False + + def get_user_details(self, response): + return { + "gender": response.get("gender"), + "fullname": response.get("name"), + "username": response.get("name"), + "first_name": response.get("first_name"), + "last_name": response.get("last_name"), + "locale": response.get("locale"), + "email": response.get("email"), + "address": response.get("address"), + "birthday": response.get("birthday"), + "image": response.get("image"), + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://oauth.mail.ru/userinfo", params={"access_token": access_token} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mapmyfitness.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mapmyfitness.py new file mode 100644 index 0000000000000000000000000000000000000000..7ea8cb4cadcfc8ddbe0d838364710fde2fca7e9f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mapmyfitness.py @@ -0,0 +1,44 @@ +""" +MapMyFitness OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/mapmyfitness.html +""" +from .oauth import BaseOAuth2 + + +class MapMyFitnessOAuth2(BaseOAuth2): + """MapMyFitness OAuth authentication backend""" + + name = "mapmyfitness" + AUTHORIZATION_URL = "https://www.mapmyfitness.com/v7.0/oauth2/authorize" + ACCESS_TOKEN_URL = "https://oauth2-api.mapmyapi.com/v7.0/oauth2/access_token" + REQUEST_TOKEN_METHOD = "POST" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("refresh_token", "refresh_token"), + ] + + def auth_headers(self): + key = self.get_key_and_secret()[0] + return {"Api-Key": key} + + def get_user_id(self, details, response): + return response["id"] + + def get_user_details(self, response): + first = response.get("first_name", "") + last = response.get("last_name", "") + full = (first + last).strip() + return { + "username": response["username"], + "email": response["email"], + "fullname": full, + "first_name": first, + "last_name": last, + } + + def user_data(self, access_token, *args, **kwargs): + key = self.get_key_and_secret()[0] + url = "https://oauth2-api.mapmyapi.com/v7.0/user/self/" + headers = {"Authorization": f"Bearer {access_token}", "Api-Key": key} + return self.get_json(url, headers=headers) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mediawiki.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mediawiki.py new file mode 100644 index 0000000000000000000000000000000000000000..b4b1d9d60f42b442874d306cc7194fd643a1000c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mediawiki.py @@ -0,0 +1,183 @@ +""" +MediaWiki OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/mediawiki.html +""" + +import re +import time +from urllib.parse import parse_qs, urlencode, urlparse + +import jwt +import requests +from requests_oauthlib import OAuth1 + +from ..exceptions import AuthException +from .oauth import BaseOAuth1 + + +def force_unicode(value): + """ + Return string in unicode. + """ + if isinstance(value, str): + return value + else: + return str(value, "unicode-escape") + + +class MediaWiki(BaseOAuth1): + """ + Handles the handshake with Mediawiki and fetching of user data. + """ + + name = "mediawiki" + MEDIAWIKI_URL = "https://meta.wikimedia.org/w/index.php" + SOCIAL_AUTH_MEDIAWIKI_CALLBACK = "oob" + LEEWAY = 10.0 + + def unauthorized_token(self): + """ + Return request for unauthorized token (first stage) + + Mediawiki request token is requested from e.g.: + * https://en.wikipedia.org/w/index.php?title=Special:OAuth/initiate + """ + params = self.request_token_extra_arguments() + params.update(self.get_scope_argument()) + params["title"] = "Special:OAuth/initiate" + key, secret = self.get_key_and_secret() + response = self.request( + self.setting("MEDIAWIKI_URL"), + params=params, + auth=OAuth1(key, secret, callback_uri=self.setting("CALLBACK")), + method=self.REQUEST_TOKEN_METHOD, + ) + + if response.content.decode().startswith("Error"): + raise AuthException(self, response.content.decode()) + + return response.content.decode() + + def oauth_authorization_request(self, token): + """ + Generates the URL for the authorization link + """ + if not isinstance(token, dict): + token = parse_qs(token) + + oauth_token = token.get(self.OAUTH_TOKEN_PARAMETER_NAME)[0] + state = self.get_or_create_state() + base_url = self.setting("MEDIAWIKI_URL") + + return "{}?{}".format( + base_url, + urlencode( + { + "title": "Special:Oauth/authenticate", + self.OAUTH_TOKEN_PARAMETER_NAME: oauth_token, + self.REDIRECT_URI_PARAMETER_NAME: self.get_redirect_uri(state), + } + ), + ) + + def access_token(self, token): + """ + Fetches the Mediawiki access token. + """ + auth_token = self.oauth_auth(token) + + response = requests.post( + url=self.setting("MEDIAWIKI_URL"), + params={"title": "Special:Oauth/token"}, + auth=auth_token, + ) + credentials = parse_qs(response.content) + oauth_token_key = credentials.get(b"oauth_token")[0] + oauth_token_secret = credentials.get(b"oauth_token_secret")[0] + oauth_token_key = oauth_token_key.decode() + oauth_token_secret = oauth_token_secret.decode() + + return { + "oauth_token": oauth_token_key, + "oauth_token_secret": oauth_token_secret, + } + + def get_user_details(self, response): + """ + Gets the user details from Special:OAuth/identify + """ + key, secret = self.get_key_and_secret() + access_token = response["access_token"] + + auth = OAuth1( + key, + client_secret=secret, + resource_owner_key=access_token["oauth_token"], + resource_owner_secret=access_token["oauth_token_secret"], + ) + + req_resp = requests.post( + url=self.setting("MEDIAWIKI_URL"), + params={"title": "Special:OAuth/identify"}, + auth=auth, + ) + + try: + identity = jwt.decode( + req_resp.content, + secret, + audience=key, + algorithms=["HS256"], + leeway=self.LEEWAY, + ) + except jwt.InvalidTokenError as exception: + raise AuthException( + self, + "An error occurred while trying to read json " + + f"content: {exception}", + ) + + issuer = urlparse(identity["iss"]).netloc + expected_domain = urlparse(self.setting("MEDIAWIKI_URL")).netloc + + if not issuer == expected_domain: + raise AuthException( + self, + f"Unexpected issuer {issuer}, expected {expected_domain}", + ) + + now = time.time() + issued_at = float(identity["iat"]) + if not now >= (issued_at - self.LEEWAY): + raise AuthException( + self, f"Identity issued {issued_at - now} seconds in the future" + ) + + authorization_header = force_unicode(req_resp.request.headers["Authorization"]) + request_nonce = re.search(r'oauth_nonce="(.*?)"', authorization_header).group(1) + + if identity["nonce"] != request_nonce: + raise AuthException( + self, + "Replay attack detected: {} != {}".format( + identity["nonce"], request_nonce + ), + ) + + return { + "username": identity["username"], + "userID": identity["sub"], + "email": identity.get("email"), + "confirmed_email": identity.get("confirmed_email"), + "editcount": identity.get("editcount"), + "rights": identity.get("rights"), + "groups": identity.get("groups"), + "registered": identity.get("registered"), + "blocked": identity.get("blocked"), + } + + def get_user_id(self, details, response): + """ + Get the unique Mediawiki user ID. + """ + return details["userID"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/meetup.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/meetup.py new file mode 100644 index 0000000000000000000000000000000000000000..a064c270fe1a24dbcd44b7a9030ecd0ed715bc1a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/meetup.py @@ -0,0 +1,37 @@ +""" +Meetup OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/meetup.html +""" +from .oauth import BaseOAuth2 + + +class MeetupOAuth2(BaseOAuth2): + """Meetup OAuth2 authentication backend""" + + name = "meetup" + AUTHORIZATION_URL = "https://secure.meetup.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://secure.meetup.com/oauth2/access" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["basic"] + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + STATE_PARAMETER = "state" + + def get_user_details(self, response): + """Return user details from Meetup account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + + return { + "username": response.get("username"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.meetup.com/2/member/self", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mendeley.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mendeley.py new file mode 100644 index 0000000000000000000000000000000000000000..9ed5d57798f1660349ce6db7c1b940c5f560a865 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mendeley.py @@ -0,0 +1,63 @@ +""" +Mendeley OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/mendeley.html +""" +from .oauth import BaseOAuth1, BaseOAuth2 + + +class MendeleyMixin: + SCOPE_SEPARATOR = "+" + EXTRA_DATA = [("profile_id", "profile_id"), ("name", "name"), ("bio", "bio")] + + def get_user_id(self, details, response): + return response["id"] + + def get_user_details(self, response): + """Return user details from Mendeley account""" + profile_id = response["id"] + name = response["display_name"] + bio = response["link"] + return {"profile_id": profile_id, "name": name, "bio": bio} + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + values = self.get_user_data(access_token) + values.update(values) + return values + + def get_user_data(self, access_token): + raise NotImplementedError("Implement in subclass") + + +class MendeleyOAuth(MendeleyMixin, BaseOAuth1): + name = "mendeley" + AUTHORIZATION_URL = "http://api.mendeley.com/oauth/authorize/" + REQUEST_TOKEN_URL = "http://api.mendeley.com/oauth/request_token/" + ACCESS_TOKEN_URL = "http://api.mendeley.com/oauth/access_token/" + + def get_user_data(self, access_token): + return self.get_json( + "http://api.mendeley.com/oapi/profiles/info/me/", + auth=self.oauth_auth(access_token), + ) + + +class MendeleyOAuth2(MendeleyMixin, BaseOAuth2): + name = "mendeley-oauth2" + AUTHORIZATION_URL = "https://api-oauth2.mendeley.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api-oauth2.mendeley.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["all"] + REDIRECT_STATE = False + EXTRA_DATA = MendeleyMixin.EXTRA_DATA + [ + ("refresh_token", "refresh_token"), + ("expires_in", "expires_in"), + ("token_type", "token_type"), + ] + + def get_user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.mendeley.com/profiles/me/", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/microsoft.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/microsoft.py new file mode 100644 index 0000000000000000000000000000000000000000..1114822f59dfd6f2472b7ca6cecb2f559b1360f5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/microsoft.py @@ -0,0 +1,88 @@ +""" +OAuth2 Backend to work with microsoft graph. +""" +import time + +from .oauth import BaseOAuth2 + + +class MicrosoftOAuth2(BaseOAuth2): + name = "microsoft-graph" + SCOPE_SEPARATOR = " " + AUTHORIZATION_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" + ACCESS_TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token" + + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + DEFAULT_SCOPE = ["User.Read"] + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + state = self.validate_state() + + response = self.request_access_token( + self.access_token_url(), + data=self.auth_complete_params(state), + headers=self.auth_headers(), + auth=self.auth_complete_credentials(), + method=self.ACCESS_TOKEN_METHOD, + ) + + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + def get_user_id(self, details, response): + """Use user account id as unique id""" + return response.get("id") + + def get_user_details(self, response): + """Return user details from Microsoft online account""" + email = response.get("mail") + username = response.get("userPrincipalName") + + if "@" in username: + if not email: + email = username + username = username.split("@", 1)[0] + + return { + "username": username, + "email": email, + "fullname": response.get("displayName", ""), + "first_name": response.get("givenName", ""), + "last_name": response.get("surname", ""), + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data by querying Microsoft service""" + return self.get_json( + "https://graph.microsoft.com/v1.0/me", + headers={ + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + "Authorization": "Bearer " + access_token, + }, + method="GET", + ) + + def refresh_token_params(self, token, *args, **kwargs): + return { + "client_id": self.setting("KEY"), + "client_secret": self.setting("SECRET"), + "refresh_token": token, + "grant_type": "refresh_token", + } + + def get_auth_token(self, user_id): + """Return the access token for the given user, after ensuring that it + has not expired, or refreshing it if so.""" + user = self.get_user(user_id=user_id) + access_token = user.social_user.access_token + expires_on = user.social_user.extra_data["expires_on"] + if expires_on <= int(time.time()): + new_token_response = self.refresh_token(token=access_token) + access_token = new_token_response["access_token"] + return access_token diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mineid.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mineid.py new file mode 100644 index 0000000000000000000000000000000000000000..9a1fc1687c28620844f247aa3fa8f1d25b275835 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mineid.py @@ -0,0 +1,37 @@ +from .oauth import BaseOAuth2 + + +class MineIDOAuth2(BaseOAuth2): + """MineID OAuth2 authentication backend""" + + name = "mineid" + _AUTHORIZATION_URL = "%(scheme)s://%(host)s/oauth/authorize" + _ACCESS_TOKEN_URL = "%(scheme)s://%(host)s/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + EXTRA_DATA = [] + + def get_user_details(self, response): + """Return user details""" + return {"email": response.get("email"), "username": response.get("email")} + + def user_data(self, access_token, *args, **kwargs): + return self._user_data(access_token) + + def _user_data(self, access_token, path=None): + url = "%(scheme)s://%(host)s/api/user" % self.get_mineid_url_params() + return self.get_json(url, params={"access_token": access_token}) + + @property + def AUTHORIZATION_URL(self): + return self._AUTHORIZATION_URL % self.get_mineid_url_params() + + @property + def ACCESS_TOKEN_URL(self): + return self._ACCESS_TOKEN_URL % self.get_mineid_url_params() + + def get_mineid_url_params(self): + return { + "host": self.setting("HOST", "www.mineid.org"), + "scheme": self.setting("SCHEME", "https"), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mixcloud.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mixcloud.py new file mode 100644 index 0000000000000000000000000000000000000000..04c00ec583ff1460b2344110b49cc8483d8f0920 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/mixcloud.py @@ -0,0 +1,29 @@ +""" +Mixcloud OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/mixcloud.html +""" +from .oauth import BaseOAuth2 + + +class MixcloudOAuth2(BaseOAuth2): + name = "mixcloud" + ID_KEY = "username" + AUTHORIZATION_URL = "https://www.mixcloud.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.mixcloud.com/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names(response["name"]) + return { + "username": response["username"], + "email": None, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://api.mixcloud.com/me/", + params={"access_token": access_token, "alt": "json"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/monzo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/monzo.py new file mode 100644 index 0000000000000000000000000000000000000000..dd490d948c8d37b1921b366347001dcce225608a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/monzo.py @@ -0,0 +1,32 @@ +from .oauth import BaseOAuth2 + + +class MonzoOAuth2(BaseOAuth2): + """ + Monzo OAuth2 authentication backend. + """ + + name = "monzo" + + AUTHORIZATION_URL = "https://auth.getmondo.co.uk/" + ACCESS_TOKEN_URL = "https://api.monzo.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response["accounts"][0]["description"], + ) + + return { + "username": str(response.get("user_id")), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://api.monzo.com/accounts", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/moves.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/moves.py new file mode 100644 index 0000000000000000000000000000000000000000..5e6f51f76cc9d69b1b08e3c3d919e01c990236b6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/moves.py @@ -0,0 +1,33 @@ +""" +Moves OAuth2 backend, docs at: + https://dev.moves-app.com/docs/authentication + +Written by Avi Alkalay <avi at unix dot sh> +Certified to work with Django 1.6 +""" +from .oauth import BaseOAuth2 + + +class MovesOAuth2(BaseOAuth2): + """Moves OAuth authentication backend""" + + name = "moves" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://api.moves-app.com/oauth/v1/authorize" + ACCESS_TOKEN_URL = "https://api.moves-app.com/oauth/v1/access_token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("expires_in", "expires"), + ] + + def get_user_details(self, response): + """Return user details Moves account""" + return {"username": str(response.get("user_id"))} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.moves-app.com/api/1.1/user/profile", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/musicbrainz.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/musicbrainz.py new file mode 100644 index 0000000000000000000000000000000000000000..d17487282113d76e7311e4795a73a3fa33b64ffc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/musicbrainz.py @@ -0,0 +1,33 @@ +from social_core.backends.oauth import BaseOAuth2 + + +class MusicBrainzOAuth2(BaseOAuth2): + """MusicBrainz OAuth authentication backend""" + + name = "musicbrainz" + AUTHORIZATION_URL = "https://musicbrainz.org/oauth2/authorize" + ACCESS_TOKEN_URL = "https://musicbrainz.org/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + ID_KEY = "metabrainz_user_id" + DEFAULT_SCOPE = ["profile", "email"] + SCOPE_SEPARATOR = " " + REDIRECT_STATE = False + EXTRA_DATA = [ + ("metabrainz_user_id", "id"), + ("expires_in", "expires"), + ] + + def get_user_details(self, response): + """Return user details from MusicBrainz account""" + return { + "username": response.get("sub"), + "email": response.get("email") or "", + "first_name": response.get("sub"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://musicbrainz.org/oauth2/userinfo", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nationbuilder.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nationbuilder.py new file mode 100644 index 0000000000000000000000000000000000000000..c71fa96b3224e12f1e4722c57b8d23d4ce52566e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nationbuilder.py @@ -0,0 +1,44 @@ +""" +NationBuilder OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/nationbuilder.html +""" +from .oauth import BaseOAuth2 + + +class NationBuilderOAuth2(BaseOAuth2): + """NationBuilder OAuth2 authentication backend""" + + name = "nationbuilder" + AUTHORIZATION_URL = "https://{slug}.nationbuilder.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://{slug}.nationbuilder.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + SCOPE_SEPARATOR = "," + EXTRA_DATA = [("id", "id"), ("expires", "expires")] + + def authorization_url(self): + return self.AUTHORIZATION_URL.format(slug=self.slug) + + def access_token_url(self): + return self.ACCESS_TOKEN_URL.format(slug=self.slug) + + @property + def slug(self): + return self.setting("SLUG") + + def get_user_details(self, response): + """Return user details from Github account""" + email = response.get("email") or "" + username = email.split("@")[0] if email else "" + return { + "username": username, + "email": email, + "fullname": response.get("full_name") or "", + "first_name": response.get("first_name") or "", + "last_name": response.get("last_name") or "", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + url = f"https://{self.slug}.nationbuilder.com/api/v1/people/me" + return self.get_json(url, params={"access_token": access_token})["person"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/naver.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/naver.py new file mode 100644 index 0000000000000000000000000000000000000000..63857d5245744b5a1bac0baccb5647396541f9d9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/naver.py @@ -0,0 +1,62 @@ +from .oauth import BaseOAuth2 + + +class NaverOAuth2(BaseOAuth2): + """Naver OAuth authentication backend""" + + name = "naver" + AUTHORIZATION_URL = "https://nid.naver.com/oauth2.0/authorize" + ACCESS_TOKEN_URL = "https://nid.naver.com/oauth2.0/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("id", "id"), + ] + + def get_user_id(self, details, response): + return response.get("id") + + def get_user_details(self, response): + """Return user details from Naver account""" + return { + "username": response.get("username"), + "email": response.get("email"), + "fullname": response.get("username"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + response = self.request( + "https://openapi.naver.com/v1/nid/me", + headers={ + "Authorization": f"Bearer {access_token}", + "Content_Type": "text/json", + }, + ) + + data = response.json() + + return { + "id": self._fetch(data, "id"), + "email": self._fetch(data, "email"), + "username": self._fetch(data, "name"), + "nickname": self._fetch(data, "nickname"), + "gender": self._fetch(data, "gender"), + "age": self._fetch(data, "age"), + "birthday": self._fetch(data, "birthday"), + "profile_image": self._fetch(data, "profile_image"), + } + + def auth_headers(self): + client_id, client_secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", + "code": self.data.get("code"), + "client_id": client_id, + "client_secret": client_secret, + } + + def _fetch(self, data, key): + try: + return data["response"][key] + except (KeyError, TypeError): + return "" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ngpvan.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ngpvan.py new file mode 100644 index 0000000000000000000000000000000000000000..8db9823d9224dc71d30ea3743139bfad15d8e6da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ngpvan.py @@ -0,0 +1,75 @@ +""" +NGP VAN's `ActionID` Provider + +http://developers.ngpvan.com/action-id +""" +from openid.extensions import ax + +from .open_id import OpenIdAuth + + +class ActionIDOpenID(OpenIdAuth): + """ + NGP VAN's ActionID OpenID 1.1 authentication backend + """ + + name = "actionid-openid" + URL = "https://accounts.ngpvan.com/Home/Xrds" + USERNAME_KEY = "email" + + def get_ax_attributes(self): + """ + Return the AX attributes that ActionID responds with, as well as the + user data result that it must map to. + """ + return [ + ("http://openid.net/schema/contact/internet/email", "email"), + ("http://openid.net/schema/contact/phone/business", "phone"), + ("http://openid.net/schema/namePerson/first", "first_name"), + ("http://openid.net/schema/namePerson/last", "last_name"), + ("http://openid.net/schema/namePerson", "fullname"), + ] + + def setup_request(self, params=None): + """ + Setup the OpenID request + + Because ActionID does not advertise the availiability of AX attributes + nor use standard attribute aliases, we need to setup the attributes + manually instead of rely on the parent OpenIdAuth.setup_request() + """ + request = self.openid_request(params) + + fetch_request = ax.FetchRequest() + fetch_request.add( + ax.AttrInfo( + "http://openid.net/schema/contact/internet/email", + alias="ngpvanemail", + required=True, + ) + ) + + fetch_request.add( + ax.AttrInfo( + "http://openid.net/schema/contact/phone/business", + alias="ngpvanphone", + required=False, + ) + ) + fetch_request.add( + ax.AttrInfo( + "http://openid.net/schema/namePerson/first", + alias="ngpvanfirstname", + required=False, + ) + ) + fetch_request.add( + ax.AttrInfo( + "http://openid.net/schema/namePerson/last", + alias="ngpvanlastname", + required=False, + ) + ) + request.addExtension(fetch_request) + + return request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nk.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nk.py new file mode 100644 index 0000000000000000000000000000000000000000..a5dfe14752a71fc9cf8593decca7895e50ca40ed --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/nk.py @@ -0,0 +1,73 @@ +from urllib import urlencode + +from requests_oauthlib import OAuth1 + +from .oauth import BaseOAuth2 + + +class NKOAuth2(BaseOAuth2): + """NK OAuth authentication backend""" + + name = "nk" + AUTHORIZATION_URL = "https://nk.pl/oauth2/login" + ACCESS_TOKEN_URL = "https://nk.pl/oauth2/token" + SCOPE_SEPARATOR = "," + ACCESS_TOKEN_METHOD = "POST" + SIGNATURE_TYPE_AUTH_HEADER = "AUTH_HEADER" + EXTRA_DATA = [ + ("id", "id"), + ] + + def get_user_details(self, response): + """Return user details from NK account""" + entry = response["entry"] + return { + "username": entry.get("displayName"), + "email": entry["emails"][0]["value"], + "first_name": entry.get("displayName").split(" ")[0], + "id": entry.get("id"), + } + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "client_id": client_id, + "client_secret": client_secret, + "redirect_uri": self.get_redirect_uri(state), + "scope": self.get_scope_argument(), + } + + def get_user_id(self, details, response): + """Return a unique ID for the current user, by default from server + response.""" + return details.get(self.ID_KEY) + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + url = "http://opensocial.nk-net.pl/v09/social/rest/people/@me?" + urlencode( + { + "nk_token": access_token, + "fields": "name,surname,avatar,localization,age," + + "gender,emails,birthdate", + } + ) + return self.get_json(url, auth=self.oauth_auth(access_token)) + + def oauth_auth( + self, token=None, oauth_verifier=None, signature_type=SIGNATURE_TYPE_AUTH_HEADER + ): + key, secret = self.get_key_and_secret() + oauth_verifier = oauth_verifier or self.data.get("oauth_verifier") + token = token or {} + state = self.get_or_create_state() + return OAuth1( + key, + secret, + resource_owner_key=None, + resource_owner_secret=None, + callback_uri=self.get_redirect_uri(state), + verifier=oauth_verifier, + signature_type=signature_type, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/oauth.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/oauth.py new file mode 100644 index 0000000000000000000000000000000000000000..ae00aa5b28940211b62517de84815856d2c0e2f3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/oauth.py @@ -0,0 +1,461 @@ +from urllib.parse import unquote, urlencode + +from oauthlib.oauth1 import SIGNATURE_TYPE_AUTH_HEADER +from requests_oauthlib import OAuth1 + +from ..exceptions import ( + AuthCanceled, + AuthFailed, + AuthMissingParameter, + AuthStateForbidden, + AuthStateMissing, + AuthTokenError, + AuthUnknownError, +) +from ..utils import ( + constant_time_compare, + handle_http_errors, + parse_qs, + url_add_parameters, +) +from .base import BaseAuth + + +class OAuthAuth(BaseAuth): + """OAuth authentication backend base class. + + Settings will be inspected to get more values names that should be + stored on extra_data field. The setting name is created following the + pattern SOCIAL_AUTH_<uppercase current backend name>_EXTRA_DATA. + + access_token is always stored. + + URLs settings: + AUTHORIZATION_URL Authorization service url + ACCESS_TOKEN_URL Access token URL + """ + + AUTHORIZATION_URL = "" + ACCESS_TOKEN_URL = "" + ACCESS_TOKEN_METHOD = "GET" + REVOKE_TOKEN_URL = None + REVOKE_TOKEN_METHOD = "POST" + ID_KEY = "id" + SCOPE_PARAMETER_NAME = "scope" + DEFAULT_SCOPE = None + SCOPE_SEPARATOR = " " + REDIRECT_STATE = False + STATE_PARAMETER = False + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return access_token and extra defined names to store in + extra_data field""" + data = super().extra_data(user, uid, response, details, *args, **kwargs) + data["access_token"] = response.get("access_token", "") or kwargs.get( + "access_token" + ) + return data + + def state_token(self): + """Generate csrf token to include as state parameter.""" + return self.strategy.random_string(32) + + def get_or_create_state(self): + if self.STATE_PARAMETER or self.REDIRECT_STATE: + # Store state in session for further request validation. The state + # value is passed as state parameter (as specified in OAuth2 spec), + # but also added to redirect, that way we can still verify the + # request if the provider doesn't implement the state parameter. + # Reuse token if any. + name = self.name + "_state" + state = self.strategy.session_get(name) + if state is None: + state = self.state_token() + self.strategy.session_set(name, state) + else: + state = None + return state + + def get_session_state(self): + return self.strategy.session_get(self.name + "_state") + + def get_request_state(self): + request_state = self.data.get("state") or self.data.get("redirect_state") + if request_state and isinstance(request_state, list): + request_state = request_state[0] + return request_state + + def validate_state(self): + """Validate state value. Raises exception on error, returns state + value if valid.""" + if not self.STATE_PARAMETER and not self.REDIRECT_STATE: + return None + state = self.get_session_state() + request_state = self.get_request_state() + if not request_state: + raise AuthMissingParameter(self, "state") + elif not state: + raise AuthStateMissing(self, "state") + elif not constant_time_compare(request_state, state): + raise AuthStateForbidden(self) + else: + return state + + def get_redirect_uri(self, state=None): + """Build redirect with redirect_state parameter.""" + uri = self.redirect_uri + if self.REDIRECT_STATE and state: + uri = url_add_parameters(uri, {"redirect_state": state}) + return uri + + def get_scope(self): + """Return list with needed access scope""" + scope = self.setting("SCOPE", []) + if not self.setting("IGNORE_DEFAULT_SCOPE", False): + scope = scope + (self.DEFAULT_SCOPE or []) + return scope + + def get_scope_argument(self): + param = {} + scope = self.get_scope() + if scope: + param[self.SCOPE_PARAMETER_NAME] = self.SCOPE_SEPARATOR.join(scope) + return param + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service. Implement in subclass""" + return {} + + def authorization_url(self): + return self.AUTHORIZATION_URL + + def access_token_url(self): + return self.ACCESS_TOKEN_URL + + def revoke_token_url(self, token, uid): + return self.REVOKE_TOKEN_URL + + def revoke_token_params(self, token, uid): + return {} + + def revoke_token_headers(self, token, uid): + return {} + + def process_revoke_token_response(self, response): + return response.status_code == 200 + + def revoke_token(self, token, uid): + if self.REVOKE_TOKEN_URL: + url = self.revoke_token_url(token, uid) + params = self.revoke_token_params(token, uid) + headers = self.revoke_token_headers(token, uid) + data = urlencode(params) if self.REVOKE_TOKEN_METHOD != "GET" else None + response = self.request( + url, + params=params, + headers=headers, + data=data, + method=self.REVOKE_TOKEN_METHOD, + ) + return self.process_revoke_token_response(response) + + +class BaseOAuth1(OAuthAuth): + """Consumer based mechanism OAuth authentication, fill the needed + parameters to communicate properly with authentication service. + + URLs settings: + REQUEST_TOKEN_URL Request token URL + + """ + + REQUEST_TOKEN_URL = "" + REQUEST_TOKEN_METHOD = "GET" + OAUTH_TOKEN_PARAMETER_NAME = "oauth_token" + REDIRECT_URI_PARAMETER_NAME = "redirect_uri" + UNATHORIZED_TOKEN_SUFIX = "unauthorized_token_name" + + def auth_url(self): + """Return redirect url""" + token = self.set_unauthorized_token() + return self.oauth_authorization_request(token) + + def process_error(self, data): + if "oauth_problem" in data: + if data["oauth_problem"] == "user_refused": + raise AuthCanceled(self, "User refused the access") + raise AuthUnknownError(self, "Error was " + data["oauth_problem"]) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Return user, might be logged in""" + # Multiple unauthorized tokens are supported (see #521) + self.process_error(self.data) + self.validate_state() + token = self.get_unauthorized_token() + access_token = self.access_token(token) + return self.do_auth(access_token, *args, **kwargs) + + @handle_http_errors + def do_auth(self, access_token, *args, **kwargs): + """Finish the auth process once the access_token was retrieved""" + if not isinstance(access_token, dict): + access_token = parse_qs(access_token) + data = self.user_data(access_token) + if data is not None and "access_token" not in data: + data["access_token"] = access_token + kwargs.update({"response": data, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def get_unauthorized_token(self): + name = self.name + self.UNATHORIZED_TOKEN_SUFIX + unauthed_tokens = self.strategy.session_get(name, []) + if not unauthed_tokens: + raise AuthTokenError(self, "Missing unauthorized token") + + data_token = self.data.get(self.OAUTH_TOKEN_PARAMETER_NAME) + + if data_token is None: + raise AuthTokenError(self, "Missing unauthorized token") + + token = None + for utoken in unauthed_tokens: + orig_utoken = utoken + if not isinstance(utoken, dict): + utoken = parse_qs(utoken) + if utoken.get(self.OAUTH_TOKEN_PARAMETER_NAME) == data_token: + self.strategy.session_set( + name, list(set(unauthed_tokens) - {orig_utoken}) + ) + token = utoken + break + else: + raise AuthTokenError(self, "Incorrect tokens") + return token + + def set_unauthorized_token(self): + token = self.unauthorized_token() + name = self.name + self.UNATHORIZED_TOKEN_SUFIX + tokens = self.strategy.session_get(name, []) + [token] + self.strategy.session_set(name, tokens) + return token + + def request_token_extra_arguments(self): + """Return extra arguments needed on request-token process""" + return self.setting("REQUEST_TOKEN_EXTRA_ARGUMENTS", {}) + + def unauthorized_token(self): + """Return request for unauthorized token (first stage)""" + params = self.request_token_extra_arguments() + params.update(self.get_scope_argument()) + key, secret = self.get_key_and_secret() + state = self.get_or_create_state() + response = self.request( + self.REQUEST_TOKEN_URL, + params=params, + auth=OAuth1(key, secret, callback_uri=self.get_redirect_uri(state)), + method=self.REQUEST_TOKEN_METHOD, + ) + content = response.content + if response.encoding or response.apparent_encoding: + content = content.decode(response.encoding or response.apparent_encoding) + else: + content = response.content.decode() + return content + + def oauth_authorization_request(self, token): + """Generate OAuth request to authorize token.""" + if not isinstance(token, dict): + token = parse_qs(token) + params = self.auth_extra_arguments() or {} + params.update(self.get_scope_argument()) + params[self.OAUTH_TOKEN_PARAMETER_NAME] = token.get( + self.OAUTH_TOKEN_PARAMETER_NAME + ) + state = self.get_or_create_state() + params[self.REDIRECT_URI_PARAMETER_NAME] = self.get_redirect_uri(state) + return f"{self.authorization_url()}?{urlencode(params)}" + + def oauth_auth( + self, token=None, oauth_verifier=None, signature_type=SIGNATURE_TYPE_AUTH_HEADER + ): + key, secret = self.get_key_and_secret() + oauth_verifier = oauth_verifier or self.data.get("oauth_verifier") + if token: + resource_owner_key = token.get("oauth_token") + resource_owner_secret = token.get("oauth_token_secret") + if not resource_owner_key: + raise AuthTokenError(self, "Missing oauth_token") + if not resource_owner_secret: + raise AuthTokenError(self, "Missing oauth_token_secret") + else: + resource_owner_key = None + resource_owner_secret = None + state = self.get_or_create_state() + return OAuth1( + key, + secret, + resource_owner_key=resource_owner_key, + resource_owner_secret=resource_owner_secret, + callback_uri=self.get_redirect_uri(state), + verifier=oauth_verifier, + signature_type=signature_type, + ) + + def oauth_request(self, token, url, params=None, method="GET"): + """Generate OAuth request, setups callback url""" + return self.request( + url, method=method, params=params, auth=self.oauth_auth(token) + ) + + def access_token(self, token): + """Return request for access token value""" + return self.get_querystring( + self.access_token_url(), + auth=self.oauth_auth(token), + method=self.ACCESS_TOKEN_METHOD, + ) + + +class BaseOAuth2(OAuthAuth): + """Base class for OAuth2 providers. + + OAuth2 details at: + https://datatracker.ietf.org/doc/html/rfc6749 + """ + + REFRESH_TOKEN_URL = None + REFRESH_TOKEN_METHOD = "POST" + RESPONSE_TYPE = "code" + REDIRECT_STATE = True + STATE_PARAMETER = True + USE_BASIC_AUTH = False + + def use_basic_auth(self): + return self.USE_BASIC_AUTH + + def auth_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + params = {"client_id": client_id, "redirect_uri": self.get_redirect_uri(state)} + if self.STATE_PARAMETER and state: + params["state"] = state + if self.RESPONSE_TYPE: + params["response_type"] = self.RESPONSE_TYPE + return params + + def auth_url(self): + """Return redirect url""" + state = self.get_or_create_state() + params = self.auth_params(state) + params.update(self.get_scope_argument()) + params.update(self.auth_extra_arguments()) + params = urlencode(params) + if not self.REDIRECT_STATE: + # redirect_uri matching is strictly enforced, so match the + # providers value exactly. + params = unquote(params) + return f"{self.authorization_url()}?{params}" + + def auth_complete_params(self, state=None): + params = { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "redirect_uri": self.get_redirect_uri(state), + } + if not self.use_basic_auth(): + client_id, client_secret = self.get_key_and_secret() + params.update( + { + "client_id": client_id, + "client_secret": client_secret, + } + ) + return params + + def auth_complete_credentials(self): + if self.use_basic_auth(): + return self.get_key_and_secret() + return None + + def auth_headers(self): + return { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + } + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return access_token, token_type, and extra defined names to store in + extra_data field""" + data = super().extra_data(user, uid, response, details=details, *args, **kwargs) + data["token_type"] = response.get("token_type") or kwargs.get("token_type") + return data + + def request_access_token(self, *args, **kwargs): + return self.get_json(*args, **kwargs) + + def process_error(self, data): + if data.get("error"): + if "denied" in data["error"] or "cancelled" in data["error"]: + raise AuthCanceled(self, data.get("error_description", "")) + raise AuthFailed(self, data.get("error_description") or data["error"]) + elif "denied" in data: + raise AuthCanceled(self, data["denied"]) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + state = self.validate_state() + data, params = None, None + if self.ACCESS_TOKEN_METHOD == "GET": + params = self.auth_complete_params(state) + else: + data = self.auth_complete_params(state) + + response = self.request_access_token( + self.access_token_url(), + data=data, + params=params, + headers=self.auth_headers(), + auth=self.auth_complete_credentials(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + @handle_http_errors + def do_auth(self, access_token, *args, **kwargs): + """Finish the auth process once the access_token was retrieved""" + data = self.user_data(access_token, *args, **kwargs) + response = kwargs.get("response") or {} + response.update(data or {}) + if "access_token" not in response: + response["access_token"] = access_token + kwargs.update({"response": response, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def refresh_token_params(self, token, *args, **kwargs): + client_id, client_secret = self.get_key_and_secret() + return { + "refresh_token": token, + "grant_type": "refresh_token", + "client_id": client_id, + "client_secret": client_secret, + } + + def process_refresh_token_response(self, response, *args, **kwargs): + return response.json() + + def refresh_token(self, token, *args, **kwargs): + params = self.refresh_token_params(token, *args, **kwargs) + url = self.refresh_token_url() + method = self.REFRESH_TOKEN_METHOD + key = "params" if method == "GET" else "data" + request_args = {"headers": self.auth_headers(), "method": method, key: params} + request = self.request(url, **request_args) + return self.process_refresh_token_response(request, *args, **kwargs) + + def refresh_token_url(self): + return self.REFRESH_TOKEN_URL or self.access_token_url() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/odnoklassniki.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/odnoklassniki.py new file mode 100644 index 0000000000000000000000000000000000000000..cb573f9789f740071dfd6cf456fe7dc3a4f800d6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/odnoklassniki.py @@ -0,0 +1,188 @@ +""" +Odnoklassniki OAuth2 and Iframe Application backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/odnoklassnikiru.html +""" +from hashlib import md5 +from urllib.parse import unquote + +from ..exceptions import AuthFailed +from .base import BaseAuth +from .oauth import BaseOAuth2 + + +class OdnoklassnikiOAuth2(BaseOAuth2): + """Odnoklassniki authentication backend""" + + name = "odnoklassniki-oauth2" + ID_KEY = "uid" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = ";" + AUTHORIZATION_URL = "https://connect.ok.ru/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.ok.ru/oauth/token.do" + EXTRA_DATA = [("refresh_token", "refresh_token"), ("expires_in", "expires")] + + def get_user_details(self, response): + """Return user details from Odnoklassniki request""" + fullname, first_name, last_name = self.get_user_names( + fullname=unquote(response["name"]), + first_name=unquote(response["first_name"]), + last_name=unquote(response["last_name"]), + ) + return { + "username": response["uid"], + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data from Odnoklassniki REST API""" + data = {"access_token": access_token, "method": "users.getCurrentUser"} + key, secret = self.get_key_and_secret() + public_key = self.setting("PUBLIC_NAME") + return odnoklassniki_api( + self, data, "https://api.ok.ru/", public_key, secret, "oauth" + ) + + +class OdnoklassnikiApp(BaseAuth): + """Odnoklassniki iframe app authentication backend""" + + name = "odnoklassniki-app" + ID_KEY = "uid" + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + return { + key: value + for key, value in response.items() + if key in response["extra_data_list"] + } + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + fullname=unquote(response["name"]), + first_name=unquote(response["first_name"]), + last_name=unquote(response["last_name"]), + ) + return { + "username": response["uid"], + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def auth_complete(self, *args, **kwargs): + self.verify_auth_sig() + response = self.get_response() + fields = ("uid", "first_name", "last_name", "name") + self.setting( + "EXTRA_USER_DATA_LIST", () + ) + data = { + "method": "users.getInfo", + "uids": "{}".format(response["logged_user_id"]), + "fields": ",".join(fields), + } + client_key, client_secret = self.get_key_and_secret() + public_key = self.setting("PUBLIC_NAME") + details = odnoklassniki_api( + self, + data, + response["api_server"], + public_key, + client_secret, + "iframe_nosession", + ) + if len(details) == 1 and "uid" in details[0]: + details = details[0] + auth_data_fields = self.setting( + "EXTRA_AUTH_DATA_LIST", + ( + "api_server", + "apiconnection", + "session_key", + "authorized", + "session_secret_key", + ), + ) + + for field in auth_data_fields: + details[field] = response[field] + details["extra_data_list"] = fields + auth_data_fields + kwargs.update({"backend": self, "response": details}) + else: + raise AuthFailed(self, "Cannot get user details: API error") + return self.strategy.authenticate(*args, **kwargs) + + def get_auth_sig(self): + secret_key = self.setting("SECRET") + hash_source = "{:s}{:s}{:s}".format( + self.data["logged_user_id"], self.data["session_key"], secret_key + ) + return md5(hash_source.encode("utf-8")).hexdigest() + + def get_response(self): + fields = ( + "logged_user_id", + "api_server", + "application_key", + "session_key", + "session_secret_key", + "authorized", + "apiconnection", + ) + return {name: self.data[name] for name in fields if name in self.data} + + def verify_auth_sig(self): + correct_key = self.get_auth_sig() + key = self.data["auth_sig"].lower() + if correct_key != key: + raise AuthFailed(self, "Wrong authorization key") + + +def odnoklassniki_oauth_sig(data, client_secret): + """ + Calculates signature of request data access_token value must be included + Algorithm is described at + https://apiok.ru/wiki/pages/viewpage.action?pageId=12878032, + search for "little bit different way" + """ + suffix = md5( + "{:s}{:s}".format(data["access_token"], client_secret).encode("utf-8") + ).hexdigest() + check_list = sorted( + f"{key:s}={value:s}" for key, value in data.items() if key != "access_token" + ) + return md5(("".join(check_list) + suffix).encode("utf-8")).hexdigest() + + +def odnoklassniki_iframe_sig(data, client_secret_or_session_secret): + """ + Calculates signature as described at: + https://apiok.ru/wiki/display/ok/Authentication+and+Authorization + If API method requires session context, request is signed with session + secret key. Otherwise it is signed with application secret key + """ + param_list = sorted(f"{key:s}={value:s}" for key, value in data.items()) + return md5( + ("".join(param_list) + client_secret_or_session_secret).encode("utf-8") + ).hexdigest() + + +def odnoklassniki_api( + backend, data, api_url, public_key, client_secret, request_type="oauth" +): + """Calls Odnoklassniki REST API method + https://apiok.ru/wiki/display/ok/Odnoklassniki+Rest+API""" + data.update({"application_key": public_key, "format": "JSON"}) + if request_type == "oauth": + data["sig"] = odnoklassniki_oauth_sig(data, client_secret) + elif request_type == "iframe_session": + data["sig"] = odnoklassniki_iframe_sig(data, data["session_secret_key"]) + elif request_type == "iframe_nosession": + data["sig"] = odnoklassniki_iframe_sig(data, client_secret) + else: + msg = "Unknown request type {0}. How should it be signed?" + raise AuthFailed(backend, msg.format(request_type)) + return backend.get_json(api_url + "fb.do", params=data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta.py new file mode 100644 index 0000000000000000000000000000000000000000..ecdc2135d604854063a5667e7b925237f50951c6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta.py @@ -0,0 +1,66 @@ +""" +Okta OAuth2 and OpenIdConnect: + https://python-social-auth.readthedocs.io/en/latest/backends/okta.html +""" +from urllib.parse import urljoin + +from ..utils import append_slash +from .oauth import BaseOAuth2 + + +class OktaMixin: + def api_url(self): + return append_slash(self.setting("API_URL")) + + def authorization_url(self): + return self._url("v1/authorize") + + def access_token_url(self): + return self._url("v1/token") + + def _url(self, path): + return urljoin(append_slash(self.setting("API_URL")), path) + + def oidc_config(self): + return self.get_json( + self._url( + "/.well-known/openid-configuration?client_id={}".format( + self.setting("KEY") + ) + ) + ) + + +class OktaOAuth2(OktaMixin, BaseOAuth2): + """Okta OAuth authentication backend""" + + name = "okta-oauth2" + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + ID_KEY = "preferred_username" + + DEFAULT_SCOPE = ["openid", "profile", "email"] + EXTRA_DATA = [ + ("refresh_token", "refresh_token", True), + ("expires_in", "expires"), + ("token_type", "token_type", True), + ] + + def get_user_details(self, response): + """Return user details from Okta account""" + return { + "username": response.get("preferred_username"), + "email": response.get("email") or "", + "first_name": response.get("given_name"), + "last_name": response.get("family_name"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from Okta""" + return self.get_json( + self._url("v1/userinfo"), + headers={ + "Authorization": f"Bearer {access_token}", + }, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta_openidconnect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta_openidconnect.py new file mode 100644 index 0000000000000000000000000000000000000000..8b74db29964985c7f3ed08ea85ca52731c0ad98f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/okta_openidconnect.py @@ -0,0 +1,15 @@ +""" +Okta OAuth2 and OpenIdConnect: + https://python-social-auth.readthedocs.io/en/latest/backends/okta.html +""" +from .okta import OktaOAuth2 +from .open_id_connect import OpenIdConnectAuth + + +class OktaOpenIdConnect(OktaOAuth2, OpenIdConnectAuth): + """Okta OpenID-Connect authentication backend""" + + name = "okta-openidconnect" + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + RESPONSE_TYPE = "code" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id.py new file mode 100644 index 0000000000000000000000000000000000000000..a2533d4b88d60d52d9f951d437e4ae3139b91c28 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id.py @@ -0,0 +1,259 @@ +from openid.consumer.consumer import CANCEL, FAILURE, SUCCESS, Consumer +from openid.consumer.discover import DiscoveryFailure +from openid.extensions import ax, pape, sreg + +from ..exceptions import ( + AuthCanceled, + AuthException, + AuthFailed, + AuthMissingParameter, + AuthUnknownError, +) +from ..utils import url_add_parameters +from .base import BaseAuth + +# OpenID configuration +OLD_AX_ATTRS = [ + ("http://schema.openid.net/contact/email", "old_email"), + ("http://schema.openid.net/namePerson", "old_fullname"), + ("http://schema.openid.net/namePerson/friendly", "old_nickname"), +] +AX_SCHEMA_ATTRS = [ + # Request both the full name and first/last components since some + # providers offer one but not the other. + ("http://axschema.org/contact/email", "email"), + ("http://axschema.org/namePerson", "fullname"), + ("http://axschema.org/namePerson/first", "first_name"), + ("http://axschema.org/namePerson/last", "last_name"), + ("http://axschema.org/namePerson/friendly", "nickname"), +] +SREG_ATTR = [("email", "email"), ("fullname", "fullname"), ("nickname", "nickname")] +OPENID_ID_FIELD = "openid_identifier" +SESSION_NAME = "openid" + + +class OpenIdAuth(BaseAuth): + """Generic OpenID authentication backend""" + + name = "openid" + URL = None + USERNAME_KEY = "username" + + def get_user_id(self, details, response): + """Return user unique id provided by service""" + return response.identity_url + + def get_ax_attributes(self): + attrs = self.setting("AX_SCHEMA_ATTRS", []) + if attrs and self.setting("IGNORE_DEFAULT_AX_ATTRS", True): + return attrs + return attrs + AX_SCHEMA_ATTRS + OLD_AX_ATTRS + + def get_sreg_attributes(self): + return self.setting("SREG_ATTR") or SREG_ATTR + + def values_from_response(self, response, sreg_names=None, ax_names=None): + """Return values from SimpleRegistration response or + AttributeExchange response if present. + + @sreg_names and @ax_names must be a list of name and aliases + for such name. The alias will be used as mapping key. + """ + values = {} + + # Use Simple Registration attributes if provided + if sreg_names: + resp = sreg.SRegResponse.fromSuccessResponse(response) + if resp: + values.update( + (alias, resp.get(name) or "") for name, alias in sreg_names + ) + + # Use Attribute Exchange attributes if provided + if ax_names: + resp = ax.FetchResponse.fromSuccessResponse(response) + if resp: + for src, alias in ax_names: + name = alias.replace("old_", "") + values[name] = resp.getSingle(src, "") or values.get(name) + return values + + def get_user_details(self, response): + """Return user details from an OpenID request""" + values = { + "username": "", + "email": "", + "fullname": "", + "first_name": "", + "last_name": "", + } + # update values using SimpleRegistration or AttributeExchange + # values + values.update( + self.values_from_response( + response, self.get_sreg_attributes(), self.get_ax_attributes() + ) + ) + + fullname = values.get("fullname") or "" + first_name = values.get("first_name") or "" + last_name = values.get("last_name") or "" + email = values.get("email") or "" + + if not fullname and first_name and last_name: + fullname = first_name + " " + last_name + elif fullname: + try: + first_name, last_name = fullname.rsplit(" ", 1) + except ValueError: + last_name = fullname + + username_key = self.setting("USERNAME_KEY") or self.USERNAME_KEY + values.update( + { + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "username": values.get(username_key) + or (first_name.title() + last_name.title()), + "email": email, + } + ) + return values + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return defined extra data names to store in extra_data field. + Settings will be inspected to get more values names that should be + stored on extra_data field. Setting name is created from current + backend name (all uppercase) plus _SREG_EXTRA_DATA and + _AX_EXTRA_DATA because values can be returned by SimpleRegistration + or AttributeExchange schemas. + + Both list must be a value name and an alias mapping similar to + SREG_ATTR, OLD_AX_ATTRS or AX_SCHEMA_ATTRS + """ + sreg_names = self.setting("SREG_EXTRA_DATA") + ax_names = self.setting("AX_EXTRA_DATA") + values = self.values_from_response(response, sreg_names, ax_names) + from_details = super().extra_data(user, uid, {}, details, *args, **kwargs) + values.update(from_details) + return values + + def auth_url(self): + """Return auth URL returned by service""" + openid_request = self.setup_request(self.auth_extra_arguments()) + # Construct completion URL, including page we should redirect to + return_to = self.strategy.absolute_uri(self.redirect_uri) + return openid_request.redirectURL(self.trust_root(), return_to) + + def auth_html(self): + """Return auth HTML returned by service""" + openid_request = self.setup_request(self.auth_extra_arguments()) + return_to = self.strategy.absolute_uri(self.redirect_uri) + form_tag = {"id": "openid_message"} + return openid_request.htmlMarkup( + self.trust_root(), return_to, form_tag_attrs=form_tag + ) + + def trust_root(self): + """Return trust-root option""" + return self.setting("OPENID_TRUST_ROOT") or self.strategy.absolute_uri("/") + + def continue_pipeline(self, partial): + """Continue previous halted pipeline""" + response = self.consumer().complete( + dict(self.data.items()), self.strategy.absolute_uri(self.redirect_uri) + ) + return self.strategy.authenticate( + self, + response=response, + pipeline_index=partial.next_step, + *partial.args, + **partial.kwargs, + ) + + def auth_complete(self, *args, **kwargs): + """Complete auth process""" + response = self.consumer().complete( + dict(self.data.items()), self.strategy.absolute_uri(self.redirect_uri) + ) + self.process_error(response) + return self.strategy.authenticate(self, response=response, *args, **kwargs) + + def process_error(self, data): + if not data: + raise AuthException(self, "OpenID relying party endpoint") + elif data.status == FAILURE: + raise AuthFailed(self, data.message) + elif data.status == CANCEL: + raise AuthCanceled(self) + elif data.status != SUCCESS: + raise AuthUnknownError(self, data.status) + + def setup_request(self, params=None): + """Setup request""" + request = self.openid_request(params) + # Request some user details. Use attribute exchange if provider + # advertises support. + if request.endpoint.supportsType(ax.AXMessage.ns_uri): + fetch_request = ax.FetchRequest() + # Mark all attributes as required, Google ignores optional ones + for attr, alias in self.get_ax_attributes(): + fetch_request.add(ax.AttrInfo(attr, alias=alias, required=True)) + else: + fetch_request = sreg.SRegRequest( + optional=list(dict(self.get_sreg_attributes()).keys()) + ) + request.addExtension(fetch_request) + + # Add PAPE Extension for if configured + preferred_policies = self.setting("OPENID_PAPE_PREFERRED_AUTH_POLICIES") + preferred_level_types = self.setting("OPENID_PAPE_PREFERRED_AUTH_LEVEL_TYPES") + max_age = self.setting("OPENID_PAPE_MAX_AUTH_AGE") + if max_age is not None: + try: + max_age = int(max_age) + except (ValueError, TypeError): + max_age = None + + if max_age is not None or preferred_policies or preferred_level_types: + pape_request = pape.Request( + max_auth_age=max_age, + preferred_auth_policies=preferred_policies, + preferred_auth_level_types=preferred_level_types, + ) + request.addExtension(pape_request) + return request + + def consumer(self): + """Create an OpenID Consumer object for the given Django request.""" + if not hasattr(self, "_consumer"): + self._consumer = self.create_consumer(self.strategy.openid_store()) + return self._consumer + + def create_consumer(self, store=None): + return Consumer(self.strategy.openid_session_dict(SESSION_NAME), store) + + def uses_redirect(self): + """Return true if openid request will be handled with redirect or + HTML content will be returned. + """ + return self.openid_request().shouldSendRedirect() + + def openid_request(self, params=None): + """Return openid request""" + try: + return self.consumer().begin(url_add_parameters(self.openid_url(), params)) + except DiscoveryFailure as err: + raise AuthException(self, f"OpenID discovery error: {err}") + + def openid_url(self): + """Return service provider URL. + This base class is generic accepting a POST parameter that specifies + provider URL.""" + if self.URL: + return self.URL + elif OPENID_ID_FIELD in self.data: + return self.data[OPENID_ID_FIELD] + else: + raise AuthMissingParameter(self, OPENID_ID_FIELD) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id_connect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id_connect.py new file mode 100644 index 0000000000000000000000000000000000000000..5e37338922a8ab76bb42f724c290a231df9f3d89 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/open_id_connect.py @@ -0,0 +1,255 @@ +import datetime +import json +from calendar import timegm + +from jose import jwk, jwt +from jose.jwt import ExpiredSignatureError, JWTClaimsError, JWTError +from jose.utils import base64url_decode + +from social_core.backends.oauth import BaseOAuth2 +from social_core.exceptions import AuthTokenError +from social_core.utils import cache + + +class OpenIdConnectAssociation: + """Use Association model to save the nonce by force.""" + + def __init__(self, handle, secret="", issued=0, lifetime=0, assoc_type=""): + self.handle = handle # as nonce + self.secret = secret.encode() # not use + self.issued = issued # not use + self.lifetime = lifetime # not use + self.assoc_type = assoc_type # as state + + +class OpenIdConnectAuth(BaseOAuth2): + """ + Base class for Open ID Connect backends. + Currently only the code response type is supported. + + It can also be directly instantiated as a generic OIDC backend. + To use it you will need to set at minimum: + + SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = 'https://.....' # endpoint without /.well-known/openid-configuration + SOCIAL_AUTH_OIDC_KEY = '<client_id>' + SOCIAL_AUTH_OIDC_SECRET = '<client_secret>' + """ + + name = "oidc" + # Override OIDC_ENDPOINT in your subclass to enable autoconfig of OIDC + OIDC_ENDPOINT = None + ID_TOKEN_MAX_AGE = 600 + DEFAULT_SCOPE = ["openid", "profile", "email"] + EXTRA_DATA = ["id_token", "refresh_token", ("sub", "id")] + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + REVOKE_TOKEN_METHOD = "GET" + ID_KEY = "sub" + USERNAME_KEY = "preferred_username" + JWT_ALGORITHMS = ["RS256"] + JWT_DECODE_OPTIONS = dict() + # When these options are unspecified, server will choose via openid autoconfiguration + ID_TOKEN_ISSUER = "" + ACCESS_TOKEN_URL = "" + AUTHORIZATION_URL = "" + REVOKE_TOKEN_URL = "" + USERINFO_URL = "" + JWKS_URI = "" + TOKEN_ENDPOINT_AUTH_METHOD = "" + + def __init__(self, *args, **kwargs): + self.id_token = None + super().__init__(*args, **kwargs) + + def authorization_url(self): + return self.setting( + "AUTHORIZATION_URL", self.AUTHORIZATION_URL + ) or self.oidc_config().get("authorization_endpoint") + + def access_token_url(self): + return self.setting( + "ACCESS_TOKEN_URL", self.ACCESS_TOKEN_URL + ) or self.oidc_config().get("token_endpoint") + + def revoke_token_url(self, token, uid): + return self.setting( + "REVOKE_TOKEN_URL", self.REVOKE_TOKEN_URL + ) or self.oidc_config().get("revocation_endpoint") + + def id_token_issuer(self): + return self.setting( + "ID_TOKEN_ISSUER", self.ID_TOKEN_ISSUER + ) or self.oidc_config().get("issuer") + + def userinfo_url(self): + return self.setting( + "USERINFO_URL", self.USERINFO_URL + ) or self.oidc_config().get("userinfo_endpoint") + + def jwks_uri(self): + return self.setting("JWKS_URI", self.JWKS_URI) or self.oidc_config().get( + "jwks_uri" + ) + + def use_basic_auth(self): + method = self.setting( + "TOKEN_ENDPOINT_AUTH_METHOD", self.TOKEN_ENDPOINT_AUTH_METHOD + ) + if method: + return method == "client_secret_basic" + methods = self.oidc_config().get("token_endpoint_auth_methods_supported", []) + return not methods or "client_secret_basic" in methods + + def oidc_endpoint(self): + return self.setting("OIDC_ENDPOINT", self.OIDC_ENDPOINT) + + @cache(ttl=86400) + def oidc_config(self): + return self.get_json(self.oidc_endpoint() + "/.well-known/openid-configuration") + + @cache(ttl=86400) + def get_jwks_keys(self): + keys = self.get_remote_jwks_keys() + + # Add client secret as oct key so it can be used for HMAC signatures + # client_id, client_secret = self.get_key_and_secret() + # keys.append({'key': client_secret, 'kty': 'oct'}) + return keys + + def get_remote_jwks_keys(self): + response = self.request(self.jwks_uri()) + return json.loads(response.text)["keys"] + + def auth_params(self, state=None): + """Return extra arguments needed on auth process.""" + params = super().auth_params(state) + params["nonce"] = self.get_and_store_nonce(self.authorization_url(), state) + return params + + def get_and_store_nonce(self, url, state): + # Create a nonce + nonce = self.strategy.random_string(64) + # Store the nonce + association = OpenIdConnectAssociation(nonce, assoc_type=state) + self.strategy.storage.association.store(url, association) + return nonce + + def get_nonce(self, nonce): + try: + return self.strategy.storage.association.get( + server_url=self.authorization_url(), handle=nonce + )[0] + except IndexError: + pass + + def remove_nonce(self, nonce_id): + self.strategy.storage.association.remove([nonce_id]) + + def validate_claims(self, id_token): + utc_timestamp = timegm(datetime.datetime.utcnow().utctimetuple()) + + if "nbf" in id_token and utc_timestamp < id_token["nbf"]: + raise AuthTokenError(self, "Incorrect id_token: nbf") + + # Verify the token was issued in the last 10 minutes + iat_leeway = self.setting("ID_TOKEN_MAX_AGE", self.ID_TOKEN_MAX_AGE) + if utc_timestamp > id_token["iat"] + iat_leeway: + raise AuthTokenError(self, "Incorrect id_token: iat") + + # Validate the nonce to ensure the request was not modified + nonce = id_token.get("nonce") + if not nonce: + raise AuthTokenError(self, "Incorrect id_token: nonce") + + nonce_obj = self.get_nonce(nonce) + if nonce_obj: + self.remove_nonce(nonce_obj.id) + else: + raise AuthTokenError(self, "Incorrect id_token: nonce") + + def find_valid_key(self, id_token): + kid = jwt.get_unverified_header(id_token).get("kid") + + keys = self.get_jwks_keys() + if kid is not None: + for key in keys: + if kid == key.get("kid"): + break + else: + # In case the key id is not found in the cached keys, just + # reload the JWKS keys. Ideally this should be done by + # invalidating the cache. + self.get_jwks_keys.invalidate() + keys = self.get_jwks_keys() + + for key in keys: + if kid is None or kid == key.get("kid"): + if "alg" not in key: + key["alg"] = self.setting("JWT_ALGORITHMS", self.JWT_ALGORITHMS)[0] + rsakey = jwk.construct(key) + message, encoded_sig = id_token.rsplit(".", 1) + decoded_sig = base64url_decode(encoded_sig.encode("utf-8")) + if rsakey.verify(message.encode("utf-8"), decoded_sig): + return key + return None + + def validate_and_return_id_token(self, id_token, access_token): + """ + Validates the id_token according to the steps at + http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation. + """ + client_id, client_secret = self.get_key_and_secret() + + key = self.find_valid_key(id_token) + + if not key: + raise AuthTokenError(self, "Signature verification failed") + + rsakey = jwk.construct(key) + + try: + claims = jwt.decode( + id_token, + rsakey.to_pem().decode("utf-8"), + algorithms=self.setting("JWT_ALGORITHMS", self.JWT_ALGORITHMS), + audience=client_id, + issuer=self.id_token_issuer(), + access_token=access_token, + options=self.setting("JWT_DECODE_OPTIONS", self.JWT_DECODE_OPTIONS), + ) + except ExpiredSignatureError: + raise AuthTokenError(self, "Signature has expired") + except JWTClaimsError as error: + raise AuthTokenError(self, str(error)) + except JWTError: + raise AuthTokenError(self, "Invalid signature") + + self.validate_claims(claims) + + return claims + + def request_access_token(self, *args, **kwargs): + """ + Retrieve the access token. Also, validate the id_token and + store it (temporarily). + """ + response = self.get_json(*args, **kwargs) + self.id_token = self.validate_and_return_id_token( + response["id_token"], response["access_token"] + ) + return response + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + self.userinfo_url(), headers={"Authorization": f"Bearer {access_token}"} + ) + + def get_user_details(self, response): + username_key = self.setting("USERNAME_KEY", self.USERNAME_KEY) + return { + "username": response.get(username_key), + "email": response.get("email"), + "fullname": response.get("name"), + "first_name": response.get("given_name"), + "last_name": response.get("family_name"), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openinfra.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openinfra.py new file mode 100644 index 0000000000000000000000000000000000000000..57c77918eb80166667a81ccc7dce62657c4093b8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openinfra.py @@ -0,0 +1,49 @@ +""" +OpenInfra OpenId backend +""" +from urllib.parse import urlsplit + +from openid.extensions import ax + +from .open_id import OpenIdAuth + + +class OpenInfraOpenId(OpenIdAuth): + name = "openinfra" + URL = "id.openinfra.dev" + + def get_user_details(self, response): + """Generate username from identity url""" + values = super().get_user_details(response) + values["username"] = values.get("username") or urlsplit( + response.identity_url + ).path.strip("/") + values["nickname"] = values.get("nickname", "") + return values + + def setup_request(self, params=None): + """Fetch email, firstname, lastname from openid""" + request = self.openid_request(params) + + # TODO: use sreg instead ax request to fetch nickname as username + fetch_request = ax.FetchRequest() + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/contact/email", alias="email", required=True + ) + ) + + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/namePerson/first", alias="firstname", required=True + ) + ) + + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/namePerson/last", alias="lastname", required=True + ) + ) + + request.addExtension(fetch_request) + return request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openshift.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openshift.py new file mode 100644 index 0000000000000000000000000000000000000000..efc5d0fdfdc9ffb8e69cc14d9ffe9ae71f195f44 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openshift.py @@ -0,0 +1,38 @@ +""" +Openshift OAuth2 backend +""" +from urllib.parse import urljoin + +import requests + +from ..utils import append_slash +from .oauth import BaseOAuth2 + + +class OpenshiftOAuth2(BaseOAuth2): + name = "openshift" + ACCESS_TOKEN_METHOD = "POST" + + def access_token_url(self): + return urljoin(append_slash(self.setting("URL")), "oauth/token") + + def authorization_url(self): + return urljoin(append_slash(self.setting("URL")), "oauth/authorize") + + def get_user_id(self, details, response): + return response["metadata"]["uid"] + + def get_user_details(self, response): + """Return user details from openshift account""" + username = response["metadata"]["name"] + email = response["metadata"]["name"] + return {"username": username, "email": email} + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = {"Authorization": "Bearer " + access_token} + + return requests.get( + urljoin(append_slash(self.setting("URL")), "oapi/v1/users/~"), + headers=headers, + ).json() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstack.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstack.py new file mode 100644 index 0000000000000000000000000000000000000000..de1df0d4f19fc86e03c7848e74003c70972c2f63 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstack.py @@ -0,0 +1,49 @@ +""" +OpenStack OpenId backend +""" +from urllib.parse import urlsplit + +from openid.extensions import ax + +from .open_id import OpenIdAuth + + +class OpenStackOpenId(OpenIdAuth): + name = "openstack" + URL = "openstackid.org" + + def get_user_details(self, response): + """Generate username from identity url""" + values = super().get_user_details(response) + values["username"] = values.get("username") or urlsplit( + response.identity_url + ).path.strip("/") + values["nickname"] = values.get("nickname", "") + return values + + def setup_request(self, params=None): + """Fetch email, firstname, lastname from openid""" + request = self.openid_request(params) + + # TODO: use sreg instead ax request to fetch nickname as username + fetch_request = ax.FetchRequest() + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/contact/email", alias="email", required=True + ) + ) + + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/namePerson/first", alias="firstname", required=True + ) + ) + + fetch_request.add( + ax.AttrInfo( + "http://axschema.org/namePerson/last", alias="lastname", required=True + ) + ) + + request.addExtension(fetch_request) + return request diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstreetmap.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstreetmap.py new file mode 100644 index 0000000000000000000000000000000000000000..4cf40bc48894d90509ff0ef8beb2b0ae999001bd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/openstreetmap.py @@ -0,0 +1,58 @@ +""" +OpenStreetMap OAuth support. + +This adds support for OpenStreetMap OAuth service. An application must be +registered first on OpenStreetMap and the settings +SOCIAL_AUTH_OPENSTREETMAP_KEY and SOCIAL_AUTH_OPENSTREETMAP_SECRET +must be defined with the corresponding values. + +More info: https://wiki.openstreetmap.org/wiki/OAuth +""" +from xml.dom import minidom + +from .oauth import BaseOAuth1 + + +class OpenStreetMapOAuth(BaseOAuth1): + """OpenStreetMap OAuth authentication backend""" + + name = "openstreetmap" + AUTHORIZATION_URL = "https://www.openstreetmap.org/oauth/authorize" + REQUEST_TOKEN_URL = "https://www.openstreetmap.org/oauth/request_token" + ACCESS_TOKEN_URL = "https://www.openstreetmap.org/oauth/access_token" + EXTRA_DATA = [ + ("id", "id"), + ("avatar", "avatar"), + ("account_created", "account_created"), + ] + + def get_user_details(self, response): + """Return user details from OpenStreetMap account""" + return { + "username": response["username"], + "email": "", + "fullname": "", + "first_name": "", + "last_name": "", + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + response = self.oauth_request( + access_token, "https://api.openstreetmap.org/api/0.6/user/details" + ) + try: + dom = minidom.parseString(response.content) + except ValueError: + return None + user = dom.getElementsByTagName("user")[0] + try: + avatar = dom.getElementsByTagName("img")[0].getAttribute("href") + except IndexError: + avatar = None + return { + "id": user.getAttribute("id"), + "username": user.getAttribute("display_name"), + "account_created": user.getAttribute("account_created"), + "avatar": avatar, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orbi.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orbi.py new file mode 100644 index 0000000000000000000000000000000000000000..9106d501136771afc7ce3f380fe0b1b3d9806ecf --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orbi.py @@ -0,0 +1,44 @@ +""" +Orbi OAuth2 backend +""" +from .oauth import BaseOAuth2 + + +class OrbiOAuth2(BaseOAuth2): + """Orbi OAuth2 authentication backend""" + + name = "orbi" + AUTHORIZATION_URL = "https://login.orbi.kr/oauth/authorize" + ACCESS_TOKEN_URL = "https://login.orbi.kr/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("imin", "imin"), + ("nick", "nick"), + ("photo", "photo"), + ("sex", "sex"), + ("birth", "birth"), + ] + + def get_user_id(self, details, response): + return response.get("id") + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response.get("name", ""), + response.get("first_name", ""), + response.get("last_name", ""), + ) + return { + "username": response.get("username", response.get("name")), + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Load user data from orbi""" + return self.get_json( + "https://login.orbi.kr/oauth/user/get", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orcid.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orcid.py new file mode 100644 index 0000000000000000000000000000000000000000..459ccd3f3606ae61aa5f1dad3b4d005a1faed42e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/orcid.py @@ -0,0 +1,163 @@ +""" + ORCID OAuth2 Application backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/orcid.html +""" +from .oauth import BaseOAuth2 + + +class ORCIDOAuth2(BaseOAuth2): + """ORCID OAuth2 authentication backend""" + + name = "orcid" + ID_KEY = "orcid" + AUTHORIZATION_URL = "https://orcid.org/oauth/authorize" + ACCESS_TOKEN_URL = "https://orcid.org/oauth/token" + USER_ID_URL = "https://orcid.org/oauth/userinfo" + USER_DATA_URL = "https://pub.orcid.org/v2.0/{}" + DEFAULT_SCOPE = ["/authenticate"] + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("orcid", "id"), + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ] + + def auth_params(self, state=None): + params = super().auth_params(state) + return params + + def get_user_details(self, response): + """Return user details from ORCID account""" + + # response data will be of the following format: + # { + # 'orcid-identifier': { + # 'uri': 'http://orcid.org/0000-0002-2601-8132', + # 'path': '0000-0002-2601-8132', + # 'host': 'orcid.org' + # }, + # 'person': { + # 'last-modified-date': None, + # 'name': { + # 'created-date': { + # 'value': 1578249746904 + # }, + # 'last-modified-date': { + # 'value': 1578249746904 + # }, + # 'given-names': { + # 'value': 'Janani Kantharooban' + # }, + # 'family-name': { + # 'value': 'Umachanger' + # }, + # 'credit-name': None, + # 'source': None, + # 'visibility': 'PUBLIC', + # 'path': '0000-0002-2601-8132' + # }, + # } + # } + orcid_identifier = response.get("orcid-identifier") + + fullname = first_name = last_name = email = username = "" + + person = response.get("person") + + # Although we're checking here, the response will always have the orcid-identifier key: + if orcid_identifier: + username = orcid_identifier["path"] + + if person: + name = person.get("name") + + fullname = name + + if name: + first_name = name.get("given-names", {}).get("value", "") + last_name = name.get("family-name", {}).get("value", "") + + emails = person.get("emails") + if emails: + emails_list = emails.get("email") + if emails_list and len(emails_list) > 0: + email = emails_list[0].get("email", "") + + if len(emails_list) > 1: + for email_dict in emails_list: + if email_dict.get("primary"): + email = email_dict["email"] + break + else: + email = emails_list[0].get("email", "") + + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + params = self.setting("PROFILE_EXTRA_PARAMS", {}) + params["access_token"] = access_token + + # Reference Docs: ORCID Auth Flow: + # https://github.com/ORCID/ORCID-Source/blob/master/orcid-web/ORCID_AUTH_WITH_OPENID_CONNECT.md#other-endpoints + # Sample headers: -H "Accept: application/json" -H "Authorization: Bearer <access_token>" + # This will respond with a json document like this: + # { + # "sub":"0000-0002-2601-8132", + # "name":"Credit Name", + # "family_name":"Jones", + # "given_name":"Tom" + # } + try: + response = self.get_json( + self.USER_ID_URL, + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {str(access_token)}", + }, + ) + + # Update Jan 28 2021: Now we definitely have an ORCID id of format "0000-0000-0000-0000" + orcid = response["sub"] + except Exception: + pass + + # We can now attempt to access the ORCID public API with the Orcid: + try: + return self.get_json( + self.USER_DATA_URL.format(orcid), + headers={"Content-Type": "application/json"}, + params=params, + ) + except Exception: + return None + + +class ORCIDOAuth2Sandbox(ORCIDOAuth2): + """ORCID OAuth2 Sandbox authentication backend""" + + name = "orcid-sandbox" + AUTHORIZATION_URL = "https://sandbox.orcid.org/oauth/authorize" + ACCESS_TOKEN_URL = "https://sandbox.orcid.org/oauth/token" + USER_ID_URL = "https://sandbox.orcid.org/oauth/userinfo" + USER_DATA_URL = "https://pub.sandbox.orcid.org/v2.0/{}" + + +class ORCIDMemberOAuth2(ORCIDOAuth2): + """ORCID OAuth2 authentication backend that uses ORCID Member API""" + + USER_DATA_URL = "https://api.orcid.org/v2.0/{}" + DEFAULT_SCOPE = ["/authenticate", "/read-limited"] + + +class ORCIDMemberOAuth2Sandbox(ORCIDOAuth2Sandbox): + """ORCID OAuth2 Sandbox authentication backend that uses ORCID Member Sandbox API""" + + USER_DATA_URL = "https://api.sandbox.orcid.org/v2.0/{}" + DEFAULT_SCOPE = ["/authenticate", "/read-limited"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/osso.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/osso.py new file mode 100644 index 0000000000000000000000000000000000000000..98d98188d22ae6b8af18104e7a86f35d6eaea64f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/osso.py @@ -0,0 +1,48 @@ +from urllib.parse import urlencode + +from .oauth import BaseOAuth2 + + +class OssoOAuth2(BaseOAuth2): + """Osso OAuth authentication backend""" + + name = "osso" + REDIRECT_STATE = False + STATE_PARAMETER = True + AUTHORIZATION_URL = "{osso_base_url}/oauth/authorize" + ACCESS_TOKEN_URL = "{osso_base_url}/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + + @property + def osso_base_url(self): + return self.setting("OSSO_BASE_URL", "https://demo.ossoapp.com") + + def authorization_url(self): + return self.AUTHORIZATION_URL.format(osso_base_url=self.osso_base_url) + + def access_token_url(self): + return self.ACCESS_TOKEN_URL.format(osso_base_url=self.osso_base_url) + + def auth_params(self, state=None): + client_id, _client_secret = self.get_key_and_secret() + params = {"client_id": client_id, "redirect_uri": self.get_redirect_uri(state)} + if self.data.get("email"): + params["email"] = self.data.get("email") + if self.data.get("domain") and not self.data.get("email"): + params["domain"] = self.data.get("domain") + if self.STATE_PARAMETER and state: + params["state"] = state + if self.RESPONSE_TYPE: + params["response_type"] = self.RESPONSE_TYPE + return params + + def get_user_details(self, response): + """Return user details from Osso""" + return {"username": response.get("email"), "email": response.get("email")} + + def user_data(self, access_token, *args, **kwargs): + """Loads normalized user profile from Osso""" + url = f"{self.osso_base_url}/oauth/me?" + urlencode( + {"access_token": access_token} + ) + return self.get_json(url) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/patreon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/patreon.py new file mode 100644 index 0000000000000000000000000000000000000000..3532a47311c3690d5b91a4a675ded4d1ba83ef7c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/patreon.py @@ -0,0 +1,42 @@ +""" +Patreon OAuth2 backend +https://www.patreon.com/platform/documentation/oauth +""" +from .oauth import BaseOAuth2 + + +class PatreonOAuth2(BaseOAuth2): + """Patreon OAuth2 authentication backend""" + + name = "patreon" + AUTHORIZATION_URL = "https://www.patreon.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://www.patreon.com/api/oauth2/token" + REVOKE_TOKEN_URL = "https://www.patreon.com/oauth2/revoke" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + ID_KEY = "id" + EXTRA_DATA = [ + ("id", "id"), + ] + + def get_user_details(self, response): + details = response["attributes"] + return { + "username": details.get("full_name"), + "email": details.get("email"), + "fullname": details.get("full_name"), + "first_name": details.get("first_name"), + "last_name": details.get("last_name"), + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_api(access_token, "identity")["data"] + + def get_api(self, access_token, suffix): + return self.get_json( + f"https://www.patreon.com/api/oauth2/v2/{suffix}", + headers=self.get_auth_header(access_token), + ) + + def get_auth_header(self, access_token): + return {"Authorization": f"Bearer {access_token}"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/paypal.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/paypal.py new file mode 100644 index 0000000000000000000000000000000000000000..3739bca4165de5c072a28e9dd27bd6d34e7df208 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/paypal.py @@ -0,0 +1,74 @@ +import base64 + +from .oauth import BaseOAuth2 + + +class PayPalOAuth2(BaseOAuth2): + """ + PayPal OAuth2 backend, docs at: + https://developer.paypal.com/docs/connect-with-paypal/integrate/ + """ + + name = "paypal-oauth2" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://www.paypal.com/connect" + ACCESS_TOKEN_URL = "https://api.paypal.com/v1/oauth2/token" + USER_DATA_URL = ( + "https://api.paypal.com/v1/identity/oauth2/userinfo?schema=paypalv1.1" + ) + DEFAULT_SCOPE = ["openid", "profile"] + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def user_data(self, access_token, *args, **kwargs): + auth_header = {"Authorization": "Bearer %s" % access_token} + response = self.get_json(self.USER_DATA_URL, headers=auth_header) + return response + + def get_user_details(self, response): + username = response.get(self.ID_KEY).split("/")[-1] + fullname, first_name, last_name = self.get_user_names( + response.get("name", ""), + response.get("given_name", ""), + response.get("family_name", ""), + ) + emails = response.get("emails", []) + email = self.get_email(emails) + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def auth_complete_params(self, state=None): + return { + "grant_type": "authorization_code", + "code": self.data.get("code", ""), + } + + def auth_headers(self): + auth = ("%s:%s" % self.get_key_and_secret()).encode() + return {"Authorization": b"Basic " + base64.urlsafe_b64encode(auth)} + + def refresh_token_params(self, token, *args, **kwargs): + return {"refresh_token": token, "grant_type": "refresh_token"} + + @staticmethod + def get_email(emails): + if not emails: + return "" + primary_emails = (email for email in emails if email.get("primary", False)) + primary_or_first = next(primary_emails, emails[0]) + return primary_or_first.get("value") + + +class PayPalOAuth2Sandbox(PayPalOAuth2): + name = "paypal-oauth2-sandbox" + AUTHORIZATION_URL = "https://www.sandbox.paypal.com/connect" + ACCESS_TOKEN_URL = "https://api.sandbox.paypal.com/v1/oauth2/token" + USER_DATA_URL = ( + "https://api.sandbox.paypal.com/v1/identity/oauth2/userinfo?schema=paypalv1.1" + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/persona.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/persona.py new file mode 100644 index 0000000000000000000000000000000000000000..f4b2ddedb0fe810b895613b16117bc82a5d3c6c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/persona.py @@ -0,0 +1,56 @@ +""" +Mozilla Persona authentication backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/persona.html +""" +from ..exceptions import AuthFailed, AuthMissingParameter +from ..utils import handle_http_errors +from .base import BaseAuth + + +class PersonaAuth(BaseAuth): + """BrowserID authentication backend""" + + name = "persona" + + def get_user_id(self, details, response): + """Use BrowserID email as ID""" + return details["email"] + + def get_user_details(self, response): + """Return user details, BrowserID only provides Email.""" + # {'status': 'okay', + # 'audience': 'localhost:8000', + # 'expires': 1328983575529, + # 'email': 'name@server.com', + # 'issuer': 'browserid.org'} + email = response["email"] + return { + "username": email.split("@", 1)[0], + "email": email, + "fullname": "", + "first_name": "", + "last_name": "", + } + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return users extra data""" + return {"audience": response["audience"], "issuer": response["issuer"]} + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + if "assertion" not in self.data: + raise AuthMissingParameter(self, "assertion") + + response = self.get_json( + "https://browserid.org/verify", + data={ + "assertion": self.data["assertion"], + "audience": self.strategy.request_host(), + }, + method="POST", + ) + if response.get("status") == "failure": + raise AuthFailed(self) + kwargs.update({"response": response, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/phabricator.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/phabricator.py new file mode 100644 index 0000000000000000000000000000000000000000..a650a64dd78b4a6ce1dc7131b059b993b7ce5b88 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/phabricator.py @@ -0,0 +1,48 @@ +""" +Phabricator OAuth2 backend, docs at: + https://secure.phabricator.com/book/phabcontrib/article/using_oauthserver/ +""" +from .oauth import BaseOAuth2 + + +class PhabricatorOAuth2(BaseOAuth2): + """Phabricator OAuth authentication backend""" + + name = "phabricator" + API_URL = "https://secure.phabricator.com" + AUTHORIZATION_URL = "https://secure.phabricator.com/oauthserver/auth/" + ACCESS_TOKEN_URL = "https://secure.phabricator.com/oauthserver/token/" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def api_url(self, path): + api_url = self.setting("API_URL") or self.API_URL + return "{}{}".format(api_url.rstrip("/"), path) + + def authorization_url(self): + return self.api_url("/oauthserver/auth/") + + def access_token_url(self): + return self.api_url("/oauthserver/token/") + + def get_user_details(self, response): + """Return user details from Phabricator""" + fullname, first_name, last_name = self.get_user_names(response.get("realName")) + + return { + "id": response.get("phid"), + "username": response.get("userName"), + "email": response.get("primaryEmail", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from API""" + return self.get_json( + self.api_url("/api/user.whoami"), + params={ + "access_token": access_token, + }, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pinterest.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pinterest.py new file mode 100644 index 0000000000000000000000000000000000000000..38869afc59b66156ff353c2d9bd5f1989c890b2a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pinterest.py @@ -0,0 +1,43 @@ +""" +Pinterest OAuth2 backend, docs at: + https://developers.pinterest.com/docs/api/authentication/ +""" + +from .oauth import BaseOAuth2 + + +class PinterestOAuth2(BaseOAuth2): + name = "pinterest" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://api.pinterest.com/oauth/" + ACCESS_TOKEN_URL = "https://api.pinterest.com/v1/oauth/token" + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = "POST" + + def user_data(self, access_token, *args, **kwargs): + response = self.get_json( + "https://api.pinterest.com/v1/me/", params={"access_token": access_token} + ) + + if "data" in response: + username = response["data"]["url"].strip("/").split("/")[-1] + response = { + "user_id": response["data"]["id"], + "first_name": response["data"]["first_name"], + "last_name": response["data"]["last_name"], + "username": username, + } + return response + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + first_name=response["first_name"], last_name=response["last_name"] + ) + + return { + "username": response.get("username"), + "email": None, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pixelpin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pixelpin.py new file mode 100644 index 0000000000000000000000000000000000000000..b12af069bbfc9f73a5e38e15b42876dd15911768 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pixelpin.py @@ -0,0 +1,36 @@ +from .open_id_connect import OpenIdConnectAuth + + +class PixelPinOpenIDConnect(OpenIdConnectAuth): + """PixelPin OpenID Connect authentication backend""" + + name = "pixelpin-openidconnect" + ID_KEY = "sub" + AUTHORIZATION_URL = "https://login.pixelpin.io/connect/authorize" + ACCESS_TOKEN_URL = "https://login.pixelpin.io/connect/token" + OIDC_ENDPOINT = "https://login.pixelpin.io" + JWKS_URI = "https://login.pixelpin.io/.well-known/jwks" + ACCESS_TOKEN_METHOD = "POST" + REQUIRES_EMAIL_VALIDATION = False + + def get_user_details(self, response): + """Return user details from PixelPin account""" + first_name = response.get("given_name") + last_name = response.get("family_name") + sub = response.get("sub") + + username = first_name + last_name + sub + + return { + "username": username, + "email": response.get("email"), + "fullname": first_name + " " + last_name, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://login.pixelpin.io/connect/userinfo", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pocket.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pocket.py new file mode 100644 index 0000000000000000000000000000000000000000..93d12c819fe956d4f03e496eb64ed0fdea14e7d1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pocket.py @@ -0,0 +1,45 @@ +""" +Pocket OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/pocket.html +""" +from ..utils import handle_http_errors +from .base import BaseAuth + + +class PocketAuth(BaseAuth): + name = "pocket" + AUTHORIZATION_URL = "https://getpocket.com/auth/authorize" + ACCESS_TOKEN_URL = "https://getpocket.com/v3/oauth/authorize" + REQUEST_TOKEN_URL = "https://getpocket.com/v3/oauth/request" + ID_KEY = "username" + + def get_json(self, url, *args, **kwargs): + headers = {"X-Accept": "application/json"} + kwargs.update({"method": "POST", "headers": headers}) + return super().get_json(url, *args, **kwargs) + + def get_user_details(self, response): + return {"username": response["username"]} + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + return response + + def auth_url(self): + data = { + "consumer_key": self.setting("KEY"), + "redirect_uri": self.redirect_uri, + } + token = self.get_json(self.REQUEST_TOKEN_URL, data=data)["code"] + self.strategy.session_set("pocket_request_token", token) + bits = (self.AUTHORIZATION_URL, token, self.redirect_uri) + return "%s?request_token=%s&redirect_uri=%s" % bits + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + data = { + "consumer_key": self.setting("KEY"), + "code": self.strategy.session_get("pocket_request_token"), + } + response = self.get_json(self.ACCESS_TOKEN_URL, data=data) + kwargs.update({"response": response, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/podio.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/podio.py new file mode 100644 index 0000000000000000000000000000000000000000..11a064a9bf82025d5ba81659515ae55f36db2aa0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/podio.py @@ -0,0 +1,41 @@ +""" +Podio OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/podio.html +""" +from .oauth import BaseOAuth2 + + +class PodioOAuth2(BaseOAuth2): + """Podio OAuth authentication backend""" + + name = "podio" + AUTHORIZATION_URL = "https://podio.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://podio.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("access_token", "access_token"), + ("token_type", "token_type"), + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ] + + def get_user_id(self, details, response): + return response["ref"]["id"] + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response["profile"]["name"] + ) + return { + "username": "user_%d" % response["user"]["user_id"], + "email": response["user"]["mail"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://api.podio.com/user/status", + headers={"Authorization": "OAuth2 " + access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/professionali.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/professionali.py new file mode 100644 index 0000000000000000000000000000000000000000..a7090ea1a7aa1bdc453b813afa7fbf8cc958cc34 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/professionali.py @@ -0,0 +1,55 @@ +""" +Professionaly OAuth 2.0 support. + +This contribution adds support for professionaly.ru OAuth 2.0. +Username is retrieved from the identity returned by server. +""" +from time import time + +from ..utils import parse_qs +from .oauth import BaseOAuth2 + + +class ProfessionaliOAuth2(BaseOAuth2): + name = "professionali" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://api.professionali.ru/oauth/authorize.html" + ACCESS_TOKEN_URL = "https://api.professionali.ru/oauth/getToken.json" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("avatar_big", "avatar_big"), ("link", "link")] + + def get_user_details(self, response): + first_name, last_name = map(response.get, ("firstname", "lastname")) + email = "" + if self.setting("FAKE_EMAIL"): + email = f"{time()}@professionali.ru" + return { + "username": f"{last_name}_{first_name}", + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, response, *args, **kwargs): + url = "https://api.professionali.ru/v6/users/get.json" + fields = list( + set( + ["firstname", "lastname", "avatar_big", "link"] + + self.setting("EXTRA_DATA", []) + ) + ) + params = { + "fields": ",".join(fields), + "access_token": access_token, + "ids[]": response["user_id"], + } + try: + return self.get_json(url, params)[0] + except (TypeError, KeyError, OSError, ValueError, IndexError): + return None + + def get_json(self, url, *args, **kwargs): + return self.request(url, verify=False, *args, **kwargs).json() + + def get_querystring(self, url, *args, **kwargs): + return parse_qs(self.request(url, verify=False, *args, **kwargs).text) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pushbullet.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pushbullet.py new file mode 100644 index 0000000000000000000000000000000000000000..c52c7eaa25b1beb08fbcbe87844624362e71c5b8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/pushbullet.py @@ -0,0 +1,25 @@ +import base64 + +from .oauth import BaseOAuth2 + + +class PushbulletOAuth2(BaseOAuth2): + """pushbullet OAuth authentication backend""" + + name = "pushbullet" + EXTRA_DATA = [("id", "id")] + ID_KEY = "username" + AUTHORIZATION_URL = "https://www.pushbullet.com/authorize" + REQUEST_TOKEN_URL = "https://api.pushbullet.com/oauth2/token" + ACCESS_TOKEN_URL = "https://api.pushbullet.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + STATE_PARAMETER = False + + def get_user_details(self, response): + return {"username": response.get("access_token")} + + def get_user_id(self, details, response): + auth = "Basic {}".format(base64.b64encode(details["username"])) + return self.get_json( + "https://api.pushbullet.com/v2/users/me", headers={"Authorization": auth} + )["iden"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qiita.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qiita.py new file mode 100644 index 0000000000000000000000000000000000000000..6e3c2b3c965281ec7b4b935c507433183be54ecd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qiita.py @@ -0,0 +1,86 @@ +""" +Qiita OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/qiita.html + http://qiita.com/api/v2/docs#get-apiv2oauthauthorize + https://qiita.com/api/v2/docs#get-apiv2authenticated_user +""" +import json + +from social_core.exceptions import AuthException + +from .oauth import BaseOAuth2 + + +class QiitaOAuth2(BaseOAuth2): + """Qiita OAuth authentication backend""" + + name = "qiita" + + AUTHORIZATION_URL = "https://qiita.com/api/v2/oauth/authorize" + ACCESS_TOKEN_URL = "https://qiita.com/api/v2/access_tokens" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + REDIRECT_STATE = True + EXTRA_DATA = [ + ("description", "description"), + ("facebook_id", "facebook_id"), + ("followees_count", "followees_count"), + ("followers_count", "followers_count"), + ("github_login_name", "github_login_name"), + ("id", "id"), + ("items_count", "items_count"), + ("linkedin_id", "linkedin_id"), + ("location", "location"), + ("name", "name"), + ("organization", "organization"), + ("permanent_id", "permanent_id"), + ("profile_image_url", "profile_image_url"), + ("team_only", "team_only"), + ("twitter_screen_name", "twitter_screen_name"), + ("website_url", "website_url"), + ("image_monthly_upload_limit", "image_monthly_upload_limit"), + ("image_monthly_upload_remaining", "image_monthly_upload_remaining"), + ] + + def auth_complete_params(self, state=None): + data = super().auth_complete_params(state) + if "grant_type" in data: + del data["grant_type"] + if "redirect_uri" in data: + del data["redirect_uri"] + return json.dumps(data) + + def auth_headers(self): + return {"Content-Type": "application/json"} + + def request_access_token(self, *args, **kwargs): + data = super().request_access_token(*args, **kwargs) + data.update({"access_token": data["token"]}) + return data + + def get_user_details(self, response): + """Return user details from Qiita account""" + return { + "username": response["id"], + "fullname": response["name"], + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://qiita.com/api/v2/authenticated_user", + headers={"Authorization": f"Bearer {access_token}"}, + ) + + def get_user_id(self, details, response): + """Return user id""" + user_id = None + if self.setting("IDENTIFIED_BY_PERMANENT_ID"): + user_id = response.get("permanent_id") + else: + user_id = response.get("id") + + if user_id is not None: + return str(user_id) + else: + raise AuthException("failed to get user id") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qq.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qq.py new file mode 100644 index 0000000000000000000000000000000000000000..1e70b93adb9a3051de4774016755c2271fa17f9b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/qq.py @@ -0,0 +1,70 @@ +""" +Created on May 13, 2014 + +@author: Yong Zhang (zyfyfe@gmail.com) +""" + +import json + +from ..utils import parse_qs +from .oauth import BaseOAuth2 + + +class QQOAuth2(BaseOAuth2): + name = "qq" + ID_KEY = "openid" + AUTHORIZE_URL = "https://graph.qq.com/oauth2.0/authorize" + ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token" + AUTHORIZATION_URL = "https://graph.qq.com/oauth2.0/authorize" + OPENID_URL = "https://graph.qq.com/oauth2.0/me" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("nickname", "username"), + ("figureurl_qq_1", "profile_image_url"), + ("gender", "gender"), + ] + + def get_user_details(self, response): + """ + Return user detail from QQ account sometimes nickname will duplicate + with another qq account, to avoid this issue it's possible to use + openid as username. + """ + if self.setting("USE_OPENID_AS_USERNAME", False): + username = response.get("openid", "") + else: + username = response.get("nickname", "") + + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("nickname", "") + ) + + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def get_openid(self, access_token): + response = self.request(self.OPENID_URL, params={"access_token": access_token}) + content = response.content.decode() + data = json.loads(content[10:-3]) + return data["openid"] + + def user_data(self, access_token, *args, **kwargs): + openid = self.get_openid(access_token) + response = self.get_json( + "https://graph.qq.com/user/get_user_info", + params={ + "access_token": access_token, + "oauth_consumer_key": self.setting("KEY"), + "openid": openid, + }, + ) + response["openid"] = openid + return response + + def request_access_token(self, url, data, *args, **kwargs): + response = self.request(url, *args, **kwargs) + return parse_qs(response.content) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/quizlet.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/quizlet.py new file mode 100644 index 0000000000000000000000000000000000000000..bb44e3895e27abdafd6fc0981e7c5261a24b37f2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/quizlet.py @@ -0,0 +1,22 @@ +""" +Quizlet OAuth2 Sign-in backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/quizlet.html +""" +from .oauth import BaseOAuth2 + + +class QuizletOAuth2(BaseOAuth2): + """Quizlet OAuth2""" + + name = "quizlet" + ID_KEY = "user_id" + API_URL = "https://api.quizlet.com/2.0/" + AUTHORIZATION_URL = "https://quizlet.com/authorize" + ACCESS_TOKEN_URL = "https://api.quizlet.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + DEFAULT_SCOPE = ["read"] + + def get_user_details(self, response): + """Return user details from Quizlet account""" + return {"username": response.get("user_id")} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/rdio.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/rdio.py new file mode 100644 index 0000000000000000000000000000000000000000..9711014ae8a107c0ca4a96415c8862fa533485d6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/rdio.py @@ -0,0 +1,78 @@ +""" +Rdio OAuth1 and OAuth2 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/rdio.html +""" +from .oauth import BaseOAuth1, BaseOAuth2, OAuthAuth + +RDIO_API = "https://www.rdio.com/api/1/" + + +class BaseRdio(OAuthAuth): + ID_KEY = "key" + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + fullname=response["displayName"], + first_name=response["firstName"], + last_name=response["lastName"], + ) + return { + "username": response["username"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + +class RdioOAuth1(BaseRdio, BaseOAuth1): + """Rdio OAuth authentication backend""" + + name = "rdio-oauth1" + REQUEST_TOKEN_URL = "http://api.rdio.com/oauth/request_token" + AUTHORIZATION_URL = "https://www.rdio.com/oauth/authorize" + ACCESS_TOKEN_URL = "http://api.rdio.com/oauth/access_token" + EXTRA_DATA = [ + ("key", "rdio_id"), + ("icon", "rdio_icon_url"), + ("url", "rdio_profile_url"), + ("username", "rdio_username"), + ("streamRegion", "rdio_stream_region"), + ] + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + params = { + "method": "currentUser", + "extras": "username,displayName,streamRegion", + } + request = self.oauth_request(access_token, RDIO_API, params, method="POST") + return self.get_json(request.url, method="POST", data=request.to_postdata())[ + "result" + ] + + +class RdioOAuth2(BaseRdio, BaseOAuth2): + name = "rdio-oauth2" + AUTHORIZATION_URL = "https://www.rdio.com/oauth2/authorize" + ACCESS_TOKEN_URL = "https://www.rdio.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("key", "rdio_id"), + ("icon", "rdio_icon_url"), + ("url", "rdio_profile_url"), + ("username", "rdio_username"), + ("streamRegion", "rdio_stream_region"), + ("refresh_token", "refresh_token", True), + ("token_type", "token_type", True), + ] + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + RDIO_API, + method="POST", + data={ + "method": "currentUser", + "extras": "username,displayName,streamRegion", + "access_token": access_token, + }, + )["result"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/readability.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/readability.py new file mode 100644 index 0000000000000000000000000000000000000000..e037ef03a3e3adaa03259c8a0d4e61deb8fbad41 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/readability.py @@ -0,0 +1,39 @@ +""" +Readability OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/readability.html +""" +from .oauth import BaseOAuth1 + +READABILITY_API = "https://www.readability.com/api/rest/v1" + + +class ReadabilityOAuth(BaseOAuth1): + """Readability OAuth authentication backend""" + + name = "readability" + ID_KEY = "username" + AUTHORIZATION_URL = f"{READABILITY_API}/oauth/authorize/" + REQUEST_TOKEN_URL = f"{READABILITY_API}/oauth/request_token/" + ACCESS_TOKEN_URL = f"{READABILITY_API}/oauth/access_token/" + EXTRA_DATA = [ + ("date_joined", "date_joined"), + ("kindle_email_address", "kindle_email_address"), + ("avatar_url", "avatar_url"), + ("email_into_address", "email_into_address"), + ] + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + first_name=response["first_name"], last_name=response["last_name"] + ) + return { + "username": response["username"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token): + return self.get_json( + READABILITY_API + "/users/_current", auth=self.oauth_auth(access_token) + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/reddit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/reddit.py new file mode 100644 index 0000000000000000000000000000000000000000..8d35682d430bb41133f7f8ea06c0b0d9023a1a13 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/reddit.py @@ -0,0 +1,62 @@ +""" +Reddit OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/reddit.html +""" +import base64 + +from .oauth import BaseOAuth2 + + +class RedditOAuth2(BaseOAuth2): + """Reddit OAuth2 authentication backend""" + + name = "reddit" + AUTHORIZATION_URL = "https://ssl.reddit.com/api/v1/authorize" + ACCESS_TOKEN_URL = "https://ssl.reddit.com/api/v1/access_token" + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + SCOPE_SEPARATOR = "," + DEFAULT_SCOPE = ["identity"] + SEND_USER_AGENT = True + EXTRA_DATA = [ + ("id", "id"), + ("name", "username"), + ("link_karma", "link_karma"), + ("comment_karma", "comment_karma"), + ("refresh_token", "refresh_token"), + ("expires_in", "expires"), + ] + + def get_user_details(self, response): + """Return user details from Reddit account""" + return { + "username": response.get("name"), + "email": "", + "fullname": "", + "first_name": "", + "last_name": "", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://oauth.reddit.com/api/v1/me.json", + headers={"Authorization": "bearer " + access_token}, + ) + + def auth_headers(self): + return { + "Authorization": b"Basic " + + base64.urlsafe_b64encode( + "{}:{}".format(*self.get_key_and_secret()).encode() + ) + } + + def refresh_token_params(self, token, redirect_uri=None, *args, **kwargs): + params = super().refresh_token_params(token) + params["redirect_uri"] = self.redirect_uri or redirect_uri + return params + + def auth_complete_credentials(self): + return self.get_key_and_secret() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/runkeeper.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/runkeeper.py new file mode 100644 index 0000000000000000000000000000000000000000..fb9eae5aa5bc054a3b24c523bc1a45dc6fb15a4d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/runkeeper.py @@ -0,0 +1,50 @@ +""" +RunKeeper OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/runkeeper.html +""" +from .oauth import BaseOAuth2 + + +class RunKeeperOAuth2(BaseOAuth2): + """RunKeeper OAuth authentication backend""" + + name = "runkeeper" + AUTHORIZATION_URL = "https://runkeeper.com/apps/authorize" + ACCESS_TOKEN_URL = "https://runkeeper.com/apps/token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("userID", "id"), + ] + + def get_user_id(self, details, response): + return response["userID"] + + def get_user_details(self, response): + """Parse username from profile link""" + username = None + profile_url = response.get("profile") + if len(profile_url): + profile_url_parts = profile_url.split("http://runkeeper.com/user/") + if len(profile_url_parts) > 1 and len(profile_url_parts[1]): + username = profile_url_parts[1] + fullname, first_name, last_name = self.get_user_names( + fullname=response.get("name") + ) + return { + "username": username, + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + # We need to use the /user endpoint to get the user id, the /profile + # endpoint contains name, user name, location, gender + user_data = self._user_data(access_token, "/user") + profile_data = self._user_data(access_token, "/profile") + return dict(user_data, **profile_data) + + def _user_data(self, access_token, path): + url = f"https://api.runkeeper.com{path}" + return self.get_json(url, params={"access_token": access_token}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/salesforce.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/salesforce.py new file mode 100644 index 0000000000000000000000000000000000000000..3b419f60ead35e6c7a32f09655a1900f98a3031e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/salesforce.py @@ -0,0 +1,50 @@ +from urllib.parse import urlencode + +from .oauth import BaseOAuth2 + + +class SalesforceOAuth2(BaseOAuth2): + """Salesforce OAuth2 authentication backend""" + + name = "salesforce-oauth2" + AUTHORIZATION_URL = "https://login.salesforce.com/services/oauth2/authorize" + ACCESS_TOKEN_URL = "https://login.salesforce.com/services/oauth2/token" + REVOKE_TOKEN_URL = "https://login.salesforce.com/services/oauth2/revoke" + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + EXTRA_DATA = [ + ("id", "id"), + ("instance_url", "instance_url"), + ("issued_at", "issued_at"), + ("signature", "signature"), + ("refresh_token", "refresh_token"), + ] + + def get_user_details(self, response): + """Return user details from a Salesforce account""" + return { + "username": response.get("username"), + "email": response.get("email") or "", + "first_name": response.get("first_name"), + "last_name": response.get("last_name"), + "fullname": response.get("display_name"), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + user_id_url = kwargs.get("response").get("id") + url = user_id_url + "?" + urlencode({"access_token": access_token}) + try: + return self.get_json(url) + except ValueError: + return None + + +class SalesforceOAuth2Sandbox(SalesforceOAuth2): + """Salesforce OAuth2 authentication testing backend""" + + name = "salesforce-oauth2-sandbox" + AUTHORIZATION_URL = "https://test.salesforce.com/services/oauth2/authorize" + ACCESS_TOKEN_URL = "https://test.salesforce.com/services/oauth2/token" + REVOKE_TOKEN_URL = "https://test.salesforce.com/services/oauth2/revoke" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/saml.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/saml.py new file mode 100644 index 0000000000000000000000000000000000000000..aa912f68697b341dd5010b4c12a1c40d1c5dc7e1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/saml.py @@ -0,0 +1,362 @@ +""" +Backend for SAML 2.0 support + +Terminology: + +"Service Provider" (SP): Your web app +"Identity Provider" (IdP): The third-party site that is authenticating + users via SAML +""" +from onelogin.saml2.auth import OneLogin_Saml2_Auth +from onelogin.saml2.settings import OneLogin_Saml2_Settings + +from ..exceptions import AuthFailed, AuthMissingParameter +from .base import BaseAuth + +# Helpful constants: +OID_COMMON_NAME = "urn:oid:2.5.4.3" +OID_EDU_PERSON_PRINCIPAL_NAME = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6" +OID_EDU_PERSON_ENTITLEMENT = "urn:oid:1.3.6.1.4.1.5923.1.1.1.7" +OID_GIVEN_NAME = "urn:oid:2.5.4.42" +OID_MAIL = "urn:oid:0.9.2342.19200300.100.1.3" +OID_SURNAME = "urn:oid:2.5.4.4" +OID_USERID = "urn:oid:0.9.2342.19200300.100.1.1" + + +class SAMLIdentityProvider: + """Wrapper around configuration for a SAML Identity provider""" + + def __init__(self, name, **kwargs): + """Load and parse configuration""" + self.name = name + # name should be a slug and must not contain a colon, which + # could conflict with uid prefixing: + assert ( + ":" not in self.name and " " not in self.name + ), 'IdP "name" should be a slug (short, no spaces)' + self.conf = kwargs + + def get_user_permanent_id(self, attributes): + """ + The most important method: Get a permanent, unique identifier + for this user from the attributes supplied by the IdP. + + If you want to use the NameID, it's available via + attributes['name_id'] + """ + uid = attributes[self.conf.get("attr_user_permanent_id", OID_USERID)] + if isinstance(uid, list): + uid = uid[0] + return uid + + # Attributes processing: + def get_user_details(self, attributes): + """ + Given the SAML attributes extracted from the SSO response, get + the user data like name. + """ + return { + "fullname": self.get_attr(attributes, "attr_full_name", OID_COMMON_NAME), + "first_name": self.get_attr(attributes, "attr_first_name", OID_GIVEN_NAME), + "last_name": self.get_attr(attributes, "attr_last_name", OID_SURNAME), + "username": self.get_attr(attributes, "attr_username", OID_USERID), + "email": self.get_attr(attributes, "attr_email", OID_MAIL), + } + + def get_attr(self, attributes, conf_key, default_attribute): + """ + Internal helper method. + Get the attribute 'default_attribute' out of the attributes, + unless self.conf[conf_key] overrides the default by specifying + another attribute to use. + """ + key = self.conf.get(conf_key, default_attribute) + value = attributes[key] if key in attributes else None + if isinstance(value, list): + value = value[0] if value else None + return value + + @property + def entity_id(self): + """Get the entity ID for this IdP""" + # Required. e.g. "https://idp.testshib.org/idp/shibboleth" + return self.conf["entity_id"] + + @property + def sso_url(self): + """Get the SSO URL for this IdP""" + # Required. e.g. + # "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO" + return self.conf["url"] + + @property + def slo_url(self): + """Get the SLO URL for this IdP""" + return self.conf.get("slo_url") + + @property + def saml_config_dict(self): + """Get the IdP configuration dict in the format required by + python-saml""" + result = { + "entityId": self.entity_id, + "singleSignOnService": { + "url": self.sso_url, + # python-saml only supports Redirect + "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", + }, + } + + if self.slo_url: + result["singleLogoutService"] = { + "url": self.slo_url, + "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", + } + + cert = self.conf.get("x509cert", None) + if cert: + result["x509cert"] = cert + return result + cert = self.conf.get("x509certMulti", None) + if cert: + result["x509certMulti"] = cert + return result + raise KeyError("IDP must contain x509cert or x509certMulti") + + +class DummySAMLIdentityProvider(SAMLIdentityProvider): + """ + A placeholder IdP used when we must specify something, e.g. when + generating SP metadata. + + If OneLogin_Saml2_Auth is modified to not always require IdP + config, this can be removed. + """ + + def __init__(self): + super().__init__( + "dummy", + entity_id="https://dummy.none/saml2", + url="https://dummy.none/SSO", + x509cert="", + ) + + +class SAMLAuth(BaseAuth): + """ + PSA Backend that implements SAML 2.0 Service Provider (SP) functionality. + + Unlike all of the other backends, this one can be configured to work with + many identity providers (IdPs). For example, a University that belongs to a + Shibboleth federation may support authentication via ~100 partner + universities. Also, the IdP configuration can be changed at runtime if you + require that functionality - just subclass this and override `get_idp()`. + + Several settings are required. Here's an example: + + SOCIAL_AUTH_SAML_SP_ENTITY_ID = "https://saml.example.com/" + SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = "... X.509 certificate string ..." + SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = "... private key ..." + SOCIAL_AUTH_SAML_ORG_INFO = { + "en-US": { + "name": "example", + "displayname": "Example Inc.", + "url": "http://example.com" + } + } + SOCIAL_AUTH_SAML_TECHNICAL_CONTACT = { + "givenName": "Tech Gal", + "emailAddress": "technical@example.com" + } + SOCIAL_AUTH_SAML_SUPPORT_CONTACT = { + "givenName": "Support Guy", + "emailAddress": "support@example.com" + } + SOCIAL_AUTH_SAML_ENABLED_IDPS = { + "testshib": { + "entity_id": "https://idp.testshib.org/idp/shibboleth", + "url": "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO", + "x509cert": "MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0B... + ...8Bbnl+ev0peYzxFyF5sQA==", + } + } + + Optional settings: + SOCIAL_AUTH_SAML_SP_EXTRA = {} + SOCIAL_AUTH_SAML_SECURITY_CONFIG = {} + """ + + name = "saml" + EXTRA_DATA = [] + + def get_idp(self, idp_name): + """Given the name of an IdP, get a SAMLIdentityProvider instance""" + idp_config = self.setting("ENABLED_IDPS")[idp_name] + return SAMLIdentityProvider(idp_name, **idp_config) + + def generate_saml_config(self, idp=None): + """ + Generate the configuration required to instantiate OneLogin_Saml2_Auth + """ + # The shared absolute URL that all IdPs redirect back to - + # this is specified in our metadata.xml: + abs_completion_url = self.redirect_uri + config = { + "contactPerson": { + "technical": self.setting("TECHNICAL_CONTACT"), + "support": self.setting("SUPPORT_CONTACT"), + }, + "debug": True, + "idp": idp.saml_config_dict if idp else {}, + "organization": self.setting("ORG_INFO"), + "security": { + "metadataValidUntil": "", + "metadataCacheDuration": "P10D", # metadata valid for ten days + }, + "sp": { + "assertionConsumerService": { + "url": abs_completion_url, + # python-saml only supports HTTP-POST + "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", + }, + "entityId": self.setting("SP_ENTITY_ID"), + "x509cert": self.setting("SP_PUBLIC_CERT"), + "privateKey": self.setting("SP_PRIVATE_KEY"), + }, + "strict": True, # We must force strict mode - for security + } + config["security"].update(self.setting("SECURITY_CONFIG", {})) + config["sp"].update(self.setting("SP_EXTRA", {})) + return config + + def generate_metadata_xml(self): + """ + Helper method that can be used from your web app to generate the XML + metadata required to link your web app as a Service Provider. + + Returns (metadata XML string, list of errors) + + Example usage (Django): + from ..apps.django_app.utils import load_strategy, \ + load_backend + def saml_metadata_view(request): + complete_url = reverse('social:complete', args=("saml", )) + saml_backend = load_backend(load_strategy(request), "saml", + complete_url) + metadata, errors = saml_backend.generate_metadata_xml() + if not errors: + return HttpResponse(content=metadata, + content_type='text/xml') + return HttpResponseServerError(content=', '.join(errors)) + """ + config = self.generate_saml_config() + saml_settings = OneLogin_Saml2_Settings(config, sp_validation_only=True) + metadata = saml_settings.get_sp_metadata() + errors = saml_settings.validate_metadata(metadata) + return metadata, errors + + def _create_saml_auth(self, idp): + """Get an instance of OneLogin_Saml2_Auth""" + config = self.generate_saml_config(idp) + request_info = { + "https": "on" if self.strategy.request_is_secure() else "off", + "http_host": self.strategy.request_host(), + "script_name": self.strategy.request_path(), + "get_data": self.strategy.request_get(), + "post_data": self.strategy.request_post(), + } + return OneLogin_Saml2_Auth(request_info, config) + + def auth_url(self): + """Get the URL to which we must redirect in order to + authenticate the user""" + try: + idp_name = self.strategy.request_data()["idp"] + except KeyError: + raise AuthMissingParameter(self, "idp") + auth = self._create_saml_auth(idp=self.get_idp(idp_name)) + # Below, return_to sets the RelayState, which can contain + # arbitrary data. We use it to store the specific SAML IdP + # name, since we multiple IdPs share the same auth_complete + # URL. + return auth.login(return_to=idp_name) + + def get_user_details(self, response): + """Get user details like full name, email, etc. from the + response - see auth_complete""" + idp = self.get_idp(response["idp_name"]) + return idp.get_user_details(response["attributes"]) + + def get_user_id(self, details, response): + """ + Get the permanent ID for this user from the response. + We prefix each ID with the name of the IdP so that we can + connect multiple IdPs to this user. + """ + idp = self.get_idp(response["idp_name"]) + uid = idp.get_user_permanent_id(response["attributes"]) + return f"{idp.name}:{uid}" + + def auth_complete(self, *args, **kwargs): + """ + The user has been redirected back from the IdP and we should + now log them in, if everything checks out. + """ + idp_name = self.strategy.request_data()["RelayState"] + idp = self.get_idp(idp_name) + auth = self._create_saml_auth(idp) + auth.process_response() + errors = auth.get_errors() + if errors or not auth.is_authenticated(): + reason = auth.get_last_error_reason() + raise AuthFailed(self, f"SAML login failed: {errors} ({reason})") + + attributes = auth.get_attributes() + attributes["name_id"] = auth.get_nameid() + self._check_entitlements(idp, attributes) + response = { + "idp_name": idp_name, + "attributes": attributes, + "session_index": auth.get_session_index(), + } + kwargs.update({"response": response, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + extra_data = super().extra_data( + user, uid, response["attributes"], details=details, *args, **kwargs + ) + extra_data["session_index"] = response["session_index"] + extra_data["name_id"] = response["attributes"]["name_id"] + return extra_data + + def request_logout(self, idp_name, social_auth, return_to=None): + idp = self.get_idp(idp_name) + auth = self._create_saml_auth(idp) + name_id = social_auth.extra_data["name_id"] + session_index = social_auth.extra_data["session_index"] + return auth.logout( + name_id=name_id, session_index=session_index, return_to=return_to + ) + + def process_logout(self, idp_name, delete_session_cb): + idp = self.get_idp(idp_name) + auth = self._create_saml_auth(idp) + url = auth.process_slo(delete_session_cb=delete_session_cb) + errors = auth.get_errors() + return url, errors + + def _check_entitlements(self, idp, attributes): + """ + Additional verification of a SAML response before + authenticating the user. + + Subclasses can override this method if they need custom + validation code, such as requiring the presence of an + eduPersonEntitlement. + + raise social_core.exceptions.AuthForbidden if the user should not + be authenticated, or do nothing to allow the login pipeline to + continue. + """ + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/scistarter.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/scistarter.py new file mode 100644 index 0000000000000000000000000000000000000000..8a4990d6981c9b7f3330410d6b8504267668ab72 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/scistarter.py @@ -0,0 +1,56 @@ +""" SciStarter OAuth2 Auth """ + +from .oauth import BaseOAuth2 + + +class SciStarterOAuth2(BaseOAuth2): + name = "scistarter" + ID_KEY = "email" + SCOPE_PARAMETER_NAME = "scope" + DEFAULT_SCOPE = ["login", "extensive"] + SCOPE_SEPARATOR = " " + AUTHORIZATION_URL = "https://scistarter.com/authorize" + ACCESS_TOKEN_URL = "https://scistarter.com/token?key={key}" + ACCESS_TOKEN_METHOD = "POST" + USER_ACCESS_URL = ( + "https://scistarter.com/api/user_info?client_id={clientid}&key={key}" + ) + REFRESH_TOKEN_URL = None + RESPONSE_TYPE = "code" + STATE_PARAMETER = True + REDIRECT_STATE = True + EXTRA_DATA = [("profile_id", "profile_id"), ("expires", "expires")] + + def get_redirect_uri(self, state=None): + """Build redirect with redirect_state parameter.""" + return self.redirect_uri.rstrip("/") + + def authorization_url(self): + return self.AUTHORIZATION_URL + + def get_user_details(self, response): + return { + "username": response.get("handle"), + "email": response.get("email") or "", + "first_name": response.get("first_name"), + "last_name": response.get("last_name"), + } + + def user_data(self, access_token, *args, **kwards): + client_id, client_secret = self.get_key_and_secret() + return self.get_json( + self.USER_ACCESS_URL.format(clientid=client_id, key=client_secret), + headers={"Authorization": "Bearer " + access_token}, + ) + + def access_token(self, token): + """Return request for access token value""" + return self.get_querystring( + self.access_token_url(), + auth=self.oauth_auth(token), + method=self.ACCESS_TOKEN_METHOD, + ) + + def access_token_url(self): + client_id, client_secret = self.get_key_and_secret() + return self.ACCESS_TOKEN_URL.format(key=client_secret) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/seznam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/seznam.py new file mode 100644 index 0000000000000000000000000000000000000000..a7b4cb001e8f296689d0eadda205cadc59a4d048 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/seznam.py @@ -0,0 +1,51 @@ +""" +Seznam OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/seznam.html +""" +from .oauth import BaseOAuth2 + + +class SeznamOAuth2(BaseOAuth2): + """Seznam OAuth authentication backend""" + + name = "seznam-oauth2" + API_URL = "https://login.szn.cz/api/v1/user" + AUTHORIZATION_URL = "https://login.szn.cz/api/v1/oauth/auth" + ACCESS_TOKEN_URL = "https://login.szn.cz/api/v1/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + ID_KEY = "oauth_user_id" + STATE_PARAMETER = True + DEFAULT_SCOPE = ["identity"] + + def api_url(self): + return self.setting("API_URL") or self.API_URL + + def authorization_url(self): + return self.setting("AUTHORIZATION_URL") or self.AUTHORIZATION_URL + + def access_token_url(self): + return self.setting("ACCESS_TOKEN_URL") or self.ACCESS_TOKEN_URL + + def get_user_id(self, details, response): + return response.get(self.setting("ID_KEY") or self.ID_KEY) + + def get_user_details(self, response): + """Return user details from Seznam account""" + fullname, first_name, last_name = self.get_user_names( + response.get("name"), + first_name=response.get("firstname"), + last_name=response.get("lastname"), + ) + return { + "username": response.get("username"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.api_url(), headers={"Authorization": f"bearer {access_token}"} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shimmering.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shimmering.py new file mode 100644 index 0000000000000000000000000000000000000000..d626093f764aae91dd5c6bdccbe494ae8671a522 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shimmering.py @@ -0,0 +1,36 @@ +""" +Shimmering Oauth +""" +from .oauth import BaseOAuth2 + + +class ShimmeringOAuth2(BaseOAuth2): + """Shimmering Verify OAuth2 authentication backend""" + + name = "shimmering" + ID_KEY = "id" + AUTHORIZATION_URL = "http://developers.shimmeringverify.com/o/authorize/" + ACCESS_TOKEN_URL = "http://developers.shimmeringverify.com/o/token/" + ACCESS_TOKEN_METHOD = "POST" + + def get_user_details(self, response): + """Return user details from Shimmering""" + first_name = response.get("first_name") + last_name = response.get("last_name") + email = response.get("email") + username = response.get("username") + fullname = f"{first_name} {last_name}" + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = {"Authorization": "Bearer %s" % access_token} + return self.get_json( + "http://developers.shimmeringverify.com/user_info/", headers=headers + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shopify.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shopify.py new file mode 100644 index 0000000000000000000000000000000000000000..60602c9003d703d82d52896f8f28abdf73feef32 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/shopify.py @@ -0,0 +1,92 @@ +""" +Shopify OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/shopify.html +""" +import imp + +from ..exceptions import AuthCanceled, AuthFailed +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class ShopifyOAuth2(BaseOAuth2): + """Shopify OAuth2 authentication backend""" + + name = "shopify" + ID_KEY = "shop" + EXTRA_DATA = [("shop", "shop"), ("website", "website"), ("expires", "expires")] + REDIRECT_STATE = False + + @property + def shopify_api_version(self): + return self.setting("API_VERSION", "2020-10") + + @property + def shopify_api(self): + if not hasattr(self, "_shopify_api"): + fp, pathname, description = imp.find_module("shopify") + self._shopify_api = imp.load_module("shopify", fp, pathname, description) + return self._shopify_api + + def get_user_details(self, response): + """Use the shopify store name as the username""" + return {"username": str(response.get("shop", "")).replace(".myshopify.com", "")} + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + """Return access_token and extra defined names to store in + extra_data field""" + data = super().extra_data(user, uid, response, details, *args, **kwargs) + session = self.shopify_api.Session( + self.data.get("shop").strip(), version=self.shopify_api_version + ) + # Get, and store the permanent token + token = session.request_token(data["access_token"]) + data["access_token"] = token + return dict(data) + + def auth_url(self): + key, secret = self.get_key_and_secret() + self.shopify_api.Session.setup(api_key=key, secret=secret) + scope = self.get_scope() + state = self.state_token() + self.strategy.session_set(self.name + "_state", state) + redirect_uri = self.get_redirect_uri(state) + session = self.shopify_api.Session( + self.data.get("shop").strip(), version=self.shopify_api_version + ) + return session.create_permission_url(scope=scope, redirect_uri=redirect_uri) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + access_token = None + key, secret = self.get_key_and_secret() + try: + shop_url = self.data.get("shop") + self.shopify_api.Session.setup(api_key=key, secret=secret) + shopify_session = self.shopify_api.Session( + shop_url, version=self.shopify_api_version, token=self.data + ) + access_token = shopify_session.token + except self.shopify_api.ValidationException: + raise AuthCanceled(self) + else: + if not access_token: + raise AuthFailed(self, "Authentication Failed") + return self.do_auth( + access_token, shop_url, shopify_session.url, *args, **kwargs + ) + + def do_auth(self, access_token, shop_url, website, *args, **kwargs): + kwargs.update( + { + "backend": self, + "response": { + "shop": shop_url, + "website": f"http://{website}", + "access_token": access_token, + }, + } + ) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/simplelogin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/simplelogin.py new file mode 100644 index 0000000000000000000000000000000000000000..42dd9a3c56b7bdf696cf46283ac06cf198beb8eb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/simplelogin.py @@ -0,0 +1,41 @@ +""" +SimpleLogin OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/simplelogin.html +""" + +from .oauth import BaseOAuth2 + + +class SimpleLoginOAuth2(BaseOAuth2): + """SimpleLogin OAuth authentication backend""" + + name = "simplelogin" + AUTHORIZATION_URL = "https://app.simplelogin.io/oauth2/authorize" + ACCESS_TOKEN_URL = "https://app.simplelogin.io/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + STATE_PARAMETER = True + SEND_USER_AGENT = True + EXTRA_DATA = [ + ("name", "name"), + ("email", "email"), + ("avatar_url", "avatar_url"), + ] + + # endpoint to get user info + USERINFO_URL = "https://app.simplelogin.io/oauth2/userinfo" + + def get_user_details(self, response): + """Return user details from SimpleLogin account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": response.get("email"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json(self.USERINFO_URL, params={"access_token": access_token}) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/sketchfab.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/sketchfab.py new file mode 100644 index 0000000000000000000000000000000000000000..6fb293e77074e042e72252b1a9d52aea45a2765b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/sketchfab.py @@ -0,0 +1,39 @@ +""" +Sketchfab OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/sketchfab.html + https://sketchfab.com/developers/oauth +""" +from .oauth import BaseOAuth2 + + +class SketchfabOAuth2(BaseOAuth2): + name = "sketchfab" + ID_KEY = "uid" + AUTHORIZATION_URL = "https://sketchfab.com/oauth2/authorize/" + ACCESS_TOKEN_URL = "https://sketchfab.com/oauth2/token/" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + REQUIRES_EMAIL_VALIDATION = False + EXTRA_DATA = [("username", "username"), ("apiToken", "apiToken")] + + def get_user_details(self, response): + """Return user details from Sketchfab account""" + user_data = response + email = user_data.get("email", "") + username = user_data["username"] + name = user_data.get("displayName", "") + fullname, first_name, last_name = self.get_user_names(name) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://sketchfab.com/v2/users/me", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/skyrock.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/skyrock.py new file mode 100644 index 0000000000000000000000000000000000000000..428907b5bfc7aa903ee16cbc89cef9d4b60ef94b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/skyrock.py @@ -0,0 +1,36 @@ +""" +Skyrock OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/skyrock.html +""" +from .oauth import BaseOAuth1 + + +class SkyrockOAuth(BaseOAuth1): + """Skyrock OAuth authentication backend""" + + name = "skyrock" + ID_KEY = "id_user" + AUTHORIZATION_URL = "https://api.skyrock.com/v2/oauth/authenticate" + REQUEST_TOKEN_URL = "https://api.skyrock.com/v2/oauth/initiate" + ACCESS_TOKEN_URL = "https://api.skyrock.com/v2/oauth/token" + EXTRA_DATA = [("id", "id")] + + def get_user_details(self, response): + """Return user details from Skyrock account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response["firstname"], last_name=response["name"] + ) + return { + "username": response["username"], + "email": response["email"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token): + """Return user data provided""" + return self.get_json( + "https://api.skyrock.com/v2/user/get.json", + auth=self.oauth_auth(access_token), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/slack.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/slack.py new file mode 100644 index 0000000000000000000000000000000000000000..46757cf94a76d9822eced0540de9918983b6798e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/slack.py @@ -0,0 +1,58 @@ +""" +Slack OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/slack.html + https://api.slack.com/docs/oauth +""" + +from .oauth import BaseOAuth2 + + +class SlackOAuth2(BaseOAuth2): + """Slack OAuth authentication backend""" + + name = "slack" + AUTHORIZATION_URL = "https://slack.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://slack.com/api/oauth.access" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["identity.basic", "identity.email"] + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + EXTRA_DATA = [("id", "id"), ("name", "name"), ("real_name", "real_name")] + + def auth_extra_arguments(self): + params = super().auth_extra_arguments() or {} + if self.setting("TEAM"): + params["team"] = self.setting("TEAM") + return params + + def get_user_details(self, response): + """Return user details from Slack account""" + # Build the username with the team $username@$team_url + # Necessary to get unique names for all of slack + user = response["user"] + team = response.get("team") + name = user["name"] + email = user.get("email") + username = email and email.split("@", 1)[0] or name + fullname, first_name, last_name = self.get_user_names(name) + + if self.setting("USERNAME_WITH_TEAM", True) and team and "name" in team: + username = "{}@{}".format(username, response["team"]["name"]) + + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + response = self.get_json( + "https://slack.com/api/users.identity", + headers={"Authorization": "Bearer %s" % access_token}, + ) + if not response.get("id", None): + response["id"] = response["user"]["id"] + return response diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/soundcloud.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/soundcloud.py new file mode 100644 index 0000000000000000000000000000000000000000..a4861dbfc1b9c1cb93b148bfafdb3e2718884f4c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/soundcloud.py @@ -0,0 +1,58 @@ +""" +Soundcloud OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/soundcloud.html +""" +from urllib.parse import urlencode + +from .oauth import BaseOAuth2 + + +class SoundcloudOAuth2(BaseOAuth2): + """Soundcloud OAuth authentication backend""" + + name = "soundcloud" + AUTHORIZATION_URL = "https://soundcloud.com/connect" + ACCESS_TOKEN_URL = "https://api.soundcloud.com/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + EXTRA_DATA = [ + ("id", "id"), + ("refresh_token", "refresh_token"), + ("expires", "expires"), + ] + + def get_user_details(self, response): + """Return user details from Soundcloud account""" + fullname, first_name, last_name = self.get_user_names(response.get("full_name")) + return { + "username": response.get("username"), + "email": response.get("email") or "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.soundcloud.com/me.json", params={"oauth_token": access_token} + ) + + def auth_url(self): + """Return redirect url""" + state = None + if self.STATE_PARAMETER or self.REDIRECT_STATE: + # Store state in session for further request validation. The state + # value is passed as state parameter (as specified in OAuth2 spec), + # but also added to redirect_uri, that way we can still verify the + # request if the provider doesn't implement the state parameter. + # Reuse token if any. + name = self.name + "_state" + state = self.strategy.session_get(name) or self.state_token() + self.strategy.session_set(name, state) + + params = self.auth_params(state) + params.update(self.get_scope_argument()) + params.update(self.auth_extra_arguments()) + return self.AUTHORIZATION_URL + "?" + urlencode(params) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/spotify.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/spotify.py new file mode 100644 index 0000000000000000000000000000000000000000..a47b5deda1cee44abfb3d8b261ba3224d8888a85 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/spotify.py @@ -0,0 +1,48 @@ +""" +Spotify backend, docs at: + https://developer.spotify.com/spotify-web-api/ + https://developer.spotify.com/spotify-web-api/authorization-guide/ +""" +import base64 + +from .oauth import BaseOAuth2 + + +class SpotifyOAuth2(BaseOAuth2): + """Spotify OAuth2 authentication backend""" + + name = "spotify" + ID_KEY = "id" + AUTHORIZATION_URL = "https://accounts.spotify.com/authorize" + ACCESS_TOKEN_URL = "https://accounts.spotify.com/api/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = " " + REDIRECT_STATE = False + EXTRA_DATA = [ + ("refresh_token", "refresh_token"), + ] + + def auth_headers(self): + auth_str = "{}:{}".format(*self.get_key_and_secret()) + b64_auth_str = base64.urlsafe_b64encode(auth_str.encode()).decode() + return {"Authorization": f"Basic {b64_auth_str}"} + + def get_user_details(self, response): + """Return user details from Spotify account""" + fullname, first_name, last_name = self.get_user_names( + response.get("display_name") + ) + return { + "username": response.get("id"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.spotify.com/v1/me", + headers={"Authorization": f"Bearer {access_token}"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stackoverflow.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stackoverflow.py new file mode 100644 index 0000000000000000000000000000000000000000..85fa3fcd7aea0b44de4eec987fa0acee03c8a298 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stackoverflow.py @@ -0,0 +1,43 @@ +""" +Stackoverflow OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/stackoverflow.html +""" +from .oauth import BaseOAuth2 + + +class StackoverflowOAuth2(BaseOAuth2): + """Stackoverflow OAuth2 authentication backend""" + + name = "stackoverflow" + ID_KEY = "user_id" + AUTHORIZATION_URL = "https://stackexchange.com/oauth" + ACCESS_TOKEN_URL = "https://stackexchange.com/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + EXTRA_DATA = [("id", "id"), ("expires", "expires")] + + def get_user_details(self, response): + """Return user details from Stackoverflow account""" + fullname, first_name, last_name = self.get_user_names( + response.get("display_name") + ) + return { + "username": response.get("link").rsplit("/", 1)[-1], + "full_name": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.stackexchange.com/2.1/me", + params={ + "site": "stackoverflow", + "access_token": access_token, + "key": self.setting("API_KEY"), + }, + )["items"][0] + + def request_access_token(self, *args, **kwargs): + return self.get_querystring(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/steam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/steam.py new file mode 100644 index 0000000000000000000000000000000000000000..160b06a5b1303e468288d37402fd18789bdd7f49 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/steam.py @@ -0,0 +1,51 @@ +""" +Steam OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/steam.html +""" +from ..exceptions import AuthFailed +from .open_id import OpenIdAuth + +USER_INFO = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?" + + +class SteamOpenId(OpenIdAuth): + name = "steam" + URL = "https://steamcommunity.com/openid" + + def get_user_id(self, details, response): + """Return user unique id provided by service""" + return self._user_id(response) + + def get_user_details(self, response): + player = self.get_json( + USER_INFO, + params={ + "key": self.setting("API_KEY"), + "steamids": self._user_id(response), + }, + ) + if len(player["response"]["players"]) > 0: + player = player["response"]["players"][0] + details = { + "username": player.get("personaname"), + "email": "", + "fullname": "", + "first_name": "", + "last_name": "", + "player": player, + } + else: + details = {} + return details + + def consumer(self): + # Steam seems to support stateless mode only, ignore store + if not hasattr(self, "_consumer"): + self._consumer = self.create_consumer() + return self._consumer + + def _user_id(self, response): + user_id = response.identity_url.rsplit("/", 1)[-1] + if not user_id.isdigit(): + raise AuthFailed(self, "Missing Steam Id") + return user_id diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stocktwits.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stocktwits.py new file mode 100644 index 0000000000000000000000000000000000000000..65af8477c53adddc86be6d8e3d099500167c14da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stocktwits.py @@ -0,0 +1,43 @@ +""" +Stocktwits OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/stocktwits.html +""" +from .oauth import BaseOAuth2 + + +class StocktwitsOAuth2(BaseOAuth2): + """Stockwiths OAuth2 backend""" + + name = "stocktwits" + AUTHORIZATION_URL = "https://api.stocktwits.com/api/2/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.stocktwits.com/api/2/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + DEFAULT_SCOPE = [ + "read", + "publish_messages", + "publish_watch_lists", + "follow_users", + "follow_stocks", + ] + + def get_user_id(self, details, response): + return response["user"]["id"] + + def get_user_details(self, response): + """Return user details from Stocktwits account""" + fullname, first_name, last_name = self.get_user_names(response["user"]["name"]) + return { + "username": response["user"]["username"], + "email": "", # not supplied + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://api.stocktwits.com/api/2/account/verify.json", + params={"access_token": access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/strava.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/strava.py new file mode 100644 index 0000000000000000000000000000000000000000..2b52847fe587038ad5d67802fdbe0c70e108f33a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/strava.py @@ -0,0 +1,52 @@ +""" +Strava OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/strava.html +""" +from .oauth import BaseOAuth2 + + +class StravaOAuth(BaseOAuth2): + name = "strava" + AUTHORIZATION_URL = "https://www.strava.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.strava.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + # Strava doesn't check for parameters in redirect_uri and directly appends + # the auth parameters to it, ending with an URL like: + # http://example.com/complete/strava?redirect_state=xxx?code=xxx&state=xxx + # Check issue #259 for details. + REDIRECT_STATE = False + REVOKE_TOKEN_URL = "https://www.strava.com/oauth/deauthorize" + SCOPE_SEPARATOR = "," + EXTRA_DATA = [ + ("refresh_token", "refresh_token"), + ("expires_in", "expires"), + ] + + def get_user_id(self, details, response): + return response["athlete"]["id"] + + def get_user_details(self, response): + """Return user details from Strava account""" + username = response["athlete"].get("username", "") + fullname, first_name, last_name = self.get_user_names( + first_name=response["athlete"].get("firstname", ""), + last_name=response["athlete"].get("lastname", ""), + ) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://www.strava.com/api/v3/athlete", + params={"access_token": access_token}, + ) + + def revoke_token_params(self, token, uid): + params = super().revoke_token_params(token, uid) + params["access_token"] = token + return params diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stripe.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stripe.py new file mode 100644 index 0000000000000000000000000000000000000000..3d28cbe5f94d72ebc78fdc6f471bd288aab5e60a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/stripe.py @@ -0,0 +1,61 @@ +""" +Stripe OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/stripe.html +""" +from .oauth import BaseOAuth2 + + +class StripeOAuth2(BaseOAuth2): + """Stripe OAuth2 authentication backend""" + + name = "stripe" + ID_KEY = "stripe_user_id" + AUTHORIZATION_URL = "https://connect.stripe.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://connect.stripe.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("stripe_publishable_key", "stripe_publishable_key"), + ("access_token", "access_token"), + ("livemode", "livemode"), + ("token_type", "token_type"), + ("refresh_token", "refresh_token"), + ("stripe_user_id", "stripe_user_id"), + ] + + def user_data(self, access_token, *args, **kwargs): + """Grab user profile information from Stripe""" + return self.get_json( + "https://api.stripe.com/v1/account", + headers={ + "Authorization": f"Bearer {access_token}", + }, + ) + + def get_user_details(self, response): + """Return user details from Stripe account""" + return { + "email": response.get("email"), + "username": response.get("stripe_user_id"), + "first_name": response.get("first_name", ""), + "last_name": response.get("last_name", ""), + } + + def auth_complete_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", + "client_id": client_id, + "scope": self.SCOPE_SEPARATOR.join(self.get_scope()), + "code": self.data["code"], + } + + def auth_headers(self): + client_id, client_secret = self.get_key_and_secret() + return { + "Accept": "application/json", + "Authorization": f"Bearer {client_secret}", + } + + def refresh_token_params(self, refresh_token, *args, **kwargs): + return {"refresh_token": refresh_token, "grant_type": "refresh_token"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/surveymonkey.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/surveymonkey.py new file mode 100644 index 0000000000000000000000000000000000000000..155c53e356dae9f4a2c4c102bda5ce80d34ee724 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/surveymonkey.py @@ -0,0 +1,33 @@ +""" +SurveyMonkey OAuth2 backend, docs at: + https://developer.surveymonkey.com/api/v3/#authentication +""" +from .oauth import BaseOAuth2 + + +class SurveyMonkeyOAuth2(BaseOAuth2): + """SurveyMonkey OAuth2 authentication backend""" + + name = "surveymonkey" + AUTHORIZATION_URL = "https://api.surveymonkey.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.surveymonkey.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + USER_DATA_URL = "/v3/users/me" + STATE_PARAMETER = False + REDIRECT_STATE = False + EXTRA_DATA = [ + ("access_url", "access_url"), + ] + + def get_user_details(self, response): + """Return user details from a SurveyMonkey /users/me response""" + response["name"] = response["first_name"] + " " + response["last_name"] + return response + + def user_data(self, access_token, *args, **kwargs): + """Loads user data information from service""" + base_url = kwargs["response"]["access_url"] + return self.get_json( + base_url + self.USER_DATA_URL, + headers={"Authorization": "bearer " + access_token}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/suse.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/suse.py new file mode 100644 index 0000000000000000000000000000000000000000..ca1121e8ecf1c9e8681bbec2758868496525be19 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/suse.py @@ -0,0 +1,17 @@ +""" +Open Suse OpenId backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/suse.html +""" +from .open_id import OpenIdAuth + + +class OpenSUSEOpenId(OpenIdAuth): + name = "opensuse" + URL = "https://www.opensuse.org/openid/user/" + + def get_user_id(self, details, response): + """ + Return user unique id provided by service. For openSUSE + the nickname is original. + """ + return details["nickname"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/taobao.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/taobao.py new file mode 100644 index 0000000000000000000000000000000000000000..b4446f8200dde45fd470eba2a0df12127fb481eb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/taobao.py @@ -0,0 +1,30 @@ +from .oauth import BaseOAuth2 + + +class TAOBAOAuth(BaseOAuth2): + """Taobao OAuth authentication mechanism""" + + name = "taobao" + ID_KEY = "taobao_user_id" + ACCESS_TOKEN_METHOD = "POST" + AUTHORIZATION_URL = "https://oauth.taobao.com/authorize" + ACCESS_TOKEN_URL = "https://oauth.taobao.com/token" + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + try: + return self.get_json( + "https://eco.taobao.com/router/rest", + params={ + "method": "taobao.user.get", + "fomate": "json", + "v": "2.0", + "access_token": access_token, + }, + ) + except ValueError: + return None + + def get_user_details(self, response): + """Return user details from Taobao account""" + return {"username": response.get("taobao_user_nick")} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/telegram.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/telegram.py new file mode 100644 index 0000000000000000000000000000000000000000..b82aa2d1969dd6935d8fd3fc62de9b5df85f0e52 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/telegram.py @@ -0,0 +1,57 @@ +import hashlib +import hmac +import time + +from ..exceptions import AuthFailed, AuthMissingParameter +from ..utils import handle_http_errors +from .base import BaseAuth + + +class TelegramAuth(BaseAuth): + name = "telegram" + ID_KEY = "id" + + def verify_data(self, response): + bot_token = self.setting("BOT_TOKEN") + if bot_token is None: + raise AuthMissingParameter("telegram", "SOCIAL_AUTH_TELEGRAM_BOT_TOKEN") + + received_hash_string = response.get("hash") + auth_date = response.get("auth_date") + + if received_hash_string is None or auth_date is None: + raise AuthMissingParameter("telegram", "hash or auth_date") + + data_check_string = [f"{k}={v}" for k, v in response.items() if k != "hash"] + data_check_string = "\n".join(sorted(data_check_string)) + secret_key = hashlib.sha256(bot_token.encode()).digest() + built_hash = hmac.new( + secret_key, msg=data_check_string.encode(), digestmod=hashlib.sha256 + ).hexdigest() + current_timestamp = int(time.time()) + auth_timestamp = int(auth_date) + if current_timestamp - auth_timestamp > 86400: + raise AuthFailed("telegram", "Auth date is outdated") + if built_hash != received_hash_string: + raise AuthFailed("telegram", "Invalid hash supplied") + + def extra_data(self, user, uid, response, details=None, *args, **kwargs): + return response + + def get_user_details(self, response): + first_name = response.get("first_name", "") + last_name = response.get("last_name", "") + fullname = f"{first_name} {last_name}".strip() + return { + "username": response.get("username") or response[self.ID_KEY], + "first_name": first_name, + "last_name": last_name, + "fullname": fullname, + } + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + response = self.data + self.verify_data(response) + kwargs.update({"response": self.data, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/thisismyjam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/thisismyjam.py new file mode 100644 index 0000000000000000000000000000000000000000..fac6102159ec4ff56d8749ed9f7a1f286fb450c3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/thisismyjam.py @@ -0,0 +1,34 @@ +""" +ThisIsMyJam OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/thisismyjam.html +""" +from .oauth import BaseOAuth1 + + +class ThisIsMyJamOAuth1(BaseOAuth1): + """ThisIsMyJam OAuth1 authentication backend""" + + name = "thisismyjam" + REQUEST_TOKEN_URL = "http://www.thisismyjam.com/oauth/request_token" + AUTHORIZATION_URL = "http://www.thisismyjam.com/oauth/authorize" + ACCESS_TOKEN_URL = "http://www.thisismyjam.com/oauth/access_token" + REDIRECT_URI_PARAMETER_NAME = "oauth_callback" + + def get_user_details(self, response): + """Return user details from ThisIsMyJam account""" + info = response.get("person") + fullname, first_name, last_name = self.get_user_names(info.get("fullname")) + return { + "username": info.get("name"), + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "http://api.thisismyjam.com/1/verify.json", + auth=self.oauth_auth(access_token), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/trello.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/trello.py new file mode 100644 index 0000000000000000000000000000000000000000..70a1d793487421b99d0ec2db3a4105f40c4747b0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/trello.py @@ -0,0 +1,48 @@ +""" +Trello OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/trello.html +""" +from .oauth import BaseOAuth1 + + +class TrelloOAuth(BaseOAuth1): + + """Trello OAuth authentication backend""" + + name = "trello" + ID_KEY = "username" + AUTHORIZATION_URL = "https://trello.com/1/OAuthAuthorizeToken" + REQUEST_TOKEN_URL = "https://trello.com/1/OAuthGetRequestToken" + ACCESS_TOKEN_URL = "https://trello.com/1/OAuthGetAccessToken" + + EXTRA_DATA = [ + ("username", "username"), + ("email", "email"), + ("fullName", "fullName"), + ] + + def get_user_details(self, response): + """Return user details from Trello account""" + fullname, first_name, last_name = self.get_user_names(response.get("fullName")) + return { + "username": response.get("username"), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token): + """Return user data provided""" + url = "https://trello.com/1/members/me" + try: + return self.get_json(url, auth=self.oauth_auth(access_token)) + except ValueError: + return None + + def auth_extra_arguments(self): + return { + "name": self.setting("APP_NAME", ""), + # trello default expiration is '30days' + "expiration": self.setting("EXPIRATION", "never"), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tripit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tripit.py new file mode 100644 index 0000000000000000000000000000000000000000..f6f1ea78662ade505b76175c4e063a9cf23fca16 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tripit.py @@ -0,0 +1,49 @@ +""" +Tripit OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/tripit.html +""" +from xml.dom import minidom + +from .oauth import BaseOAuth1 + + +class TripItOAuth(BaseOAuth1): + """TripIt OAuth authentication backend""" + + name = "tripit" + AUTHORIZATION_URL = "https://www.tripit.com/oauth/authorize" + REQUEST_TOKEN_URL = "https://api.tripit.com/oauth/request_token" + ACCESS_TOKEN_URL = "https://api.tripit.com/oauth/access_token" + EXTRA_DATA = [("screen_name", "screen_name")] + + def get_user_details(self, response): + """Return user details from TripIt account""" + fullname, first_name, last_name = self.get_user_names(response["name"]) + return { + "username": response["screen_name"], + "email": response["email"], + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + dom = minidom.parseString( + self.oauth_request( + access_token, "https://api.tripit.com/v1/get/profile" + ).content + ) + return { + "id": dom.getElementsByTagName("Profile")[0].getAttribute("ref"), + "name": dom.getElementsByTagName("public_display_name")[0] + .childNodes[0] + .data, + "screen_name": dom.getElementsByTagName("screen_name")[0] + .childNodes[0] + .data, + "email": dom.getElementsByTagName("is_primary")[0] + .parentNode.getElementsByTagName("address")[0] + .childNodes[0] + .data, + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tumblr.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tumblr.py new file mode 100644 index 0000000000000000000000000000000000000000..516ae8c5e4e6f3842a5dde9e6d6546253be823db --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/tumblr.py @@ -0,0 +1,32 @@ +""" +Tumblr OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/tumblr.html +""" +from ..utils import first +from .oauth import BaseOAuth1 + + +class TumblrOAuth(BaseOAuth1): + name = "tumblr" + ID_KEY = "name" + AUTHORIZATION_URL = "http://www.tumblr.com/oauth/authorize" + REQUEST_TOKEN_URL = "http://www.tumblr.com/oauth/request_token" + REQUEST_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "http://www.tumblr.com/oauth/access_token" + + def get_user_id(self, details, response): + return response["response"]["user"][self.ID_KEY] + + def get_user_details(self, response): + # http://www.tumblr.com/docs/en/api/v2#user-methods + user_info = response["response"]["user"] + data = {"username": user_info["name"]} + blog = first(lambda blog: blog["primary"], user_info["blogs"]) + if blog: + data["fullname"] = blog["title"] + return data + + def user_data(self, access_token): + return self.get_json( + "http://api.tumblr.com/v2/user/info", auth=self.oauth_auth(access_token) + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twilio.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twilio.py new file mode 100644 index 0000000000000000000000000000000000000000..90cb1e960434ea4e3f85e630d0122deda642aff6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twilio.py @@ -0,0 +1,41 @@ +""" +Twilio auth backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/twilio.html +""" +from re import sub +from urllib.parse import urlencode + +from .base import BaseAuth + + +class TwilioAuth(BaseAuth): + name = "twilio" + ID_KEY = "AccountSid" + + def get_user_details(self, response): + """Return twilio details, Twilio only provides AccountSID as + parameters.""" + # /complete/twilio/?AccountSid=ACc65ea16c9ebd4d4684edf814995b27e + return { + "username": response["AccountSid"], + "email": "", + "fullname": "", + "first_name": "", + "last_name": "", + } + + def auth_url(self): + """Return authorization redirect url.""" + key, secret = self.get_key_and_secret() + callback = self.strategy.absolute_uri(self.redirect_uri) + callback = sub(r"^https", "http", callback) + query = urlencode({"cb": callback}) + return f"https://www.twilio.com/authorize/{key}?{query}" + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + account_sid = self.data.get("AccountSid") + if not account_sid: + raise ValueError("No AccountSid returned") + kwargs.update({"response": self.data, "backend": self}) + return self.strategy.authenticate(*args, **kwargs) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitch.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitch.py new file mode 100644 index 0000000000000000000000000000000000000000..38dd29b66edfa65f239cf568692bb39647d9323b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitch.py @@ -0,0 +1,72 @@ +""" +Twitch OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/twitch.html +""" +from .oauth import BaseOAuth2 +from .open_id_connect import OpenIdConnectAuth + + +class TwitchOpenIdConnect(OpenIdConnectAuth): + """Twitch OpenID Connect authentication backend""" + + name = "twitch" + USERNAME_KEY = "preferred_username" + OIDC_ENDPOINT = "https://id.twitch.tv/oauth2" + DEFAULT_SCOPE = ["openid", "user:read:email"] + TWITCH_CLAIMS = ( + '{"id_token":{"email": null,"email_verified":null,"preferred_username":null}}' + ) + + def auth_params(self, state=None): + params = super().auth_params(state) + # Twitch uses a non-compliant OpenID implementation where the claims must be passed as a param + params["claims"] = self.TWITCH_CLAIMS + return params + + def get_user_details(self, response): + return { + "username": self.id_token["preferred_username"], + "email": self.id_token["email"], + # Twitch does not provide this information + "fullname": "", + "first_name": "", + "last_name": "", + } + + +class TwitchOAuth2(BaseOAuth2): + """Twitch OAuth authentication backend""" + + name = "twitch" + ID_KEY = "_id" + AUTHORIZATION_URL = "https://id.twitch.tv/oauth2/authorize" + ACCESS_TOKEN_URL = "https://id.twitch.tv/oauth2/token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["user:read:email"] + REDIRECT_STATE = False + + def get_user_id(self, details, response): + """ + Use twitch user id as unique id + """ + return response.get("id") + + def get_user_details(self, response): + return { + "username": response.get("login"), + "email": response.get("email"), + "first_name": "", + "last_name": "", + } + + def user_data(self, access_token, *args, **kwargs): + client_id, _ = self.get_key_and_secret() + auth_headers = { + "Authorization": "Bearer %s" % access_token, + "Client-Id": client_id, + } + url = "https://api.twitch.tv/helix/users" + + data = self.get_json(url, headers=auth_headers) + + return data["data"][0] if data.get("data") else {} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitter.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitter.py new file mode 100644 index 0000000000000000000000000000000000000000..0bb12f5a6a51489e6541683ee9f4d53f2fbc7ca0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/twitter.py @@ -0,0 +1,44 @@ +""" +Twitter OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/twitter.html +""" +from ..exceptions import AuthCanceled +from .oauth import BaseOAuth1 + + +class TwitterOAuth(BaseOAuth1): + """Twitter OAuth authentication backend""" + + name = "twitter" + EXTRA_DATA = [("id", "id")] + REQUEST_TOKEN_METHOD = "POST" + ACCESS_TOKEN_METHOD = "POST" + AUTHORIZATION_URL = "https://api.twitter.com/oauth/authenticate" + REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token" + ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token" + REDIRECT_STATE = True + + def process_error(self, data): + if "denied" in data: + raise AuthCanceled(self) + else: + super().process_error(data) + + def get_user_details(self, response): + """Return user details from Twitter account""" + fullname, first_name, last_name = self.get_user_names(response["name"]) + return { + "username": response["screen_name"], + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "https://api.twitter.com/1.1/account/verify_credentials.json", + params={"include_email": "true"}, + auth=self.oauth_auth(access_token), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/uber.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/uber.py new file mode 100644 index 0000000000000000000000000000000000000000..e7ca8bb4119597343b42e362f20c67e4373b3d38 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/uber.py @@ -0,0 +1,43 @@ +""" +Uber OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/uber.html +""" +from .oauth import BaseOAuth2 + + +class UberOAuth2(BaseOAuth2): + name = "uber" + ID_KEY = "uuid" + SCOPE_SEPARATOR = " " + AUTHORIZATION_URL = "https://login.uber.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://login.uber.com/oauth/token" + ACCESS_TOKEN_METHOD = "POST" + + def auth_complete_credentials(self): + return self.get_key_and_secret() + + def get_user_details(self, response): + """Return user details from Uber account""" + email = response.get("email", "") + fullname, first_name, last_name = self.get_user_names( + "", response.get("first_name", ""), response.get("last_name", "") + ) + return { + "username": email, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + response = kwargs.pop("response") + return self.get_json( + "https://api.uber.com/v1/me", + headers={ + "Authorization": "{} {}".format( + response.get("token_type"), access_token + ) + }, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ubuntu.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ubuntu.py new file mode 100644 index 0000000000000000000000000000000000000000..8d4c2ed835a657d02eb4a8363cd60e8dfdc0f3c2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/ubuntu.py @@ -0,0 +1,16 @@ +""" +Ubuntu One OpenId backend +""" +from .open_id import OpenIdAuth + + +class UbuntuOpenId(OpenIdAuth): + name = "ubuntu" + URL = "https://login.ubuntu.com" + + def get_user_id(self, details, response): + """ + Return user unique id provided by service. For Ubuntu One + the nickname should be original. + """ + return details["nickname"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/udata.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/udata.py new file mode 100644 index 0000000000000000000000000000000000000000..c2b04320654ebf1ddbd66ecda3ced970131f4b49 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/udata.py @@ -0,0 +1,37 @@ +""" +Udata related backends. + +Docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/udata.html +""" +from .oauth import BaseOAuth2 + + +class UdataBaseOAuth2(BaseOAuth2): + """Udata base OAuth authentication backend.""" + + SCOPE_SEPARATOR = "," + REDIRECT_STATE = False + DEFAULT_SCOPE = ["default"] + ACCESS_TOKEN_METHOD = "POST" + + def get_user_details(self, response): + """Return user details from Udata account.""" + return { + "username": response.get("first_name"), + "email": response.get("email") or "", + "first_name": response.get("first_name"), + } + + def user_data(self, access_token, *args, **kwargs): + """Load user data from service.""" + return self.get_json(self.USER_DATA_URL, params={"access_token": access_token}) + + +class DatagouvfrOAuth2(UdataBaseOAuth2): + """Datagouvfr OAuth authentication backend.""" + + name = "datagouv" + ACCESS_TOKEN_URL = "https://www.data.gouv.fr/oauth/token" + AUTHORIZATION_URL = "https://www.data.gouv.fr/oauth/authorize" + USER_DATA_URL = "https://www.data.gouv.fr/api/1/me/" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/universe.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/universe.py new file mode 100644 index 0000000000000000000000000000000000000000..96d38e0a1e5c4070de7b510c8b42412ad8db1bcd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/universe.py @@ -0,0 +1,36 @@ +from .oauth import BaseOAuth2 + + +class UniverseOAuth2(BaseOAuth2): + """Universe Ticketing OAuth2 authentication backend""" + + name = "universe" + AUTHORIZATION_URL = "https://www.universe.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.universe.com/oauth/token" + BASE_API_URL = "https://www.universe.com/api" + USER_INFO_URL = BASE_API_URL + "/v2/current_user" + ACCESS_TOKEN_METHOD = "POST" + STATE_PARAMETER = True + REDIRECT_STATE = True + EXTRA_DATA = [ + ("id", "id"), + ("slug", "slug"), + ("created_at", "created_at"), + ("updated_at", "updated_at"), + ] + + def get_user_id(self, details, response): + return response["current_user"][self.ID_KEY] + + def get_user_details(self, response): + """Return user details from a Universe account""" + # Start with the user data as it was returned + user_details = response["current_user"] + user_details["username"] = user_details["email"] + return user_details + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + self.USER_INFO_URL, headers={"Authorization": f"Bearer {access_token}"} + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/untappd.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/untappd.py new file mode 100644 index 0000000000000000000000000000000000000000..924a9d89ef7ee287d1559a28533bf6c1017af4dd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/untappd.py @@ -0,0 +1,116 @@ +import requests + +from ..exceptions import AuthFailed +from ..utils import handle_http_errors +from .oauth import BaseOAuth2 + + +class UntappdOAuth2(BaseOAuth2): + """Untappd OAuth2 authentication backend""" + + name = "untappd" + AUTHORIZATION_URL = "https://untappd.com/oauth/authenticate/" + ACCESS_TOKEN_URL = "https://untappd.com/oauth/authorize/" + BASE_API_URL = "https://api.untappd.com" + USER_INFO_URL = BASE_API_URL + "/v4/user/info/" + ACCESS_TOKEN_METHOD = "GET" + STATE_PARAMETER = False + REDIRECT_STATE = False + SEND_USER_AGENT = True + EXTRA_DATA = [ + ("id", "id"), + ("bio", "bio"), + ("date_joined", "date_joined"), + ("location", "location"), + ("url", "url"), + ("user_avatar", "user_avatar"), + ("user_avatar_hd", "user_avatar_hd"), + ("user_cover_photo", "user_cover_photo"), + ] + + def auth_params(self, state=None): + client_id, client_secret = self.get_key_and_secret() + params = { + "client_id": client_id, + "redirect_url": self.get_redirect_uri(), + "response_type": self.RESPONSE_TYPE, + } + return params + + def process_error(self, data): + """ + All errors from Untappd are contained in the 'meta' key of the + response. + """ + response_code = data.get("meta", {}).get("http_code") + if response_code is not None and response_code != requests.codes.ok: + raise AuthFailed(self, data["meta"]["error_detail"]) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + client_id, client_secret = self.get_key_and_secret() + code = self.data.get("code") + + self.process_error(self.data) + + # Untapped sends the access token request with URL parameters, + # not a body + response = self.request_access_token( + self.access_token_url(), + method=self.ACCESS_TOKEN_METHOD, + params={ + "response_type": "code", + "code": code, + "client_id": client_id, + "client_secret": client_secret, + "redirect_url": self.get_redirect_uri(), + }, + ) + + self.process_error(response) + + # Both the access_token and the rest of the response are + # buried in the 'response' key + return self.do_auth( + response["response"]["access_token"], + response=response["response"], + *args, + **kwargs + ) + + def get_user_details(self, response): + """Return user details from an Untappd account""" + # Start with the user data as it was returned + user_data = response["user"] + + # Make a few updates to match expected key names + user_data.update( + { + "username": user_data.get("user_name"), + "email": user_data.get("settings", {}).get("email_address", ""), + "first_name": user_data.get("first_name"), + "last_name": user_data.get("last_name"), + "fullname": " ".join( + [user_data.get("first_name"), user_data.get("last_name")] + ), + } + ) + return user_data + + def get_user_id(self, details, response): + """ + Return a unique ID for the current user, by default from + server response. + """ + return response["user"].get(self.ID_KEY) + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + response = self.get_json( + self.USER_INFO_URL, params={"access_token": access_token, "compact": "true"} + ) + self.process_error(response) + + # The response data is buried in the 'response' key + return response["response"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/upwork.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/upwork.py new file mode 100644 index 0000000000000000000000000000000000000000..eb9815ac418883999e60c5be63f1d1eb92148474 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/upwork.py @@ -0,0 +1,40 @@ +""" +Upwork OAuth1 backend +""" +from .oauth import BaseOAuth1 + + +class UpworkOAuth(BaseOAuth1): + """Upwork OAuth authentication backend""" + + name = "upwork" + ID_KEY = "id" + AUTHORIZATION_URL = "https://www.upwork.com/services/api/auth" + REQUEST_TOKEN_URL = "https://www.upwork.com/api/auth/v1/oauth/token/request" + REQUEST_TOKEN_METHOD = "POST" + ACCESS_TOKEN_URL = "https://www.upwork.com/api/auth/v1/oauth/token/access" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_URI_PARAMETER_NAME = "oauth_callback" + + def get_user_details(self, response): + """Return user details from Upwork account""" + info = response.get("info", {}) + auth_user = response.get("auth_user", {}) + first_name = auth_user.get("first_name") + last_name = auth_user.get("last_name") + fullname = f"{first_name} {last_name}" + profile_url = info.get("profile_url", "") + username = profile_url.rsplit("/")[-1].replace("~", "") + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "https://www.upwork.com/api/auth/v1/info.json", + auth=self.oauth_auth(access_token), + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/username.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/username.py new file mode 100644 index 0000000000000000000000000000000000000000..be0be109c46da55afdc85bc7b46b584cfafdf89f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/username.py @@ -0,0 +1,11 @@ +""" +Legacy Username backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/username.html +""" +from .legacy import LegacyAuth + + +class UsernameAuth(LegacyAuth): + name = "username" + ID_KEY = "username" + EXTRA_DATA = ["username"] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..2d46a6c75fb35e3d28b726fe15780eb34a1257d4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/utils.py @@ -0,0 +1,78 @@ +from collections import OrderedDict + +from ..exceptions import MissingBackend +from ..utils import module_member, user_is_authenticated +from .base import BaseAuth + +# Cache for discovered backends. +BACKENDSCACHE = OrderedDict() + + +def load_backends(backends, force_load=False): + """ + Load backends defined on SOCIAL_AUTH_AUTHENTICATION_BACKENDS, backends will + be imported and cached on BACKENDSCACHE. The key in that dict will be the + backend name, and the value is the backend class. + + Only subclasses of BaseAuth (and sub-classes) are considered backends. + + Previously there was a BACKENDS attribute expected on backends modules, + this is not needed anymore since it's enough with the + AUTHENTICATION_BACKENDS setting. BACKENDS was used because backends used to + be split on two classes the authentication backend and another class that + dealt with the auth mechanism with the provider, those classes are joined + now. + + A force_load boolean argument is also provided so that get_backend + below can retry a requested backend that may not yet be discovered. + """ + global BACKENDSCACHE + if force_load: + BACKENDSCACHE = OrderedDict() + if not BACKENDSCACHE: + for auth_backend in backends: + backend = module_member(auth_backend) + if issubclass(backend, BaseAuth): + BACKENDSCACHE[backend.name] = backend + return BACKENDSCACHE + + +def get_backend(backends, name): + """Returns a backend by name. Backends are stored in the BACKENDSCACHE + cache dict. If not found, each of the modules referenced in + AUTHENTICATION_BACKENDS is imported and checked for a BACKENDS + definition. If the named backend is found in the module's BACKENDS + definition, it's then stored in the cache for future access. + """ + try: + # Cached backend which has previously been discovered + return BACKENDSCACHE[name] + except KeyError: + # Reload BACKENDS to ensure a missing backend hasn't been missed + load_backends(backends, force_load=True) + try: + return BACKENDSCACHE[name] + except KeyError: + raise MissingBackend(name) + + +def user_backends_data(user, backends, storage): + """ + Will return backends data for given user, the return value will have the + following keys: + associated: UserSocialAuth model instances for currently associated + accounts + not_associated: Not associated (yet) backend names + backends: All backend names. + + If user is not authenticated, then 'associated' list is empty, and there's + no difference between 'not_associated' and 'backends'. + """ + available = list(load_backends(backends).keys()) + values = {"associated": [], "not_associated": available, "backends": available} + if user_is_authenticated(user): + associated = storage.user.get_social_auth_for_user(user) + not_associated = list(set(available) - {assoc.provider for assoc in associated}) + values["associated"] = associated + values["not_associated"] = not_associated + return values diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vault.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vault.py new file mode 100644 index 0000000000000000000000000000000000000000..4064072deca1e43ab5f3986138fd382b127f5f66 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vault.py @@ -0,0 +1,15 @@ +""" +Backend for Hashicorp Vault OIDC Identity Provider in Vault 1.9+ +https://www.vaultproject.io/docs/secrets/identity/oidc-provider +""" +from social_core.backends.open_id_connect import OpenIdConnectAuth + + +class VaultOpenIdConnect(OpenIdConnectAuth): + """ + Vault OIDC authentication backend + + This is an alias for the generic OIDC backend + """ + + name = "vault" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vend.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vend.py new file mode 100644 index 0000000000000000000000000000000000000000..01646475e89922268a966f7c83b3b7763a2ea873 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vend.py @@ -0,0 +1,37 @@ +""" +Vend OAuth2 backend: +""" +from .oauth import BaseOAuth2 + + +class VendOAuth2(BaseOAuth2): + name = "vend" + AUTHORIZATION_URL = "https://secure.vendhq.com/connect" + ACCESS_TOKEN_URL = "https://{0}.vendhq.com/api/1.0/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("refresh_token", "refresh_token"), + ("domain_prefix", "domain_prefix"), + ] + + def access_token_url(self): + return self.ACCESS_TOKEN_URL.format(self.data["domain_prefix"]) + + def get_user_details(self, response): + email = response["email"] + username = response.get("username") or email.split("@", 1)[0] + return { + "username": username, + "email": email, + "fullname": "", + "first_name": "", + "last_name": "", + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + prefix = kwargs["response"]["domain_prefix"] + url = f"https://{prefix}.vendhq.com/api/users" + data = self.get_json(url, headers={"Authorization": f"Bearer {access_token}"}) + return data["users"][0] if data.get("users") else {} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vimeo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vimeo.py new file mode 100644 index 0000000000000000000000000000000000000000..1bd05e939c67ffe39e674777debee8d4d6ca2cf1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vimeo.py @@ -0,0 +1,83 @@ +from .oauth import BaseOAuth1, BaseOAuth2 + + +class VimeoOAuth1(BaseOAuth1): + """Vimeo OAuth authentication backend""" + + name = "vimeo" + AUTHORIZATION_URL = "https://vimeo.com/oauth/authorize" + REQUEST_TOKEN_URL = "https://vimeo.com/oauth/request_token" + ACCESS_TOKEN_URL = "https://vimeo.com/oauth/access_token" + + def get_user_id(self, details, response): + return response.get("person", {}).get("id") + + def get_user_details(self, response): + """Return user details from Twitter account""" + person = response.get("person", {}) + fullname, first_name, last_name = self.get_user_names( + person.get("display_name", "") + ) + return { + "username": person.get("username", ""), + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "https://vimeo.com/api/rest/v2", + params={"format": "json", "method": "vimeo.people.getInfo"}, + auth=self.oauth_auth(access_token), + ) + + +class VimeoOAuth2(BaseOAuth2): + """Vimeo OAuth2 authentication backend""" + + name = "vimeo-oauth2" + AUTHORIZATION_URL = "https://api.vimeo.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://api.vimeo.com/oauth/access_token" + REFRESH_TOKEN_URL = "https://api.vimeo.com/oauth/request_token" + ACCESS_TOKEN_METHOD = "POST" + SCOPE_SEPARATOR = "," + API_ACCEPT_HEADER = {"Accept": "application/vnd.vimeo.*+json;version=3.0"} + + def get_redirect_uri(self, state=None): + """ + Build redirect with redirect_state parameter. + + @Vimeo API 3 requires exact redirect uri without additional + additional state parameter included + """ + return self.redirect_uri + + def get_user_id(self, details, response): + """Return user id""" + try: + user_id = response.get("user", {})["uri"].split("/")[-1] + except KeyError: + user_id = None + return user_id + + def get_user_details(self, response): + """Return user details from account""" + user = response.get("user", {}) + fullname, first_name, last_name = self.get_user_names(user.get("name", "")) + return { + "username": fullname, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + return self.get_json( + "https://api.vimeo.com/me", + params={"access_token": access_token}, + headers=VimeoOAuth2.API_ACCEPT_HEADER, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vk.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vk.py new file mode 100644 index 0000000000000000000000000000000000000000..88fe53ad777d3ff7a48ce9f96401a00d1c783d61 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/vk.py @@ -0,0 +1,206 @@ +""" +VK.com OpenAPI, OAuth2 and Iframe application OAuth2 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/vk.html +""" +import json +from hashlib import md5 +from time import time + +from ..exceptions import AuthException, AuthTokenRevoked +from ..utils import parse_qs +from .base import BaseAuth +from .oauth import BaseOAuth2 + + +class VKontakteOpenAPI(BaseAuth): + """VK.COM OpenAPI authentication backend""" + + name = "vk-openapi" + ID_KEY = "id" + + def get_user_details(self, response): + """Return user details from VK.com request""" + nickname = response.get("nickname") or "" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("first_name", [""])[0], + last_name=response.get("last_name", [""])[0], + ) + return { + "username": response["id"] if len(nickname) == 0 else nickname, + "email": "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.data + + def auth_html(self): + """Returns local VK authentication page, not necessary for + VK to authenticate. + """ + ctx = { + "VK_APP_ID": self.setting("APP_ID"), + "VK_COMPLETE_URL": self.redirect_uri, + } + local_html = self.setting("LOCAL_HTML", "vkontakte.html") + return self.strategy.render_html(tpl=local_html, context=ctx) + + def auth_complete(self, *args, **kwargs): + """Performs check of authentication in VKontakte, returns User if + succeeded""" + session_value = self.strategy.session_get("vk_app_" + self.setting("APP_ID")) + if "id" not in self.data or not session_value: + raise ValueError("VK.com authentication is not completed") + + mapping = parse_qs(session_value) + check_str = "".join( + item + "=" + mapping[item] for item in ["expire", "mid", "secret", "sid"] + ) + + key, secret = self.get_key_and_secret() + hash = md5((check_str + secret).encode("utf-8")).hexdigest() + if hash != mapping["sig"] or int(mapping["expire"]) < time(): + raise ValueError("VK.com authentication failed: Invalid Hash") + + kwargs.update({"backend": self, "response": self.user_data(mapping["mid"])}) + return self.strategy.authenticate(*args, **kwargs) + + def uses_redirect(self): + """VK.com does not require visiting server url in order + to do authentication, so auth_xxx methods are not needed to be called. + Their current implementation is just an example""" + return False + + +class VKOAuth2(BaseOAuth2): + """VKOAuth2 authentication backend""" + + name = "vk-oauth2" + ID_KEY = "id" + AUTHORIZATION_URL = "https://oauth.vk.com/authorize" + ACCESS_TOKEN_URL = "https://oauth.vk.com/access_token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [("id", "id"), ("expires_in", "expires")] + + def get_user_details(self, response): + """Return user details from VK.com account""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("first_name"), last_name=response.get("last_name") + ) + return { + "username": response.get("screen_name"), + "email": response.get("email", ""), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + request_data = [ + "first_name", + "last_name", + "screen_name", + "nickname", + "photo", + ] + self.setting("EXTRA_DATA", []) + + fields = ",".join(set(request_data)) + data = vk_api( + self, + "users.get", + { + "access_token": access_token, + "fields": fields, + }, + ) + + if data and data.get("error"): + error = data["error"] + msg = error.get("error_msg", "Unknown error") + if error.get("error_code") == 5: + raise AuthTokenRevoked(self, msg) + else: + raise AuthException(self, msg) + + if data: + data = data.get("response")[0] + data["user_photo"] = data.get("photo") # Backward compatibility + return data or {} + + +class VKAppOAuth2(VKOAuth2): + """VK.com Application Authentication support""" + + name = "vk-app" + + def auth_complete(self, *args, **kwargs): + required_params = ("is_app_user", "viewer_id", "access_token", "api_id") + if not all(param in self.data for param in required_params): + return None + + auth_key = self.data.get("auth_key") + + # Verify signature, if present + key, secret = self.get_key_and_secret() + if auth_key: + check_key = md5( + "_".join([key, self.data.get("viewer_id"), secret]).encode("utf-8") + ).hexdigest() + if check_key != auth_key: + raise ValueError("VK.com authentication failed: invalid " "auth key") + + user_check = self.setting("USERMODE") + user_id = self.data.get("viewer_id") + if user_check is not None: + user_check = int(user_check) + if user_check == 1: + is_user = self.data.get("is_app_user") + elif user_check == 2: + is_user = vk_api(self, "isAppUser", {"user_id": user_id}).get( + "response", 0 + ) + if not int(is_user): + return None + + auth_data = { + "auth": self, + "backend": self, + "request": self.strategy.request_data(), + "response": { + self.ID_KEY: user_id, + }, + } + auth_data["response"].update( + json.loads(auth_data["request"]["api_result"])["response"][0] + ) + return self.strategy.authenticate(*args, **auth_data) + + +def vk_api(backend, method, data): + """ + Calls VK.com OpenAPI method, check: + https://vk.com/apiclub + http://goo.gl/yLcaa + """ + # We need to perform server-side call if no access_token + data["v"] = backend.setting("API_VERSION", "5.131") + if "access_token" not in data: + key, secret = backend.get_key_and_secret() + if "api_id" not in data: + data["api_id"] = key + + data["method"] = method + data["format"] = "json" + url = "https://api.vk.com/api.php" + param_list = sorted(list(item + "=" + data[item] for item in data)) + data["sig"] = md5(("".join(param_list) + secret).encode("utf-8")).hexdigest() + else: + url = "https://api.vk.com/method/" + method + + try: + return backend.get_json(url, params=data) + except (TypeError, KeyError, OSError, ValueError, IndexError): + return None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weibo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weibo.py new file mode 100644 index 0000000000000000000000000000000000000000..b69125d5ed2afa5b790b7f2210ef2393bf92aa65 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weibo.py @@ -0,0 +1,63 @@ +# author:hepochen@gmail.com https://github.com/hepochen +""" +Weibo OAuth2 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/weibo.html +""" +from .oauth import BaseOAuth2 + + +class WeiboOAuth2(BaseOAuth2): + """Weibo (of sina) OAuth authentication backend""" + + name = "weibo" + ID_KEY = "uid" + AUTHORIZATION_URL = "https://api.weibo.com/oauth2/authorize" + REQUEST_TOKEN_URL = "https://api.weibo.com/oauth2/request_token" + ACCESS_TOKEN_URL = "https://api.weibo.com/oauth2/access_token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [ + ("id", "id"), + ("name", "username"), + ("profile_image_url", "profile_image_url"), + ("gender", "gender"), + ] + + def get_user_details(self, response): + """Return user details from Weibo. API URL is: + https://api.weibo.com/2/users/show.json/?uid=<UID>&access_token=<TOKEN> + """ + if self.setting("DOMAIN_AS_USERNAME"): + username = response.get("domain", "") + else: + username = response.get("name", "") + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("screen_name", "") + ) + return { + "username": username, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def get_uid(self, access_token): + """Return uid by access_token""" + data = self.get_json( + "https://api.weibo.com/oauth2/get_token_info", + method="POST", + params={"access_token": access_token}, + ) + return data["uid"] + + def user_data(self, access_token, response=None, *args, **kwargs): + """Return user data""" + # If user id was not retrieved in the response, then get it directly + # from weibo get_token_info endpoint + uid = response and response.get("uid") or self.get_uid(access_token) + user_data = self.get_json( + "https://api.weibo.com/2/users/show.json", + params={"access_token": access_token, "uid": uid}, + ) + user_data["uid"] = uid + return user_data diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weixin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weixin.py new file mode 100644 index 0000000000000000000000000000000000000000..2aec528e2c4e2f346a803f16ba0c80a7da15d29a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/weixin.py @@ -0,0 +1,178 @@ +# author:duoduo3369@gmail.com https://github.com/duoduo369 +""" +Weixin OAuth2 backend +""" +from urllib.parse import urlencode + +from requests import HTTPError + +from ..exceptions import AuthCanceled, AuthUnknownError +from .oauth import BaseOAuth2 + + +class WeixinOAuth2(BaseOAuth2): + """Weixin OAuth authentication backend""" + + name = "weixin" + ID_KEY = "openid" + AUTHORIZATION_URL = "https://open.weixin.qq.com/connect/qrconnect" + ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" + ACCESS_TOKEN_METHOD = "POST" + DEFAULT_SCOPE = ["snsapi_login"] + REDIRECT_STATE = False + EXTRA_DATA = [ + ("nickname", "username"), + ("headimgurl", "profile_image_url"), + ] + + def get_user_details(self, response): + """Return user details from Weixin. API URL is: + https://api.weixin.qq.com/sns/userinfo + """ + if self.setting("DOMAIN_AS_USERNAME"): + username = response.get("domain", "") + else: + username = response.get("nickname", "") + return { + "username": username, + "profile_image_url": response.get("headimgurl", ""), + } + + def user_data(self, access_token, *args, **kwargs): + data = self.get_json( + "https://api.weixin.qq.com/sns/userinfo", + params={ + "access_token": access_token, + "openid": kwargs["response"]["openid"], + }, + ) + nickname = data.get("nickname") + if nickname: + # weixin api has some encode bug, here need handle + data["nickname"] = nickname.encode("raw_unicode_escape").decode("utf-8") + return data + + def auth_params(self, state=None): + appid, secret = self.get_key_and_secret() + params = {"appid": appid, "redirect_uri": self.get_redirect_uri(state)} + if self.STATE_PARAMETER and state: + params["state"] = state + if self.RESPONSE_TYPE: + params["response_type"] = self.RESPONSE_TYPE + return params + + def auth_complete_params(self, state=None): + appid, secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "appid": appid, + "secret": secret, + "redirect_uri": self.get_redirect_uri(state), + } + + def refresh_token_params(self, token, *args, **kwargs): + appid, secret = self.get_key_and_secret() + return { + "refresh_token": token, + "grant_type": "refresh_token", + "appid": appid, + "secret": secret, + } + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + try: + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + except HTTPError as err: + if err.response.status_code == 400: + raise AuthCanceled(self, response=err.response) + else: + raise + except KeyError: + raise AuthUnknownError(self) + if "errcode" in response: + raise AuthCanceled(self) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + +class WeixinOAuth2APP(WeixinOAuth2): + """ + Weixin OAuth authentication backend + + Can't use in web, only in weixin app + """ + + name = "weixinapp" + ID_KEY = "openid" + AUTHORIZATION_URL = "https://open.weixin.qq.com/connect/oauth2/authorize" + ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def auth_url(self): + if self.STATE_PARAMETER or self.REDIRECT_STATE: + # Store state in session for further request validation. The state + # value is passed as state parameter (as specified in OAuth2 spec), + # but also added to redirect, that way we can still verify the + # request if the provider doesn't implement the state parameter. + # Reuse token if any. + name = self.name + "_state" + state = self.strategy.session_get(name) + if state is None: + state = self.state_token() + self.strategy.session_set(name, state) + else: + state = None + + params = self.auth_params(state) + params.update(self.get_scope_argument()) + params.update(self.auth_extra_arguments()) + params = urlencode(sorted(params.items())) + return "{}#wechat_redirect".format(self.AUTHORIZATION_URL + "?" + params) + + def auth_complete_params(self, state=None): + appid, secret = self.get_key_and_secret() + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "appid": appid, + "secret": secret, + } + + def validate_state(self): + return None + + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + try: + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + except HTTPError as err: + if err.response.status_code == 400: + raise AuthCanceled(self) + else: + raise + except KeyError: + raise AuthUnknownError(self) + + if "errcode" in response: + raise AuthCanceled(self) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/withings.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/withings.py new file mode 100644 index 0000000000000000000000000000000000000000..69c05455d41a4a9f27c5b8f05d12f02280f06a84 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/withings.py @@ -0,0 +1,13 @@ +from .oauth import BaseOAuth1 + + +class WithingsOAuth(BaseOAuth1): + name = "withings" + AUTHORIZATION_URL = "https://developer.health.nokia.com/account/authorize" + REQUEST_TOKEN_URL = "https://developer.health.nokia.com/account/request_token" + ACCESS_TOKEN_URL = "https://developer.health.nokia.com/account/access_token" + ID_KEY = "userid" + + def get_user_details(self, response): + """Return user details from Withings account""" + return {"userid": response["access_token"]["userid"], "email": ""} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/wunderlist.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/wunderlist.py new file mode 100644 index 0000000000000000000000000000000000000000..f0d8d9e49df9f898d3d8d7ba05e5b44301c0c81b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/wunderlist.py @@ -0,0 +1,27 @@ +from .oauth import BaseOAuth2 + + +class WunderlistOAuth2(BaseOAuth2): + """Wunderlist OAuth2 authentication backend""" + + name = "wunderlist" + AUTHORIZATION_URL = "https://www.wunderlist.com/oauth/authorize" + ACCESS_TOKEN_URL = "https://www.wunderlist.com/oauth/access_token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_details(self, response): + """Return user details from Wunderlist account""" + fullname, first_name, last_name = self.get_user_names(response.get("name")) + return { + "username": str(response.get("id")), + "email": response.get("email"), + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = {"X-Access-Token": access_token, "X-Client-ID": self.setting("KEY")} + return self.get_json("https://a.wunderlist.com/api/v1/user", headers=headers) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/xing.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/xing.py new file mode 100644 index 0000000000000000000000000000000000000000..7ea4e4151fb9aaf39ba72ab30ed5ac323a8a6e6a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/xing.py @@ -0,0 +1,66 @@ +""" +XING OAuth1 backend, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/xing.html +""" +from oauthlib.oauth1 import SIGNATURE_TYPE_AUTH_HEADER +from requests_oauthlib import OAuth1 + +from ..exceptions import AuthTokenError +from .oauth import BaseOAuth1 + + +class XingOAuth(BaseOAuth1): + """Xing OAuth authentication backend""" + + name = "xing" + AUTHORIZATION_URL = "https://api.xing.com/v1/authorize" + REQUEST_TOKEN_URL = "https://api.xing.com/v1/request_token" + ACCESS_TOKEN_URL = "https://api.xing.com/v1/access_token" + SCOPE_SEPARATOR = "+" + EXTRA_DATA = [("id", "id"), ("user_id", "user_id")] + + def get_user_details(self, response): + """Return user details from Xing account""" + email = response.get("email", "") + fullname, first_name, last_name = self.get_user_names( + first_name=response["first_name"], last_name=response["last_name"] + ) + return { + "username": first_name + last_name, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "email": email, + } + + def clean_oauth_auth(self, access_token): + """Override of oauth_auth since Xing doesn't like callback_uri + and oauth_verifier on authenticated API calls""" + key, secret = self.get_key_and_secret() + resource_owner_key = access_token.get("oauth_token") + resource_owner_secret = access_token.get("oauth_token_secret") + if not resource_owner_key: + raise AuthTokenError(self, "Missing oauth_token") + if not resource_owner_secret: + raise AuthTokenError(self, "Missing oauth_token_secret") + return OAuth1( + key, + secret, + resource_owner_key=resource_owner_key, + resource_owner_secret=resource_owner_secret, + signature_type=SIGNATURE_TYPE_AUTH_HEADER, + ) + + def user_data(self, access_token, *args, **kwargs): + """Return user data provided""" + profile = self.get_json( + "https://api.xing.com/v1/users/me.json", + auth=self.clean_oauth_auth(access_token), + )["users"][0] + return { + "user_id": profile["id"], + "id": profile["id"], + "first_name": profile["first_name"], + "last_name": profile["last_name"], + "email": profile["active_email"], + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yahoo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yahoo.py new file mode 100644 index 0000000000000000000000000000000000000000..b42ba0bbdbc8af6b8d2f03295822fb435b2440b1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yahoo.py @@ -0,0 +1,146 @@ +""" +Yahoo OpenId, OAuth1 and OAuth2 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/yahoo.html +""" +from requests.auth import HTTPBasicAuth + +from ..utils import handle_http_errors +from .oauth import BaseOAuth1, BaseOAuth2 + + +class YahooOAuth(BaseOAuth1): + """Yahoo OAuth authentication backend. DEPRECATED""" + + name = "yahoo-oauth" + ID_KEY = "guid" + AUTHORIZATION_URL = "https://api.login.yahoo.com/oauth/v2/request_auth" + REQUEST_TOKEN_URL = "https://api.login.yahoo.com/oauth/v2/get_request_token" + ACCESS_TOKEN_URL = "https://api.login.yahoo.com/oauth/v2/get_token" + EXTRA_DATA = [ + ("guid", "id"), + ("access_token", "access_token"), + ("expires", "expires"), + ] + + def get_user_details(self, response): + """Return user details from Yahoo Profile""" + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("givenName"), last_name=response.get("familyName") + ) + emails = [email for email in response.get("emails", []) if email.get("handle")] + emails.sort(key=lambda e: e.get("primary", False), reverse=True) + return { + "username": response.get("nickname"), + "email": emails[0]["handle"] if emails else "", + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + url = "https://social.yahooapis.com/v1/user/{0}/profile?format=json" + return self.get_json( + url.format(self._get_guid(access_token)), auth=self.oauth_auth(access_token) + )["profile"] + + def _get_guid(self, access_token): + """ + Beause you have to provide GUID for every API request it's also + returned during one of OAuth calls + """ + return self.get_json( + "https://social.yahooapis.com/v1/me/guid?format=json", + auth=self.oauth_auth(access_token), + )["guid"]["value"] + + +class YahooOAuth2(BaseOAuth2): + """Yahoo OAuth2 authentication backend""" + + name = "yahoo-oauth2" + ID_KEY = "sub" + AUTHORIZATION_URL = "https://api.login.yahoo.com/oauth2/request_auth" + ACCESS_TOKEN_URL = "https://api.login.yahoo.com/oauth2/get_token" + ACCESS_TOKEN_METHOD = "POST" + EXTRA_DATA = [ + ("sub", "id"), + ("access_token", "access_token"), + ("expires_in", "expires"), + ("refresh_token", "refresh_token"), + ("token_type", "token_type"), + ] + + def get_user_names(self, first_name, last_name): + if first_name or last_name: + return " ".join((first_name, last_name)), first_name, last_name + return None, None, None + + def get_user_details(self, response): + """ + Return user details from Yahoo Profile. + To Get user email you need the profile private read permission. + """ + + fullname, first_name, last_name = self.get_user_names( + first_name=response.get("given_name"), last_name=response.get("family_name") + ) + + email = response.get("email") + return { + "username": response.get("nickname"), + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + + url = "https://api.login.yahoo.com/openid/v1/userinfo" + + return self.get_json( + url, headers={"Authorization": f"Bearer {access_token}"}, method="GET" + ) + + @handle_http_errors + def auth_complete(self, *args, **kwargs): + """Completes login process, must return user instance""" + self.process_error(self.data) + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + auth=HTTPBasicAuth(*self.get_key_and_secret()), + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD, + ) + self.process_error(response) + return self.do_auth( + response["access_token"], response=response, *args, **kwargs + ) + + def refresh_token_params(self, token, *args, **kwargs): + return { + "refresh_token": token, + "grant_type": "refresh_token", + "redirect_uri": "oob", # out of bounds + } + + def refresh_token(self, token, *args, **kwargs): + params = self.refresh_token_params(token, *args, **kwargs) + url = self.REFRESH_TOKEN_URL or self.ACCESS_TOKEN_URL + method = self.REFRESH_TOKEN_METHOD + key = "params" if method == "GET" else "data" + request_args = {"headers": self.auth_headers(), "method": method, key: params} + request = self.request( + url, auth=HTTPBasicAuth(*self.get_key_and_secret()), **request_args + ) + return self.process_refresh_token_response(request, *args, **kwargs) + + def auth_complete_params(self, state=None): + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "redirect_uri": self.get_redirect_uri(state), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yammer.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yammer.py new file mode 100644 index 0000000000000000000000000000000000000000..e4fab68e688ed5937c13ec74965b9cec076b87c5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yammer.py @@ -0,0 +1,40 @@ +""" +Yammer OAuth2 production and staging backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/yammer.html +""" +from .oauth import BaseOAuth2 + + +class YammerOAuth2(BaseOAuth2): + name = "yammer" + AUTHORIZATION_URL = "https://www.yammer.com/dialog/oauth" + ACCESS_TOKEN_URL = "https://www.yammer.com/oauth2/access_token" + EXTRA_DATA = [("id", "id"), ("expires", "expires"), ("mugshot_url", "mugshot_url")] + + def get_user_id(self, details, response): + return response["user"]["id"] + + def get_user_details(self, response): + username = response["user"]["name"] + fullname, first_name, last_name = self.get_user_names( + fullname=response["user"]["full_name"], + first_name=response["user"]["first_name"], + last_name=response["user"]["last_name"], + ) + email = response["user"]["contact"]["email_addresses"][0]["address"] + mugshot_url = response["user"]["mugshot_url"] + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + "picture_url": mugshot_url, + } + + +class YammerStagingOAuth2(YammerOAuth2): + name = "yammer-staging" + AUTHORIZATION_URL = "https://www.staging.yammer.com/dialog/oauth" + ACCESS_TOKEN_URL = "https://www.staging.yammer.com/oauth2/access_token" + REQUEST_TOKEN_URL = "https://www.staging.yammer.com/oauth2/request_token" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yandex.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yandex.py new file mode 100644 index 0000000000000000000000000000000000000000..d8498a1df1e327cc6b883b81aaf909290fdb4d4b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/yandex.py @@ -0,0 +1,93 @@ +""" +Yandex OpenID and OAuth2 support. + +This contribution adds support for Yandex.ru OpenID service in the form +openid.yandex.ru/user. Username is retrieved from the identity url. + +If username is not specified, OpenID 2.0 url used for authentication. +""" +from urllib.parse import urlsplit + +from .oauth import BaseOAuth2 +from .open_id import OpenIdAuth + + +class YandexOpenId(OpenIdAuth): + """Yandex OpenID authentication backend""" + + name = "yandex-openid" + URL = "http://openid.yandex.ru" + + def get_user_id(self, details, response): + return details["email"] or response.identity_url + + def get_user_details(self, response): + """Generate username from identity url""" + values = super().get_user_details(response) + values["username"] = values.get("username") or urlsplit( + response.identity_url + ).path.strip("/") + values["email"] = values.get("email", "") + return values + + +class YandexOAuth2(BaseOAuth2): + """Legacy Yandex OAuth2 authentication backend""" + + name = "yandex-oauth2" + AUTHORIZATION_URL = "https://oauth.yandex.com/authorize" + ACCESS_TOKEN_URL = "https://oauth.yandex.com/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response.get("real_name") or response.get("display_name") or "" + ) + email = response.get("default_email") + if not email: + emails = response.get("emails") + email = emails[0] if emails else "" + return { + "username": response.get("display_name"), + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://login.yandex.ru/info", + params={"oauth_token": access_token, "format": "json"}, + ) + + +class YaruOAuth2(BaseOAuth2): + name = "yaru" + AUTHORIZATION_URL = "https://oauth.yandex.com/authorize" + ACCESS_TOKEN_URL = "https://oauth.yandex.com/token" + ACCESS_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + + def get_user_details(self, response): + fullname, first_name, last_name = self.get_user_names( + response.get("real_name") or response.get("display_name") or "" + ) + email = response.get("default_email") + if not email: + emails = response.get("emails") + email = emails[0] if emails else "" + return { + "username": response.get("display_name"), + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def user_data(self, access_token, *args, **kwargs): + return self.get_json( + "https://login.yandex.ru/info", + params={"oauth_token": access_token, "format": "json"}, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zoom.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zoom.py new file mode 100644 index 0000000000000000000000000000000000000000..8cb7eed697c757c23d652cdf93e7cafc4a1fac58 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zoom.py @@ -0,0 +1,63 @@ +import base64 + +from .oauth import BaseOAuth2 + + +class ZoomOAuth2(BaseOAuth2): + """ + Zoom OAuth2 authentication backend + Doc Reference: https://marketplace.zoom.us/docs/guides/auth/oauth + """ + + name = "zoom-oauth2" + AUTHORIZATION_URL = "https://zoom.us/oauth/authorize" + ACCESS_TOKEN_URL = "https://zoom.us/oauth/token" + USER_DETAILS_URL = "https://api.zoom.us/v2/users/me" + DEFAULT_SCOPE = ["user:read"] + ACCESS_TOKEN_METHOD = "POST" + REFRESH_TOKEN_METHOD = "POST" + REDIRECT_STATE = False + EXTRA_DATA = [("expires_in", "expires")] + + def user_data(self, access_token, *args, **kwargs): + response = self.get_json( + self.USER_DETAILS_URL, + headers={ + "Authorization": "Bearer {access_token}".format( + access_token=access_token + ) + }, + ) + return response + + def get_user_details(self, response): + username = response.get("id", "") + first_name = response.get("first_name", "") + last_name = response.get("last_name", "") + email = response.get("email", "") + fullname = "" + return { + "username": username, + "email": email, + "fullname": fullname, + "first_name": first_name, + "last_name": last_name, + } + + def auth_complete_params(self, state=None): + return { + "grant_type": "authorization_code", # request auth code + "code": self.data.get("code", ""), # server response code + "redirect_uri": self.get_redirect_uri(state), + } + + def auth_headers(self): + return { + "Authorization": b"Basic " + + base64.urlsafe_b64encode( + "{}:{}".format(*self.get_key_and_secret()).encode() + ) + } + + def refresh_token_params(self, token, *args, **kwargs): + return {"refresh_token": token, "grant_type": "refresh_token"} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zotero.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zotero.py new file mode 100644 index 0000000000000000000000000000000000000000..8684d34f9f68763f37ca889db3e3b8f12066bd62 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/backends/zotero.py @@ -0,0 +1,30 @@ +""" +Zotero OAuth1 backends, docs at: + https://python-social-auth.readthedocs.io/en/latest/backends/zotero.html +""" +from .oauth import BaseOAuth1 + + +class ZoteroOAuth(BaseOAuth1): + + """Zotero OAuth authorization mechanism""" + + name = "zotero" + AUTHORIZATION_URL = "https://www.zotero.org/oauth/authorize" + REQUEST_TOKEN_URL = "https://www.zotero.org/oauth/request" + ACCESS_TOKEN_URL = "https://www.zotero.org/oauth/access" + + def get_user_id(self, details, response): + """ + Return user unique id provided by service. For Ubuntu One + the nickname should be original. + """ + return details["userID"] + + def get_user_details(self, response): + """Return user details from Zotero API account""" + access_token = response.get("access_token", {}) + return { + "username": access_token.get("username", ""), + "userID": access_token.get("userID", ""), + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..c0900338c7fc71cdb3afd45c8e15a8a261d5485d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/exceptions.py @@ -0,0 +1,130 @@ +class SocialAuthBaseException(ValueError): + """Base class for pipeline exceptions.""" + + pass + + +class WrongBackend(SocialAuthBaseException): + def __init__(self, backend_name): + self.backend_name = backend_name + + def __str__(self): + return f'Incorrect authentication service "{self.backend_name}"' + + +class MissingBackend(WrongBackend): + def __str__(self): + return f'Missing backend "{self.backend_name}" entry' + + +class NotAllowedToDisconnect(SocialAuthBaseException): + """User is not allowed to disconnect it's social account.""" + + def __str__(self): + return "This account is not allowed to be disconnected." + + +class AuthException(SocialAuthBaseException): + """Auth process exception.""" + + def __init__(self, backend, *args, **kwargs): + self.backend = backend + super().__init__(*args, **kwargs) + + +class AuthFailed(AuthException): + """Auth process failed for some reason.""" + + def __str__(self): + msg = super().__str__() + if msg == "access_denied": + return "Authentication process was canceled" + return f"Authentication failed: {msg}" + + +class AuthCanceled(AuthException): + """Auth process was canceled by user.""" + + def __init__(self, *args, **kwargs): + self.response = kwargs.pop("response", None) + super().__init__(*args, **kwargs) + + def __str__(self): + msg = super().__str__() + if msg: + return f"Authentication process canceled: {msg}" + return "Authentication process canceled" + + +class AuthUnknownError(AuthException): + """Unknown auth process error.""" + + def __str__(self): + msg = super().__str__() + return f"An unknown error happened while authenticating {msg}" + + +class AuthTokenError(AuthException): + """Auth token error.""" + + def __str__(self): + msg = super().__str__() + return f"Token error: {msg}" + + +class AuthMissingParameter(AuthException): + """Missing parameter needed to start or complete the process.""" + + def __init__(self, backend, parameter, *args, **kwargs): + self.parameter = parameter + super().__init__(backend, *args, **kwargs) + + def __str__(self): + return f"Missing needed parameter {self.parameter}" + + +class AuthStateMissing(AuthException): + """State parameter is incorrect.""" + + def __str__(self): + return "Session value state missing." + + +class AuthStateForbidden(AuthException): + """State parameter is incorrect.""" + + def __str__(self): + return "Wrong state parameter given." + + +class AuthAlreadyAssociated(AuthException): + """A different user has already associated the target social account""" + + def __str__(self): + return "This account is already in use." + + +class AuthTokenRevoked(AuthException): + """User revoked the access_token in the provider.""" + + def __str__(self): + return "User revoke access to the token" + + +class AuthForbidden(AuthException): + """Authentication for this user is forbidden""" + + def __str__(self): + return "Your credentials aren't allowed" + + +class AuthUnreachableProvider(AuthException): + """Cannot reach the provider""" + + def __str__(self): + return "The authentication provider could not be reached" + + +class InvalidEmail(AuthException): + def __str__(self): + return "Email couldn't be validated" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ff422be6dcd5604437335c1399b2da944991522 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__init__.py @@ -0,0 +1,46 @@ +DEFAULT_AUTH_PIPELINE = ( + # Get the information we can about the user and return it in a simple + # format to create the user instance later. On some cases the details are + # already part of the auth response from the provider, but sometimes this + # could hit a provider API. + "social_core.pipeline.social_auth.social_details", + # Get the social uid from whichever service we're authing thru. The uid is + # the unique identifier of the given user in the provider. + "social_core.pipeline.social_auth.social_uid", + # Verifies that the current auth process is valid within the current + # project, this is where emails and domains whitelists are applied (if + # defined). + "social_core.pipeline.social_auth.auth_allowed", + # Checks if the current social-account is already associated in the site. + "social_core.pipeline.social_auth.social_user", + # Make up a username for this person, appends a random string at the end if + # there's any collision. + "social_core.pipeline.user.get_username", + # Send a validation email to the user to verify its email address. + # 'social_core.pipeline.mail.mail_validation', + # Associates the current social details with another user account with + # a similar email address. + # 'social_core.pipeline.social_auth.associate_by_email', + # Create a user account if we haven't found one yet. + "social_core.pipeline.user.create_user", + # Create the record that associated the social account with this user. + "social_core.pipeline.social_auth.associate_user", + # Populate the extra_data field in the social record with the values + # specified by settings (and the default ones like access_token, etc). + "social_core.pipeline.social_auth.load_extra_data", + # Update the user record with any changed info from the auth service. + "social_core.pipeline.user.user_details", +) + +DEFAULT_DISCONNECT_PIPELINE = ( + # Verifies that the social association can be disconnected from the current + # user (ensure that the user login mechanism is not compromised by this + # disconnection). + "social_core.pipeline.disconnect.allowed_to_disconnect", + # Collects the social associations to disconnect. + "social_core.pipeline.disconnect.get_entries", + # Revoke any access_token when possible. + "social_core.pipeline.disconnect.revoke_tokens", + # Removes the social associations. + "social_core.pipeline.disconnect.disconnect", +) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..059a7be7360e915f9021908b599fa135cf00e774 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/debug.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/debug.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed0999967da2d8ccf491769582ccb21f016bf5b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/debug.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/disconnect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/disconnect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72d859b6ee9f5cd3239126515735209a87516cee Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/disconnect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/mail.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/mail.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2227d8e80fdf72199adbe7a8e752992f5f6297b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/mail.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/partial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/partial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d75fd0d12b8731d6ba2589db8087e326542caa5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/partial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/social_auth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/social_auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..271dfa804384e5e496d507187673e70582f89af6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/social_auth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/user.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/user.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f7588b7ac2cf68ea55c6d9486a378cc7dba63a7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/user.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c99e668f72c0da23cdcbef6c00e6cf09d89a4da Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/debug.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/debug.py new file mode 100644 index 0000000000000000000000000000000000000000..ca021d39896878d95d5e9e45416fd26e623fcbb5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/debug.py @@ -0,0 +1,13 @@ +from pprint import pprint + + +def debug(response, details, *args, **kwargs): + print("=" * 80) + pprint(response) + print("=" * 80) + pprint(details) + print("=" * 80) + pprint(args) + print("=" * 80) + pprint(kwargs) + print("=" * 80) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/disconnect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/disconnect.py new file mode 100644 index 0000000000000000000000000000000000000000..4ac093d62cd50df9aae1c56c0e646f0ef3cfc355 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/disconnect.py @@ -0,0 +1,30 @@ +from ..exceptions import NotAllowedToDisconnect + + +def allowed_to_disconnect( + strategy, user, name, user_storage, association_id=None, *args, **kwargs +): + if not user_storage.allowed_to_disconnect(user, name, association_id): + raise NotAllowedToDisconnect() + + +def get_entries( + strategy, user, name, user_storage, association_id=None, *args, **kwargs +): + return { + "entries": user_storage.get_social_auth_for_user(user, name, association_id) + } + + +def revoke_tokens(strategy, entries, *args, **kwargs): + revoke_tokens = strategy.setting("REVOKE_TOKENS_ON_DISCONNECT", False) + if revoke_tokens: + for entry in entries: + if "access_token" in entry.extra_data: + backend = entry.get_backend_instance(strategy) + backend.revoke_token(entry.extra_data["access_token"], entry.uid) + + +def disconnect(strategy, entries, user_storage, *args, **kwargs): + for entry in entries: + user_storage.disconnect(entry) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/mail.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/mail.py new file mode 100644 index 0000000000000000000000000000000000000000..239600d030dbe57ff28f9072c714b8c594e5b055 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/mail.py @@ -0,0 +1,29 @@ +from ..exceptions import InvalidEmail +from .partial import partial + + +@partial +def mail_validation(backend, details, is_new=False, *args, **kwargs): + requires_validation = backend.REQUIRES_EMAIL_VALIDATION or backend.setting( + "FORCE_EMAIL_VALIDATION", False + ) + send_validation = details.get("email") and ( + is_new or backend.setting("PASSWORDLESS", False) + ) + if requires_validation and send_validation: + data = backend.strategy.request_data() + if "verification_code" in data: + backend.strategy.session_pop("email_validation_address") + if not backend.strategy.validate_email( + details["email"], data["verification_code"] + ): + raise InvalidEmail(backend) + else: + current_partial = kwargs.get("current_partial") + backend.strategy.send_email_validation( + backend, details["email"], current_partial.token + ) + backend.strategy.session_set("email_validation_address", details["email"]) + return backend.strategy.redirect( + backend.strategy.setting("EMAIL_VALIDATION_URL") + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/partial.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/partial.py new file mode 100644 index 0000000000000000000000000000000000000000..8925ec699a1533beec064d4b989858ecae2f3e6c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/partial.py @@ -0,0 +1,58 @@ +from functools import wraps + +from ..utils import PARTIAL_TOKEN_SESSION_NAME +from .utils import partial_prepare + + +def partial_step(save_to_session): + """Wraps func to behave like a partial pipeline step, any output + that's not None or {} will be considered a response object and + will be returned to user. + + The pipeline function will receive a current_partial object, it + contains the partial pipeline data and a token that is used to + identify it when it's continued, this is useful to build links + with the token. + + The default value for this parameter is partial_token, but can be + overridden by SOCIAL_AUTH_PARTIAL_PIPELINE_TOKEN_NAME setting. + + The token is also stored in the session under the + PARTIAL_TOKEN_SESSION_NAME (partial_pipeline_token) key when the + save_to_session parameter is True. + """ + + def decorator(func): + @wraps(func) + def wrapper(strategy, backend, pipeline_index, *args, **kwargs): + current_partial = partial_prepare( + strategy, backend, pipeline_index, *args, **kwargs + ) + + out = ( + func( + strategy=strategy, + backend=backend, + pipeline_index=pipeline_index, + current_partial=current_partial, + *args, + **kwargs + ) + or {} + ) + + if not isinstance(out, dict): + strategy.storage.partial.store(current_partial) + if save_to_session: + strategy.session_set( + PARTIAL_TOKEN_SESSION_NAME, current_partial.token + ) + return out + + return wrapper + + return decorator + + +# Backward compatible partial decorator, that stores the token in the session +partial = partial_step(save_to_session=True) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/social_auth.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/social_auth.py new file mode 100644 index 0000000000000000000000000000000000000000..1fd124aff875db051ff67acaad787aeff589fa3f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/social_auth.py @@ -0,0 +1,91 @@ +from ..exceptions import AuthAlreadyAssociated, AuthException, AuthForbidden + + +def social_details(backend, details, response, *args, **kwargs): + return {"details": dict(backend.get_user_details(response), **details)} + + +def social_uid(backend, details, response, *args, **kwargs): + return {"uid": backend.get_user_id(details, response)} + + +def auth_allowed(backend, details, response, *args, **kwargs): + if not backend.auth_allowed(response, details): + raise AuthForbidden(backend) + + +def social_user(backend, uid, user=None, *args, **kwargs): + provider = backend.name + social = backend.strategy.storage.user.get_social_auth(provider, uid) + if social: + if user and social.user != user: + raise AuthAlreadyAssociated(backend) + elif not user: + user = social.user + return { + "social": social, + "user": user, + "is_new": user is None, + "new_association": social is None, + } + + +def associate_user(backend, uid, user=None, social=None, *args, **kwargs): + if user and not social: + try: + social = backend.strategy.storage.user.create_social_auth( + user, uid, backend.name + ) + except Exception as err: + if not backend.strategy.storage.is_integrity_error(err): + raise + # Protect for possible race condition, those bastard with FTL + # clicking capabilities, check issue #131: + # https://github.com/omab/django-social-auth/issues/131 + result = social_user(backend, uid, user, *args, **kwargs) + # Check if matching social auth really exists. In case it does + # not, the integrity error probably had different cause than + # existing entry and should not be hidden. + if not result["social"]: + raise + return result + else: + return {"social": social, "user": social.user, "new_association": True} + + +def associate_by_email(backend, details, user=None, *args, **kwargs): + """ + Associate current auth with a user with the same email address in the DB. + + This pipeline entry is not 100% secure unless you know that the providers + enabled enforce email verification on their side, otherwise a user can + attempt to take over another user account by using the same (not validated) + email address on some provider. This pipeline entry is disabled by + default. + """ + if user: + return None + + email = details.get("email") + if email: + # Try to associate accounts registered with the same email address, + # only if it's a single object. AuthException is raised if multiple + # objects are returned. + users = list(backend.strategy.storage.user.get_users_by_email(email)) + if len(users) == 0: + return None + elif len(users) > 1: + raise AuthException( + backend, "The given email address is associated with another account" + ) + else: + return {"user": users[0], "is_new": False} + + +def load_extra_data(backend, details, response, uid, user, *args, **kwargs): + social = kwargs.get("social") or backend.strategy.storage.user.get_social_auth( + backend.name, uid + ) + if social: + extra_data = backend.extra_data(user, uid, response, details, *args, **kwargs) + social.set_extra_data(extra_data) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/user.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/user.py new file mode 100644 index 0000000000000000000000000000000000000000..9e4d17ac585b77703a0ec26a0c332b3372abb54d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/user.py @@ -0,0 +1,124 @@ +from uuid import uuid4 + +from ..utils import module_member, slugify + +USER_FIELDS = ["username", "email"] + + +def get_username(strategy, details, backend, user=None, *args, **kwargs): + if "username" not in backend.setting("USER_FIELDS", USER_FIELDS): + return + storage = strategy.storage + + if not user: + email_as_username = strategy.setting("USERNAME_IS_FULL_EMAIL", False) + uuid_length = strategy.setting("UUID_LENGTH", 16) + max_length = storage.user.username_max_length() + do_slugify = strategy.setting("SLUGIFY_USERNAMES", False) + do_clean = strategy.setting("CLEAN_USERNAMES", True) + + def identity_func(val): + return val + + if do_clean: + override_clean = strategy.setting("CLEAN_USERNAME_FUNCTION") + if override_clean: + clean_func = module_member(override_clean) + else: + clean_func = storage.user.clean_username + else: + clean_func = identity_func + + if do_slugify: + override_slug = strategy.setting("SLUGIFY_FUNCTION") + slug_func = module_member(override_slug) if override_slug else slugify + else: + slug_func = identity_func + + if email_as_username and details.get("email"): + username = details["email"] + elif details.get("username"): + username = details["username"] + else: + username = uuid4().hex + + short_username = ( + username[: max_length - uuid_length] if max_length is not None else username + ) + final_username = slug_func(clean_func(username[:max_length])) + + # Generate a unique username for current user using username + # as base but adding a unique hash at the end. Original + # username is cut to avoid any field max_length. + # The final_username may be empty and will skip the loop. + while not final_username or storage.user.user_exists(username=final_username): + username = short_username + uuid4().hex[:uuid_length] + final_username = slug_func(clean_func(username[:max_length])) + else: + final_username = storage.user.get_username(user) + return {"username": final_username} + + +def create_user(strategy, details, backend, user=None, *args, **kwargs): + if user: + return {"is_new": False} + + fields = { + name: kwargs.get(name, details.get(name)) + for name in backend.setting("USER_FIELDS", USER_FIELDS) + } + if not fields: + return + + return {"is_new": True, "user": strategy.create_user(**fields)} + + +def user_details(strategy, details, backend, user=None, *args, **kwargs): + """Update user details using data from provider.""" + if not user: + return + + changed = False # flag to track changes + + # Default protected user fields (username, id, pk and email) can be ignored + # by setting the SOCIAL_AUTH_NO_DEFAULT_PROTECTED_USER_FIELDS to True + if strategy.setting("NO_DEFAULT_PROTECTED_USER_FIELDS") is True: + protected = () + else: + protected = ( + "username", + "id", + "pk", + "email", + "password", + "is_active", + "is_staff", + "is_superuser", + ) + + protected = protected + tuple(strategy.setting("PROTECTED_USER_FIELDS", [])) + + # Update user model attributes with the new data sent by the current + # provider. Update on some attributes is disabled by default, for + # example username and id fields. It's also possible to disable update + # on fields defined in SOCIAL_AUTH_PROTECTED_USER_FIELDS. + field_mapping = strategy.setting("USER_FIELD_MAPPING", {}, backend) + for name, value in details.items(): + # Convert to existing user field if mapping exists + name = field_mapping.get(name, name) + if value is None or not hasattr(user, name) or name in protected: + continue + + current_value = getattr(user, name, None) + if current_value == value: + continue + + immutable_fields = tuple(strategy.setting("IMMUTABLE_USER_FIELDS", [])) + if name in immutable_fields and current_value: + continue + + changed = True + setattr(user, name, value) + + if changed: + strategy.storage.user.changed(user) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..981c891b75410f0a0c04e0fc113fc168c4c47262 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/pipeline/utils.py @@ -0,0 +1,74 @@ +SERIALIZABLE_TYPES = (dict, list, tuple, set, bool, type(None), int, str, bytes) + + +def is_dict_type(value): + """Treat any dict, MergeDict, MultiDict instance as dict type""" + # Check by class name to avoid importing Django MergeDict or + # Werkzeug MultiDict + return isinstance(value, dict) or value.__class__.__name__ in ( + "MergeDict", + "MultiDict", + ) + + +def partial_prepare( + strategy, backend, next_step, user=None, social=None, *args, **kwargs +): + kwargs.update( + { + "response": kwargs.get("response") or {}, + "details": kwargs.get("details") or {}, + "username": kwargs.get("username"), + "uid": kwargs.get("uid"), + "is_new": kwargs.get("is_new") or False, + "new_association": kwargs.get("new_association") or False, + "user": hasattr(user, "id") and user.id or None, + "social": social + and {"provider": social.provider, "uid": social.uid} + or None, + } + ) + + clean_args = [strategy.to_session_value(val) for val in args] + + # Clean any MergeDict data type from the values + clean_kwargs = {} + for name, value in kwargs.items(): + value = dict(value) if is_dict_type(value) else value + if isinstance(value, SERIALIZABLE_TYPES): + clean_kwargs[name] = strategy.to_session_value(value) + + return strategy.storage.partial.prepare( + backend.name, next_step, {"args": clean_args, "kwargs": clean_kwargs} + ) + + +def partial_store( + strategy, backend, next_step, user=None, social=None, *args, **kwargs +): + partial = partial_prepare( + strategy, backend, next_step, user=user, social=social, *args, **kwargs + ) + return strategy.storage.partial.store(partial) + + +def partial_load(strategy, token): + partial = strategy.storage.partial.load(token) + + if partial: + args = partial.args + kwargs = partial.kwargs.copy() + user = kwargs.get("user") + social = kwargs.get("social") + + if isinstance(social, dict): + kwargs["social"] = strategy.storage.user.get_social_auth(**social) + + if user: + kwargs["user"] = strategy.storage.user.get_user(user) + + partial.args = [strategy.from_session_value(val) for val in args] + partial.kwargs = { + key: strategy.from_session_value(val) for key, val in kwargs.items() + } + return partial diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/storage.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/storage.py new file mode 100644 index 0000000000000000000000000000000000000000..7c02082795110185472e490fd49a45fe21c306ff --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/storage.py @@ -0,0 +1,352 @@ +"""Models mixins for Social Auth""" +import base64 +import re +import time +import uuid +import warnings +from datetime import datetime, timedelta + +from openid.association import Association as OpenIdAssociation + +from .exceptions import MissingBackend + +NO_ASCII_REGEX = re.compile(r"[^\x00-\x7F]+") +NO_SPECIAL_REGEX = re.compile(r"[^\w.@+_-]+", re.UNICODE) + + +class UserMixin: + # Consider tokens that expire in 5 seconds as already expired + ACCESS_TOKEN_EXPIRED_THRESHOLD = 5 + + user = "" + provider = "" + uid = None + extra_data = None + + def get_backend(self, strategy): + return strategy.get_backend_class(self.provider) + + def get_backend_instance(self, strategy): + try: + return strategy.get_backend(self.provider) + except MissingBackend: + return None + + @property + def access_token(self): + """Return access_token stored in extra_data or None""" + return self.extra_data.get("access_token") + + @property + def tokens(self): + warnings.warn("tokens is deprecated, use access_token instead") + return self.access_token + + def refresh_token(self, strategy, *args, **kwargs): + token = self.extra_data.get("refresh_token") or self.extra_data.get( + "access_token" + ) + backend = self.get_backend_instance(strategy) + if token and backend and hasattr(backend, "refresh_token"): + response = backend.refresh_token(token, *args, **kwargs) + extra_data = backend.extra_data(self, self.uid, response, self.extra_data) + if self.set_extra_data(extra_data): + self.save() + + def expiration_timedelta(self): + """Return provider session live seconds. Returns a timedelta ready to + use with session.set_expiry(). + + If provider returns a timestamp instead of session seconds to live, the + timedelta is inferred from current time (using UTC timezone). None is + returned if there's no value stored or it's invalid. + """ + if self.extra_data and "expires" in self.extra_data: + try: + expires = int(self.extra_data.get("expires")) + except (ValueError, TypeError): + return None + + now = datetime.utcnow() + + # Detect if expires is a timestamp + if expires > time.mktime(now.timetuple()): + # expires is a datetime, return the remaining difference + return datetime.utcfromtimestamp(expires) - now + else: + # expires is the time to live seconds since creation, + # check against auth_time if present, otherwise return + # the value + auth_time = self.extra_data.get("auth_time") + if auth_time: + reference = datetime.utcfromtimestamp(auth_time) + return (reference + timedelta(seconds=expires)) - now + else: + return timedelta(seconds=expires) + + def expiration_datetime(self): + # backward compatible alias + return self.expiration_timedelta() + + def access_token_expired(self): + """Return true / false if access token is already expired""" + expiration = self.expiration_timedelta() + return ( + expiration + and expiration.total_seconds() <= self.ACCESS_TOKEN_EXPIRED_THRESHOLD + ) + + def get_access_token(self, strategy): + """Returns a valid access token.""" + if self.access_token_expired(): + self.refresh_token(strategy) + return self.access_token + + def set_extra_data(self, extra_data=None): + if extra_data and self.extra_data != extra_data: + if self.extra_data and not isinstance(self.extra_data, str): + self.extra_data.update(extra_data) + else: + self.extra_data = extra_data + return True + + @classmethod + def clean_username(cls, value): + """Clean username removing any unsupported character""" + value = NO_ASCII_REGEX.sub("", value) + value = NO_SPECIAL_REGEX.sub("", value) + return value + + @classmethod + def changed(cls, user): + """The given user instance is ready to be saved""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get_username(cls, user): + """Return the username for given user""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def user_model(cls): + """Return the user model""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def username_max_length(cls): + """Return the max length for username""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def allowed_to_disconnect(cls, user, backend_name, association_id=None): + """Return if it's safe to disconnect the social account for the + given user""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def disconnect(cls, entry): + """Disconnect the social account for the given user""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def user_exists(cls, *args, **kwargs): + """ + Return True/False if a User instance exists with the given arguments. + Arguments are directly passed to filter() manager method. + """ + raise NotImplementedError("Implement in subclass") + + @classmethod + def create_user(cls, *args, **kwargs): + """Create a user instance""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get_user(cls, pk): + """Return user instance for given id""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get_users_by_email(cls, email): + """Return users instances for given email address""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get_social_auth(cls, provider, uid): + """Return UserSocialAuth for given provider and uid""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get_social_auth_for_user(cls, user, provider=None, id=None): + """Return all the UserSocialAuth instances for given user""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def create_social_auth(cls, user, uid, provider): + """Create a UserSocialAuth instance for given user""" + raise NotImplementedError("Implement in subclass") + + +class NonceMixin: + """One use numbers""" + + server_url = "" + timestamp = 0 + salt = "" + + @classmethod + def use(cls, server_url, timestamp, salt): + """Create a Nonce instance""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get(cls, server_url, salt): + """Retrieve a Nonce instance""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def delete(cls, nonce): + """Delete a Nonce instance""" + raise NotImplementedError("Implement in subclass") + + +class AssociationMixin: + """OpenId account association""" + + server_url = "" + handle = "" + secret = "" + issued = 0 + lifetime = 0 + assoc_type = "" + + @classmethod + def oids(cls, server_url, handle=None): + kwargs = {"server_url": server_url} + if handle is not None: + kwargs["handle"] = handle + return sorted( + ((assoc.id, cls.openid_association(assoc)) for assoc in cls.get(**kwargs)), + key=lambda x: x[1].issued, + reverse=True, + ) + + @classmethod + def openid_association(cls, assoc): + secret = assoc.secret + if not isinstance(secret, bytes): + secret = secret.encode() + return OpenIdAssociation( + assoc.handle, + base64.decodebytes(secret), + assoc.issued, + assoc.lifetime, + assoc.assoc_type, + ) + + @classmethod + def store(cls, server_url, association): + """Create an Association instance""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def get(cls, *args, **kwargs): + """Get an Association instance""" + raise NotImplementedError("Implement in subclass") + + @classmethod + def remove(cls, ids_to_delete): + """Remove an Association instance""" + raise NotImplementedError("Implement in subclass") + + +class CodeMixin: + email = "" + code = "" + verified = False + + def verify(self): + self.verified = True + self.save() + + @classmethod + def generate_code(cls): + return uuid.uuid4().hex + + @classmethod + def make_code(cls, email): + code = cls() + code.email = email + code.code = cls.generate_code() + code.verified = False + code.save() + return code + + @classmethod + def get_code(cls, code): + raise NotImplementedError("Implement in subclass") + + +class PartialMixin: + token = "" + data = "" + next_step = "" + backend = "" + + @property + def args(self): + return self.data.get("args", []) + + @args.setter + def args(self, value): + self.data["args"] = value + + @property + def kwargs(self): + return self.data.get("kwargs", {}) + + @kwargs.setter + def kwargs(self, value): + self.data["kwargs"] = value + + def extend_kwargs(self, values): + self.data["kwargs"].update(values) + + @classmethod + def generate_token(cls): + return uuid.uuid4().hex + + @classmethod + def load(cls, token): + raise NotImplementedError("Implement in subclass") + + @classmethod + def destroy(cls, token): + raise NotImplementedError("Implement in subclass") + + @classmethod + def prepare(cls, backend, next_step, data): + partial = cls() + partial.backend = backend + partial.next_step = next_step + partial.data = data + partial.token = cls.generate_token() + return partial + + @classmethod + def store(cls, partial): + partial.save() + return partial + + +class BaseStorage: + user = UserMixin + nonce = NonceMixin + association = AssociationMixin + code = CodeMixin + partial = PartialMixin + + @classmethod + def is_integrity_error(cls, exception): + """Check if given exception flags an integrity error in the DB""" + raise NotImplementedError("Implement in subclass") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/store.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/store.py new file mode 100644 index 0000000000000000000000000000000000000000..6dfe9e072b968c28f254c1342a7592b49433d952 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/store.py @@ -0,0 +1,80 @@ +import pickle +import time + +from openid.store.interface import OpenIDStore as BaseOpenIDStore +from openid.store.nonce import SKEW + + +class OpenIdStore(BaseOpenIDStore): + """Storage class""" + + def __init__(self, strategy): + """Init method""" + super().__init__() + self.strategy = strategy + self.storage = strategy.storage + self.assoc = self.storage.association + self.nonce = self.storage.nonce + self.max_nonce_age = 6 * 60 * 60 # Six hours + + def storeAssociation(self, server_url, association): + """Store new association if it does not exist""" + self.assoc.store(server_url, association) + + def removeAssociation(self, server_url, handle): + """Remove association""" + associations_ids = list(dict(self.assoc.oids(server_url, handle)).keys()) + if associations_ids: + self.assoc.remove(associations_ids) + + def expiresIn(self, assoc): + if hasattr(assoc, "getExpiresIn"): + return assoc.getExpiresIn() + else: # python3-openid 3.0.2 + return assoc.expiresIn + + def getAssociation(self, server_url, handle=None): + """Return stored association""" + associations, expired = [], [] + for assoc_id, association in self.assoc.oids(server_url, handle): + expires = self.expiresIn(association) + if expires > 0: + associations.append(association) + elif expires == 0: + expired.append(assoc_id) + + if expired: # clear expired associations + self.assoc.remove(expired) + + if associations: # return most recet association + return associations[0] + + def useNonce(self, server_url, timestamp, salt): + """Generate one use number and return *if* it was created""" + if abs(timestamp - time.time()) > SKEW: + return False + return self.nonce.use(server_url, timestamp, salt) + + +class OpenIdSessionWrapper(dict): + pickle_instances = ( + "_yadis_services__openid_consumer_", + "_openid_consumer_last_token", + ) + + def __getitem__(self, name): + value = super().__getitem__(name) + if name in self.pickle_instances: + value = pickle.loads(value) + return value + + def __setitem__(self, name, value): + if name in self.pickle_instances: + value = pickle.dumps(value, 0) + super().__setitem__(name, value) + + def get(self, name, default=None): + try: + return self[name] + except KeyError: + return default diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/strategy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/strategy.py new file mode 100644 index 0000000000000000000000000000000000000000..60ab1cd129acaf92efaf520a3b119fefc6601d29 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/strategy.py @@ -0,0 +1,235 @@ +import hashlib +import random +import time + +from .backends.utils import get_backend +from .pipeline import DEFAULT_AUTH_PIPELINE, DEFAULT_DISCONNECT_PIPELINE +from .pipeline.utils import partial_load, partial_prepare, partial_store +from .store import OpenIdSessionWrapper, OpenIdStore +from .utils import PARTIAL_TOKEN_SESSION_NAME, module_member, setting_name + + +class BaseTemplateStrategy: + def __init__(self, strategy): + self.strategy = strategy + + def render(self, tpl=None, html=None, context=None): + if not tpl and not html: + raise ValueError("Missing template or html parameters") + context = context or {} + if tpl: + return self.render_template(tpl, context) + else: + return self.render_string(html, context) + + def render_template(self, tpl, context): + raise NotImplementedError("Implement in subclass") + + def render_string(self, html, context): + raise NotImplementedError("Implement in subclass") + + +class BaseStrategy: + ALLOWED_CHARS = ( + "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" + ) + DEFAULT_TEMPLATE_STRATEGY = BaseTemplateStrategy + + def __init__(self, storage=None, tpl=None): + self.storage = storage + self.tpl = (tpl or self.DEFAULT_TEMPLATE_STRATEGY)(self) + + def setting(self, name, default=None, backend=None): + names = [setting_name(name), name] + if backend: + names.insert(0, setting_name(backend.name, name)) + for name in names: + try: + return self.get_setting(name) + except (AttributeError, KeyError): + pass + return default + + def create_user(self, *args, **kwargs): + return self.storage.user.create_user(*args, **kwargs) + + def get_user(self, *args, **kwargs): + return self.storage.user.get_user(*args, **kwargs) + + def session_setdefault(self, name, value): + self.session_set(name, value) + return self.session_get(name) + + def openid_session_dict(self, name): + # Many frameworks are switching the session serialization from Pickle + # to JSON to avoid code execution risks. Flask did this from Flask + # 0.10, Django is switching to JSON by default from version 1.6. + # + # Sadly python-openid stores classes instances in the session which + # fails the JSON serialization, the classes are: + # + # openid.yadis.manager.YadisServiceManager + # openid.consumer.discover.OpenIDServiceEndpoint + # + # This method will return a wrapper over the session value used with + # openid (a dict) which will automatically keep a pickled value for the + # mentioned classes. + return OpenIdSessionWrapper(self.session_setdefault(name, {})) + + def to_session_value(self, val): + return val + + def from_session_value(self, val): + return val + + def partial_save(self, next_step, backend, *args, **kwargs): + return partial_store(self, backend, next_step, *args, **kwargs) + + def partial_prepare(self, next_step, backend, *args, **kwargs): + return partial_prepare(self, backend, next_step, *args, **kwargs) + + def partial_load(self, token): + return partial_load(self, token) + + def clean_partial_pipeline(self, token): + self.storage.partial.destroy(token) + current_token_in_session = self.session_get(PARTIAL_TOKEN_SESSION_NAME) + if current_token_in_session == token: + self.session_pop(PARTIAL_TOKEN_SESSION_NAME) + + def openid_store(self): + return OpenIdStore(self) + + def get_pipeline(self, backend=None): + return self.setting("PIPELINE", DEFAULT_AUTH_PIPELINE, backend) + + def get_disconnect_pipeline(self, backend=None): + return self.setting("DISCONNECT_PIPELINE", DEFAULT_DISCONNECT_PIPELINE, backend) + + def random_string(self, length=12, chars=ALLOWED_CHARS): + # Implementation borrowed from django 1.4 + try: + random.SystemRandom() + except NotImplementedError: + key = self.setting("SECRET_KEY", "") + seed = f"{random.getstate()}{time.time()}{key}" + random.seed(hashlib.sha256(seed.encode()).digest()) + return "".join([random.choice(chars) for i in range(length)]) + + def absolute_uri(self, path=None): + uri = self.build_absolute_uri(path) + if uri and self.setting("REDIRECT_IS_HTTPS"): + uri = uri.replace("http://", "https://") + return uri + + def get_language(self): + """Return current language""" + return "" + + def send_email_validation(self, backend, email, partial_token=None): + email_validation = self.setting("EMAIL_VALIDATION_FUNCTION") + send_email = module_member(email_validation) + code = self.storage.code.make_code(email) + send_email(self, backend, code, partial_token) + return code + + def validate_email(self, email, code): + verification_code = self.storage.code.get_code(code) + if not verification_code or verification_code.code != code: + return False + elif verification_code.email != email: + return False + elif verification_code.verified: + return False + else: + verification_code.verify() + return True + + def render_html(self, tpl=None, html=None, context=None): + """Render given template or raw html with given context""" + return self.tpl.render(tpl, html, context) + + def authenticate(self, backend, *args, **kwargs): + """Trigger the authentication mechanism tied to the current + framework""" + kwargs["strategy"] = self + kwargs["storage"] = self.storage + kwargs["backend"] = backend + args, kwargs = self.clean_authenticate_args(*args, **kwargs) + return backend.authenticate(*args, **kwargs) + + def clean_authenticate_args(self, *args, **kwargs): + """Take authenticate arguments and return a "cleaned" version + of them""" + return args, kwargs + + def get_backends(self): + """Return configured backends""" + return self.setting("AUTHENTICATION_BACKENDS", []) + + def get_backend_class(self, name): + """Return a configured backend class""" + return get_backend(self.get_backends(), name) + + def get_backend(self, name, redirect_uri=None, *args, **kwargs): + """Return a configured backend instance""" + Backend = self.get_backend_class(name) + return Backend(self, redirect_uri=redirect_uri, *args, **kwargs) + + # Implement the following methods on strategies sub-classes + + def redirect(self, url): + """Return a response redirect to the given URL""" + raise NotImplementedError("Implement in subclass") + + def get_setting(self, name): + """Return value for given setting name""" + raise NotImplementedError("Implement in subclass") + + def html(self, content): + """Return HTTP response with given content""" + raise NotImplementedError("Implement in subclass") + + def request_data(self, merge=True): + """Return current request data (POST or GET)""" + raise NotImplementedError("Implement in subclass") + + def request_host(self): + """Return current host value""" + raise NotImplementedError("Implement in subclass") + + def session_get(self, name, default=None): + """Return session value for given key""" + raise NotImplementedError("Implement in subclass") + + def session_set(self, name, value): + """Set session value for given key""" + raise NotImplementedError("Implement in subclass") + + def session_pop(self, name): + """Pop session value for given key""" + raise NotImplementedError("Implement in subclass") + + def build_absolute_uri(self, path=None): + """Build absolute URI with given (optional) path""" + raise NotImplementedError("Implement in subclass") + + def request_is_secure(self): + """Is the request using HTTPS?""" + raise NotImplementedError("Implement in subclass") + + def request_path(self): + """path of the current request""" + raise NotImplementedError("Implement in subclass") + + def request_port(self): + """Port in use for this request""" + raise NotImplementedError("Implement in subclass") + + def request_get(self): + """Request GET data""" + raise NotImplementedError("Implement in subclass") + + def request_post(self): + """Request POST data""" + raise NotImplementedError("Implement in subclass") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e42fde659670d2e6e47e7c63552562830180053 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf6ba3764b72de30f247f3a88d260bc2e963bd5a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/pipeline.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/pipeline.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f7141e9b77693c1872288b6bb0ba95966906be2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/pipeline.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/strategy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/strategy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83e4747f69bf056e09b228f1914aeccb6e2cbfe0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/strategy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_exceptions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b89087c2999348802f1d7d09d14ae49d287e4e7a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_exceptions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_partial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_partial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2939d99f80c0f4deac7fb208a3745e6ac5a1be80 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_partial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_pipeline.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_pipeline.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b87c6dbc4ab6011a9b425601967e5825f7e9508 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_pipeline.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_storage.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_storage.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..609e9101b905520fc7042cccc85620c9e9c4131a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_storage.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ce351df6f76d040146ce2dae89f586539a00bbb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/__pycache__/test_utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..754f32bb97b80af4a1c785a8953e4386a91721d5 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/actions.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/actions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81856b91e6d5b524568eaabb89b19b7812a22535 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/actions.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_associate.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_associate.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbad766b5577b2474af0d8153756f13deae2301d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_associate.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_disconnect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_disconnect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92bc0368c4d98a70978d8ed908fa2cbad72ce947 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_disconnect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_login.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_login.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cac886cf1cbaf0dbfc1e2abf2fe5cf1f8e1cfc70 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/__pycache__/test_login.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/actions.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/actions.py new file mode 100644 index 0000000000000000000000000000000000000000..017b4adc3e446301f4ceea16038dd089750901da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/actions.py @@ -0,0 +1,230 @@ +import json +import unittest +from urllib.parse import urlparse + +import requests +from httpretty import HTTPretty + +from ...actions import do_auth, do_complete +from ...utils import module_member, parse_qs +from ..models import TestAssociation, TestNonce, TestStorage, TestUserSocialAuth, User +from ..strategy import TestStrategy + + +class BaseActionTest(unittest.TestCase): + user_data_url = "https://api.github.com/user" + login_redirect_url = "/success" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "login": "foobar", + "id": 1, + "avatar_url": "https://github.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def __init__(self, *args, **kwargs): + self.strategy = None + super().__init__(*args, **kwargs) + + def setUp(self): + HTTPretty.enable() + User.reset_cache() + TestUserSocialAuth.reset_cache() + TestNonce.reset_cache() + TestAssociation.reset_cache() + Backend = module_member("social_core.backends.github.GithubOAuth2") + self.strategy = self.strategy or TestStrategy(TestStorage) + self.backend = Backend(self.strategy, redirect_uri="/complete/github") + self.user = None + + def tearDown(self): + self.backend = None + self.strategy = None + self.user = None + User.reset_cache() + User.set_active(True) + TestUserSocialAuth.reset_cache() + TestNonce.reset_cache() + TestAssociation.reset_cache() + HTTPretty.disable() + + def do_login( + self, after_complete_checks=True, user_data_body=None, expected_username=None + ): + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_KEY": "a-key", + "SOCIAL_AUTH_GITHUB_SECRET": "a-secret-key", + "SOCIAL_AUTH_LOGIN_REDIRECT_URL": self.login_redirect_url, + "SOCIAL_AUTH_AUTHENTICATION_BACKENDS": ( + "social_core.backends.github.GithubOAuth2", + ), + } + ) + start_url = do_auth(self.backend).url + target_url = self.strategy.build_absolute_uri("/complete/github/?code=foobar") + + start_query = parse_qs(urlparse(start_url).query) + location_url = ( + target_url + + ("&" if "?" in target_url else "?") + + "state=" + + start_query["state"] + ) + location_query = parse_qs(urlparse(location_url).query) + + HTTPretty.register_uri( + HTTPretty.GET, start_url, status=301, location=location_url + ) + HTTPretty.register_uri(HTTPretty.GET, location_url, status=200, body="foobar") + + response = requests.get(start_url) + self.assertEqual(response.url, location_url) + self.assertEqual(response.text, "foobar") + + HTTPretty.register_uri( + HTTPretty.POST, + uri=self.backend.ACCESS_TOKEN_URL, + status=200, + body=self.access_token_body or "", + content_type="text/json", + ) + + if self.user_data_url: + user_data_body = user_data_body or self.user_data_body or "" + HTTPretty.register_uri( + HTTPretty.GET, + self.user_data_url, + body=user_data_body, + content_type="text/json", + ) + self.strategy.set_request_data(location_query, self.backend) + + def _login(backend, user, social_user): + backend.strategy.session_set("username", user.username) + + redirect = do_complete(self.backend, user=self.user, login=_login) + + if after_complete_checks: + self.assertEqual( + self.strategy.session_get("username"), + expected_username or self.expected_username, + ) + self.assertEqual(redirect.url, self.login_redirect_url) + return redirect + + def do_login_with_partial_pipeline(self, before_complete=None): + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_KEY": "a-key", + "SOCIAL_AUTH_GITHUB_SECRET": "a-secret-key", + "SOCIAL_AUTH_LOGIN_REDIRECT_URL": self.login_redirect_url, + "SOCIAL_AUTH_AUTHENTICATION_BACKENDS": ( + "social_core.backends.github.GithubOAuth2", + ), + "SOCIAL_AUTH_PIPELINE": ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.auth_allowed", + "social_core.tests.pipeline.ask_for_password", + "social_core.pipeline.social_auth.social_user", + "social_core.pipeline.user.get_username", + "social_core.pipeline.user.create_user", + "social_core.pipeline.social_auth.associate_user", + "social_core.pipeline.social_auth.load_extra_data", + "social_core.tests.pipeline.set_password", + "social_core.pipeline.user.user_details", + ), + } + ) + start_url = do_auth(self.backend).url + target_url = self.strategy.build_absolute_uri("/complete/github/?code=foobar") + + start_query = parse_qs(urlparse(start_url).query) + location_url = ( + target_url + + ("&" if "?" in target_url else "?") + + "state=" + + start_query["state"] + ) + location_query = parse_qs(urlparse(location_url).query) + + HTTPretty.register_uri( + HTTPretty.GET, start_url, status=301, location=location_url + ) + HTTPretty.register_uri(HTTPretty.GET, location_url, status=200, body="foobar") + + response = requests.get(start_url) + self.assertEqual(response.url, location_url) + self.assertEqual(response.text, "foobar") + + HTTPretty.register_uri( + HTTPretty.GET, + uri=self.backend.ACCESS_TOKEN_URL, + status=200, + body=self.access_token_body or "", + content_type="text/json", + ) + + if self.user_data_url: + HTTPretty.register_uri( + HTTPretty.GET, + self.user_data_url, + body=self.user_data_body or "", + content_type="text/json", + ) + self.strategy.set_request_data(location_query, self.backend) + + def _login(backend, user, social_user): + backend.strategy.session_set("username", user.username) + + redirect = do_complete(self.backend, user=self.user, login=_login) + url = self.strategy.build_absolute_uri("/password") + self.assertEqual(redirect.url, url) + HTTPretty.register_uri(HTTPretty.GET, redirect.url, status=200, body="foobar") + HTTPretty.register_uri(HTTPretty.POST, redirect.url, status=200) + + password = "foobar" + requests.get(url) + requests.post(url, data={"password": password}) + data = parse_qs(HTTPretty.last_request.body) + self.assertEqual(data["password"], password) + self.strategy.session_set("password", data["password"]) + + if before_complete: + before_complete() + redirect = do_complete(self.backend, user=self.user, login=_login) + self.assertEqual(self.strategy.session_get("username"), self.expected_username) + self.assertEqual(redirect.url, self.login_redirect_url) + + def _logout(self, backend): + backend.strategy.session_set("username", None) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_associate.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_associate.py new file mode 100644 index 0000000000000000000000000000000000000000..fa81ba6ad2837a94ac5b2bfdc2bbe4ba98806d56 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_associate.py @@ -0,0 +1,89 @@ +import json + +from ...exceptions import AuthAlreadyAssociated +from ..models import User +from .actions import BaseActionTest + + +class AssociateActionTest(BaseActionTest): + expected_username = "foobar" + + def setUp(self): + super().setUp() + self.user = User(username="foobar", email="foo@bar.com") + self.backend.strategy.session_set("username", self.user.username) + + def test_associate(self): + self.do_login() + self.assertTrue(len(self.user.social), 1) + self.assertEqual(self.user.social[0].provider, "github") + + def test_associate_with_partial_pipeline(self): + self.do_login_with_partial_pipeline() + self.assertEqual(len(self.user.social), 1) + self.assertEqual(self.user.social[0].provider, "github") + + +class MultipleAccountsTest(AssociateActionTest): + alternative_user_data_body = json.dumps( + { + "login": "foobar2", + "id": 2, + "avatar_url": "https://github.com/images/error/foobar2_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar2", + "name": "monalisa foobar2", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar2", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_multiple_social_accounts(self): + self.do_login() + self.do_login(user_data_body=self.alternative_user_data_body) + self.assertEqual(len(self.user.social), 2) + self.assertEqual(self.user.social[0].provider, "github") + self.assertEqual(self.user.social[1].provider, "github") + + +class AlreadyAssociatedErrorTest(BaseActionTest): + def setUp(self): + super().setUp() + self.user1 = User(username="foobar", email="foo@bar.com") + self.user = None + + def tearDown(self): + super().tearDown() + self.user1 = None + self.user = None + + def test_already_associated_error(self): + self.user = self.user1 + self.do_login() + self.user = User(username="foobar2", email="foo2@bar2.com") + with self.assertRaisesRegex( + AuthAlreadyAssociated, "This account is already in use." + ): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_disconnect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_disconnect.py new file mode 100644 index 0000000000000000000000000000000000000000..310407ded5821b227d1c4a42d381f8fb93bb1d82 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_disconnect.py @@ -0,0 +1,68 @@ +import requests +from httpretty import HTTPretty + +from ...actions import do_disconnect +from ...exceptions import NotAllowedToDisconnect +from ...utils import parse_qs +from ..models import TestUserSocialAuth, User +from .actions import BaseActionTest + + +class DisconnectActionTest(BaseActionTest): + def test_not_allowed_to_disconnect(self): + self.do_login() + user = User.get(self.expected_username) + with self.assertRaisesRegex( + NotAllowedToDisconnect, "This account is not allowed to be disconnected." + ): + do_disconnect(self.backend, user) + + def test_disconnect(self): + self.do_login() + user = User.get(self.expected_username) + user.password = "password" + do_disconnect(self.backend, user) + self.assertEqual(len(user.social), 0) + + def test_disconnect_with_association_id(self): + self.do_login() + user = User.get(self.expected_username) + user.password = "password" + association_id = user.social[0].id + second_usa = TestUserSocialAuth(user, user.social[0].provider, "uid2") + self.assertEqual(len(user.social), 2) + do_disconnect(self.backend, user, association_id) + self.assertEqual(len(user.social), 1) + self.assertEqual(user.social[0], second_usa) + + def test_disconnect_with_partial_pipeline(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_DISCONNECT_PIPELINE": ( + "social_core.tests.pipeline.ask_for_password", + "social_core.tests.pipeline.set_password", + "social_core.pipeline.disconnect.allowed_to_disconnect", + "social_core.pipeline.disconnect.get_entries", + "social_core.pipeline.disconnect.revoke_tokens", + "social_core.pipeline.disconnect.disconnect", + ) + } + ) + self.do_login() + user = User.get(self.expected_username) + redirect = do_disconnect(self.backend, user) + + url = self.strategy.build_absolute_uri("/password") + self.assertEqual(redirect.url, url) + HTTPretty.register_uri(HTTPretty.GET, redirect.url, status=200, body="foobar") + HTTPretty.register_uri(HTTPretty.POST, redirect.url, status=200) + + password = "foobar" + requests.get(url) + requests.post(url, data={"password": password}) + data = parse_qs(HTTPretty.last_request.body) + self.assertEqual(data["password"], password) + self.strategy.session_set("password", data["password"]) + + redirect = do_disconnect(self.backend, user) + self.assertEqual(len(user.social), 0) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_login.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_login.py new file mode 100644 index 0000000000000000000000000000000000000000..7a56549074207a3d651eec715ca8e5d168c8da4c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/actions/test_login.py @@ -0,0 +1,78 @@ +from ...utils import PARTIAL_TOKEN_SESSION_NAME +from ..models import User +from .actions import BaseActionTest + + +class LoginActionTest(BaseActionTest): + def test_login(self): + self.do_login() + + def test_login_with_partial_pipeline(self): + self.do_login_with_partial_pipeline() + + def test_fields_stored_in_session(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_FIELDS_STORED_IN_SESSION": ["foo", "bar"]} + ) + self.strategy.set_request_data({"foo": "1", "bar": "2"}, self.backend) + self.do_login() + self.assertEqual(self.strategy.session_get("foo"), "1") + self.assertEqual(self.strategy.session_get("bar"), "2") + + self._logout(self.backend) + # The _logout helper function doesn't clear the session. + self.assertEqual(self.strategy.session_get("foo"), "1") + self.assertEqual(self.strategy.session_get("bar"), "2") + + # Login again - without the 'bar' request param and make + # sure its value didn't persist in the session. + self.strategy.remove_from_request_data("bar") + self.strategy.set_request_data({"foo": "3"}, self.backend) + self.do_login() + self.assertEqual(self.strategy.session_get("foo"), "3") + self.assertEqual(self.strategy.session_get("bar"), None) + + def test_redirect_value(self): + self.strategy.set_request_data({"next": "/after-login"}, self.backend) + redirect = self.do_login(after_complete_checks=False) + self.assertEqual(redirect.url, "/after-login") + + def test_login_with_invalid_partial_pipeline(self): + def before_complete(): + partial_token = self.strategy.session_get(PARTIAL_TOKEN_SESSION_NAME) + partial = self.strategy.storage.partial.load(partial_token) + partial.data["backend"] = "foobar" + + self.do_login_with_partial_pipeline(before_complete) + + def test_new_user(self): + self.strategy.set_settings({"SOCIAL_AUTH_NEW_USER_REDIRECT_URL": "/new-user"}) + redirect = self.do_login(after_complete_checks=False) + self.assertEqual(redirect.url, "/new-user") + + def test_inactive_user(self): + self.strategy.set_settings({"SOCIAL_AUTH_INACTIVE_USER_URL": "/inactive"}) + User.set_active(False) + redirect = self.do_login(after_complete_checks=False) + self.assertEqual(redirect.url, "/inactive") + + def test_invalid_user(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_LOGIN_ERROR_URL": "/error", + "SOCIAL_AUTH_PIPELINE": ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.auth_allowed", + "social_core.pipeline.social_auth.social_user", + "social_core.pipeline.user.get_username", + "social_core.pipeline.user.create_user", + "social_core.pipeline.social_auth.associate_user", + "social_core.pipeline.social_auth.load_extra_data", + "social_core.pipeline.user.user_details", + "social_core.tests.pipeline.remove_user", + ), + } + ) + redirect = self.do_login(after_complete_checks=False) + self.assertEqual(redirect.url, "/error") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a90e19a61a6f2a029231126f0cb9c2e37b3ef76 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/base.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5058cac70eb04549b3ae27026da6ebab18fc03e7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/base.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/legacy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/legacy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ddd6ace2953413f03bda5deb26b91a8b10a04d88 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/legacy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/oauth.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/oauth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1b7971046554921dd96ab08ece63b74db249f27 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/oauth.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/open_id.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/open_id.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb1687747093b4f9d1573b00af6f2e4f11a47647 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/open_id.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_amazon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_amazon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1044e7980095f1aba3760bf87996c2d75531d3a2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_amazon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_angel.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_angel.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..315773dc7228db4c934c8a390788386657a102ae Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_angel.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_apple.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_apple.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e2da1c7d34197cba6918d9bd212404f240565c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_apple.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_arcgis.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_arcgis.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e731adb652d75fe766614ddb4e491c6691078c7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_arcgis.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_asana.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_asana.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2afd7dc77e1df9c47085b89a5ae883b37943c6e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_asana.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_atlassian.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_atlassian.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ffda9c37718ae9823fe14fcc5b5d27753d7dc0a9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_atlassian.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_auth0.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_auth0.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7638d7eb32144bf5fe17b5badddb931030ea5634 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_auth0.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e377276631b04ccb050aed69cead1de89fcf14f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread_b2c.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread_b2c.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74fe75614b561d4a8e56c93dff8c5481817680f9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_azuread_b2c.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_behance.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_behance.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7160501ea80ac2be22addc5a7497ebad7a9d0761 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_behance.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_bitbucket.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_bitbucket.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5268022b86ac26181082d5fb1469a7199f6948b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_bitbucket.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_box.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_box.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27622739e559aa46a567537f7c833c4e8f322981 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_box.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_broken.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_broken.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba2f7568d9ad8312c4251d2a79316b57be0311b1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_broken.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_chatwork.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_chatwork.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c13688752dcb5dd26212f56712228625a8961242 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_chatwork.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cilogon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cilogon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f643cc7fff2c480eec7519fe89f44f6eb1247b9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cilogon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_clef.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_clef.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f6f5783d090b7d7a4ff1f2afffe2d978bf1af79 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_clef.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cognito.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cognito.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7253079c1692246b8e5dd03fed110f2643e5b380 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_cognito.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coinbase.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coinbase.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7278d86ee2cf13ce7602e834632ff6d3d533d3b6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coinbase.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coursera.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coursera.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ca19bd7b2270a32e5bd6db556ae867086c927ec Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_coursera.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dailymotion.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dailymotion.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd13e94d49ed9e2a9251b5f6e19ef8df2fe19d60 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dailymotion.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_deezer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_deezer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39a625071376fd5a3a4b7b6647b7a9651c41cc43 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_deezer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_digitalocean.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_digitalocean.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bf8f866b57ac5e72184e5f9931c2c2c70fe2646 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_digitalocean.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_discourse.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_discourse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1990ca28f7164293fcdc825b3e56d97d78a13a41 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_discourse.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_disqus.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_disqus.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c22afd6f8fc5393ac1276d207fa9f5450952ba6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_disqus.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dribbble.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dribbble.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..71b0bb93d2352a80211d1137066f5156cfb2f391 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dribbble.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_drip.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_drip.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8bc78db317e7711de48b5944251234135f47d79b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_drip.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dropbox.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dropbox.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1683643b4e6310242a2afe15d050c764c3f2405a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dropbox.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dummy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dummy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cad3e2856090ca2ebf644f859c7837966990454f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_dummy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_edmodo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_edmodo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15fb67c03f60853225828380fb987297840a8858 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_edmodo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_elixir.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_elixir.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a52289f7c1d34a491f56b9f8637ac0623a0320d3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_elixir.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_email.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_email.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0800c32af5d6d5f99f9d42b61a3ec555dbfdc0d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_email.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_eventbrite.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_eventbrite.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50946097127ead82ec0923d9fc4ca212f42e6ce6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_eventbrite.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_evernote.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_evernote.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1935ff7d91c5db58ced6b888ffe80ad96e4586c8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_evernote.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_facebook.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_facebook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e596f4b55c31ce485a33715cdb3e285017576272 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_facebook.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fence.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fence.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bf2e6385bc298d6d45a3076eb7db4117fe1dc93 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fence.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fitbit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fitbit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa0854b7f3d436d42b9e334a09a2c16738dbe8f2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_fitbit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_five_hundred_px.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_five_hundred_px.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c54028f5b501674d71f387bd5a78dcbeef196529 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_five_hundred_px.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3cb153eb0b8bbfbd8cd93655819d6bcc0ace367 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flickr.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flickr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..276b99ca48a83cb21913fad4f69a6d87647e9fb1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_flickr.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_foursquare.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_foursquare.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cf69f9fdd428c5f0d87084963310d26dccff083 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_foursquare.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitea.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitea.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67e6d19d77fa79920e34e8ca6425664636018331 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitea.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c20b25d8451aae013eab9891f9c50e4c127897a6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github_enterprise.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github_enterprise.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a30fce956ae5bf90135cfa5fd6f06b4090038f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_github_enterprise.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitlab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitlab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4b91f340f5e2216d3f87e92be28b5449a30ce0c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_gitlab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_globus.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_globus.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e76919ebe42785ab09f2b8dbf924d744c7283a30 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_globus.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_google.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_google.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76af838e901530dfb3df4a0a44a9f1b38569ad1d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_google.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_grafana.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_grafana.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba9f0b6cb80b205b3a617a50e862977b951a5628 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_grafana.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_instagram.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_instagram.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..309e5fa790340daba59b71bfa0955eaa5cdb6c1c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_instagram.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_itembase.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_itembase.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfe0b1333fef4f4cfe920b86e142b42f12f58345 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_itembase.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_kakao.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_kakao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d19f6242f525d2fa62931f2314b775f7798303ad Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_kakao.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_keycloak.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_keycloak.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b11263391704300e30c034b39c09961ac554e5b4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_keycloak.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_khanacademy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_khanacademy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cdf6af8c120684cc4dd295922730aaf0042e6171 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_khanacademy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_linkedin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_linkedin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f82131a7359582e8f086e5a64eae7af0ee1a7c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_linkedin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_live.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_live.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c208e2dfffad962d378f6c0bbf548bae17829e2e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_live.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_livejournal.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_livejournal.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51d2e9cd9db98aa925ebb0d438af17d040d21bb0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_livejournal.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_lyft.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_lyft.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..834f217ad67ff0c08499cf89bd7616c0d31cccb0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_lyft.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mailru.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mailru.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88bddada957d1a6c75829c507ee9242fd9cc1162 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mailru.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mapmyfitness.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mapmyfitness.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bf7078d4a969bb8b3ea679685a463a9b91a92ce Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mapmyfitness.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_microsoft.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_microsoft.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d55fd4a184c924d40c65b6979704eb24eb3f7b0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_microsoft.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mineid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mineid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7d0304d5b4f06f01b5a6a44c2b756e4e7451dda Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mineid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mixcloud.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mixcloud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa29c914ceafb49f71eea579f8385c4e009d7330 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_mixcloud.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_musicbrainz.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_musicbrainz.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfbec74c4fc93ed4b5a6d04b5b3a268c1f672f48 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_musicbrainz.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_nationbuilder.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_nationbuilder.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..937b5c92c4a89fa3392cb1e48f4ec1cb5d4f8d4f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_nationbuilder.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_naver.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_naver.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ccc5259ce0b9ab82fb4947fb5ba2d47b49e5517 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_naver.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_ngpvan.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_ngpvan.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6752ae12442c093efdab1cd90d83e33dbf8fe7ef Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_ngpvan.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_okta.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_okta.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8a99bf9841dbc4b56fecc035f0147959059747a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_okta.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_open_id_connect.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_open_id_connect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60953c8b2a8d72bbde8ea2365c61d3e770762abd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_open_id_connect.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orbi.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orbi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8123e3816a48704ffd965e56ccafe8eb17774da3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orbi.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orcid.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orcid.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d828ae3f22a14ff37cf75b25088e8b484a881d4b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_orcid.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_osso.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_osso.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c31906053b2fa36a87970f7eecd22090252adf3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_osso.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_patreon.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_patreon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46e54a24430506b711ff81160cf93255d3a4d6c1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_patreon.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_paypal.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_paypal.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0dab3127721b5f78fb3e67128728beaf6b431527 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_paypal.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_phabricator.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_phabricator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a7ce8829e8c669e8f348b2ecc2ab20aa42bee54 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_phabricator.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_pinterest.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_pinterest.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b182cc8a77ecf0d296aa1f72c8c87ab3dfad9e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_pinterest.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_podio.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_podio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50a3cb8955497c817c1554a176f47fd909f372f8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_podio.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_qiita.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_qiita.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1201c59dd29f747ce5a8d8e41bbcbfbc052a37c4 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_qiita.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_quizlet.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_quizlet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb25f39e9b0edc5038c2856bea9147dabbfb4f76 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_quizlet.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_readability.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_readability.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56d8e6612db72296d6f5e2a80b38e51368fce93b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_readability.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_reddit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_reddit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dec394ddf2b7cf11dd0adf92fd2438f6d395a062 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_reddit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_saml.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_saml.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28b35d754ca2a7166622afb8a1cfc0b9184f9fed Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_saml.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_scistarter.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_scistarter.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d283c3685a7fb471ec8a35b735b641e640e2cff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_scistarter.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_seznam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_seznam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..541ba50e98bd70ce3fbf658ffc2a697c3a66af9a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_seznam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_simplelogin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_simplelogin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdbd2e4b272b412092b50c65e11d09bddd1f294e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_simplelogin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_sketchfab.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_sketchfab.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d284a5dace14bf2ff3d6105d097fef435f34ae73 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_sketchfab.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_skyrock.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_skyrock.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3063dec268220a80fe0a458010dc83278291990 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_skyrock.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_slack.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_slack.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e2350a4eaa253932a9e39253d5e23e14211a050 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_slack.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_soundcloud.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_soundcloud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6550519196a50b19e94ec2551cef477499994f6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_soundcloud.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_spotify.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_spotify.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa5cbc528d1b244863e9cc5e6616a3f99e7f4698 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_spotify.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stackoverflow.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stackoverflow.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a59f1f143dc1f6adaaaba6bb68ce9008a3da0ea Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stackoverflow.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_steam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_steam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cffeb94c3e7b86425fe52ad4fd317fc6b41db7b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_steam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stocktwits.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stocktwits.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1a3858b22ec0f61d725304c12e65463a12aa2d8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stocktwits.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_strava.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_strava.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70740a4293a3b9d1525a250988765f62e457409c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_strava.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stripe.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stripe.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c286957a01ce1463eb476bbdef0a0b2270527ff Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_stripe.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_taobao.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_taobao.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51ec97704f87ec3c12e53bdbfc4a92d8f5bb6d64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_taobao.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_thisismyjam.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_thisismyjam.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a243867a88796bc05c1ef1b7cc7d5bfe5f73da0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_thisismyjam.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tripit.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tripit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfb9f6393621e759f79d92085fe3e7553998cd64 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tripit.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tumblr.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tumblr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40a318052361a786cc42ddf4332e226f309a386d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_tumblr.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitch.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitch.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..127d41371b3a4cd0084e40f828c5cbe12a615183 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitch.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitter.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitter.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b60775689a7737d128c1c25bcaf4b193a6cc80c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_twitter.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_uber.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_uber.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0ca8c798975274e9931ddd82660b30c4ddbc1f2 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_uber.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_udata.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_udata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1e2b7bea9224ae89d090e96901a103bfcc29762 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_udata.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_universe.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_universe.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..829eaacd2ec61dae0abd977151235b3e855477c0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_universe.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_upwork.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_upwork.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20eb8e2f98942813ea1dd32aef8146e80161f783 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_upwork.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_username.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_username.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a8af928377c84ad183cedac9aac2a4020d87714 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_username.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..716e7e2e114d633ab8de02970060faccc087090c Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vault.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vault.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1112b2176bd6cdcc669b20a32f2d230fe27a951 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vault.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vk.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vk.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d044a90d16d69ac581d1d40aa147c6f9069c6e78 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_vk.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_wunderlist.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_wunderlist.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86092adc806910dc3ed6f919596dca80c3c16cfe Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_wunderlist.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_xing.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_xing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..673638badcddbcac8b8d00541e151c2acacc30d8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_xing.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yahoo.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yahoo.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e1e65f4972b0d8f45b0f6ccea9937ec62ab4908 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yahoo.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yammer.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yammer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7c0ec8ce17552bf4e7df200fd99fb2689802846 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yammer.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yandex.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yandex.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5bdcda597ee729fbe2a527b11ac673d5e8008e0 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_yandex.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zoom.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zoom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9ca854f103d659ba152192188beeb8239d21423 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zoom.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zotero.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zotero.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09d9cf56d0e23e6581e9ce339871497dc884a060 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/__pycache__/test_zotero.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/base.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/base.py new file mode 100644 index 0000000000000000000000000000000000000000..c64a70c11bdaa6e7995b790837f4546742983986 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/base.py @@ -0,0 +1,161 @@ +import unittest + +import requests +from httpretty import HTTPretty + +from ...backends.utils import load_backends, user_backends_data +from ...utils import PARTIAL_TOKEN_SESSION_NAME, module_member, parse_qs +from ..models import ( + TestAssociation, + TestCode, + TestNonce, + TestStorage, + TestUserSocialAuth, + User, +) +from ..strategy import TestStrategy + + +class BaseBackendTest(unittest.TestCase): + backend = None + backend_path = None + name = None + complete_url = "" + raw_complete_url = "/complete/{0}" + + def setUp(self): + HTTPretty.enable(allow_net_connect=False) + Backend = module_member(self.backend_path) + self.strategy = TestStrategy(TestStorage) + self.backend = Backend(self.strategy, redirect_uri=self.complete_url) + self.name = self.backend.name.upper().replace("-", "_") + self.complete_url = self.strategy.build_absolute_uri( + self.raw_complete_url.format(self.backend.name) + ) + backends = ( + self.backend_path, + "social_core.tests.backends.test_broken.BrokenBackendAuth", + ) + self.strategy.set_settings({"SOCIAL_AUTH_AUTHENTICATION_BACKENDS": backends}) + self.strategy.set_settings(self.extra_settings()) + # Force backends loading to trash PSA cache + load_backends(backends, force_load=True) + User.reset_cache() + TestUserSocialAuth.reset_cache() + TestNonce.reset_cache() + TestAssociation.reset_cache() + TestCode.reset_cache() + + def tearDown(self): + HTTPretty.disable() + HTTPretty.reset() + self.backend = None + self.strategy = None + self.name = None + self.complete_url = None + User.reset_cache() + TestUserSocialAuth.reset_cache() + TestNonce.reset_cache() + TestAssociation.reset_cache() + TestCode.reset_cache() + + def extra_settings(self): + return {} + + def do_start(self): + raise NotImplementedError("Implement in subclass") + + def do_login(self): + user = self.do_start() + username = self.expected_username + self.assertEqual(user.username, username) + self.assertEqual(self.strategy.session_get("username"), username) + self.assertEqual(self.strategy.get_user(user.id), user) + self.assertEqual(self.backend.get_user(user.id), user) + user_backends = user_backends_data( + user, + self.strategy.get_setting("SOCIAL_AUTH_AUTHENTICATION_BACKENDS"), + self.strategy.storage, + ) + self.assertEqual(len(list(user_backends.keys())), 3) + self.assertEqual("associated" in user_backends, True) + self.assertEqual("not_associated" in user_backends, True) + self.assertEqual("backends" in user_backends, True) + self.assertEqual(len(user_backends["associated"]), 1) + self.assertEqual(len(user_backends["not_associated"]), 1) + self.assertEqual(len(user_backends["backends"]), 2) + return user + + def pipeline_settings(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_PIPELINE": ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.auth_allowed", + "social_core.tests.pipeline.ask_for_password", + "social_core.tests.pipeline.ask_for_slug", + "social_core.pipeline.social_auth.social_user", + "social_core.pipeline.user.get_username", + "social_core.pipeline.social_auth.associate_by_email", + "social_core.pipeline.user.create_user", + "social_core.pipeline.social_auth.associate_user", + "social_core.pipeline.social_auth.load_extra_data", + "social_core.tests.pipeline.set_password", + "social_core.tests.pipeline.set_slug", + "social_core.pipeline.user.user_details", + ) + } + ) + + def pipeline_handlers(self, url): + HTTPretty.register_uri(HTTPretty.GET, url, status=200, body="foobar") + HTTPretty.register_uri(HTTPretty.POST, url, status=200) + + def pipeline_password_handling(self, url): + password = "foobar" + requests.get(url) + requests.post(url, data={"password": password}) + + data = parse_qs(HTTPretty.last_request.body) + self.assertEqual(data["password"], password) + self.strategy.session_set("password", data["password"]) + return password + + def pipeline_slug_handling(self, url): + slug = "foo-bar" + requests.get(url) + requests.post(url, data={"slug": slug}) + + data = parse_qs(HTTPretty.last_request.body) + self.assertEqual(data["slug"], slug) + self.strategy.session_set("slug", data["slug"]) + return slug + + def do_partial_pipeline(self): + url = self.strategy.build_absolute_uri("/password") + self.pipeline_settings() + redirect = self.do_start() + self.assertEqual(redirect.url, url) + self.pipeline_handlers(url) + + password = self.pipeline_password_handling(url) + token = self.strategy.session_pop(PARTIAL_TOKEN_SESSION_NAME) + partial = self.strategy.partial_load(token) + self.assertEqual(partial.backend, self.backend.name) + redirect = self.backend.continue_pipeline(partial) + + url = self.strategy.build_absolute_uri("/slug") + self.assertEqual(redirect.url, url) + self.pipeline_handlers(url) + slug = self.pipeline_slug_handling(url) + + token = self.strategy.session_pop(PARTIAL_TOKEN_SESSION_NAME) + partial = self.strategy.partial_load(token) + self.assertEqual(partial.backend, self.backend.name) + user = self.backend.continue_pipeline(partial) + + self.assertEqual(user.username, self.expected_username) + self.assertEqual(user.slug, slug) + self.assertEqual(user.password, password) + return user diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_config.json b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_config.json new file mode 100644 index 0000000000000000000000000000000000000000..3f610107c771a93f51add8540ec3fda3cba3ac8f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_config.json @@ -0,0 +1,23 @@ +{ + "SOCIAL_AUTH_SAML_SP_ENTITY_ID": "https://github.com/omab/python-social-auth/saml-test", + "SOCIAL_AUTH_SAML_SP_PUBLIC_CERT": "MIICsDCCAhmgAwIBAgIJAO7BwdjDZcUWMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNBMRkwFwYDVQQIExBCcml0aXNoIENvbHVtYmlhMRswGQYDVQQKExJweXRob24tc29jaWFsLWF1dGgwHhcNMTUwNTA4MDc1ODQ2WhcNMjUwNTA3MDc1ODQ2WjBFMQswCQYDVQQGEwJDQTEZMBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTEbMBkGA1UEChMScHl0aG9uLXNvY2lhbC1hdXRoMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq3g1Cl+3uR5vCnN4HbgjTg+m3nHhteEMyb++ycZYre2bxUfsshER6x33l23tHckRYwm7MdBbrp3LrVoiOCdPblTml1IhEPTCwKMhBKvvWqTvgfcSSnRzAWkLlQYSusayyZK4n9qcYkV5MFni1rbjx+Mr5aOEmb5u33amMKLwSTwIDAQABo4GnMIGkMB0GA1UdDgQWBBRRiBR6zS66fKVokp0yJHbgv3RYmjB1BgNVHSMEbjBsgBRRiBR6zS66fKVokp0yJHbgv3RYmqFJpEcwRTELMAkGA1UEBhMCQ0ExGTAXBgNVBAgTEEJyaXRpc2ggQ29sdW1iaWExGzAZBgNVBAoTEnB5dGhvbi1zb2NpYWwtYXV0aIIJAO7BwdjDZcUWMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJwsMU3YSaybVjuJ8US0fUhlPOlM40QFCGL4vB3TEbb24Mq8HrjUwrU0JFPGls9a2OYzN2B3e35NorMuxs+grGtr2yP6LvuX+nV6A93wb4ooGHoGfC7VLlyxSSns937SS5R1pzQ4gWzZma2KGWKICWph5zQ0ARVhL63967mGLmoI=", + "SOCIAL_AUTH_SAML_SP_PRIVATE_KEY": "MIICXgIBAAKBgQCq3g1Cl+3uR5vCnN4HbgjTg+m3nHhteEMyb++ycZYre2bxUfsshER6x33l23tHckRYwm7MdBbrp3LrVoiOCdPblTml1IhEPTCwKMhBKvvWqTvgfcSSnRzAWkLlQYSusayyZK4n9qcYkV5MFni1rbjx+Mr5aOEmb5u33amMKLwSTwIDAQABAoGBAIHAg6NJSiYC/NYpVzWfKlasuoNy78R5adXYSNZiCR5V5FNm5OzmODZgXUt6g0A7FomshIT/txQWoV7y5FmwPs8n13JY3Hdt4tJ6MHw2feLo710+OEp9VBQus3JsB2F8ONYrGvs00hPPL7h5av/rzTdE8F67YM1mSgeg7xEF6BghAkEA12OOqSzp2MLTNY7PqOaLDzy4aAMVNN3Ntv2jBN0jq7s1b5ilQ2PGkLwdtkicq/VZcRyUqVbZbMwz05II3nqx3wJBAMsVhRQ5sdFCRBzEbSAm2YEJaFh5u6QT3+zWHMFpPJRnaBAWz3RXKEnleJ+DS2Xz1Jm6ZrmLdZiwMx/8dK5rDZECQQC7GTdWi7ZC3dIcpwaKIGHRhZxmda8ZMkc9Wwwd8H7I8aFUZFPCu0xEc7SXoHHACit8zyfwBYpvMN8gPK3JnOkfAkEAsUSpk0wBMT38one7IZOHzCDgGkq4RbKrhdon45Pus0PIDDM9BrqFimtpbSN4DxhVfZK91DwtfAhhuAvv9cewYQJAPMhpAqv3PBGYmtRDUlWXJQv2JRJJkrvbbqgBed2OX5RRgj5V3SR6PBhLbcTZ+q+1tdPkMFzZo5U6MN5m/6oXvQ==", + "SOCIAL_AUTH_SAML_ORG_INFO": { + "en-US": {"name": "psa", "displayname": "PSA", "url": "https://github.com/omab/python-social-auth/"} + }, + "SOCIAL_AUTH_SAML_TECHNICAL_CONTACT": + {"givenName": "Tech Gal", "emailAddress": "technical@example.com"}, + "SOCIAL_AUTH_SAML_SUPPORT_CONTACT": + {"givenName": "Support Guy", "emailAddress": "support@example.com"}, + "SOCIAL_AUTH_SAML_ENABLED_IDPS": { + "testshib": { + "entity_id": "https://idp.testshib.org/idp/shibboleth", + "url": "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO", + "x509cert": "MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA==" + }, + "other": { + "entity_id": "https://unused.saml.example.com", + "url": "https://unused.saml.example.com/SAML2/Redirect/SSO" + } + } +} diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_response.txt b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_response.txt new file mode 100644 index 0000000000000000000000000000000000000000..557bb59e89ff91389a0d0c8e7d859556e6dfc24e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/data/saml_response.txt @@ -0,0 +1 @@ +http://myapp.com/?RelayState=testshib&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL215YXBwLmNvbSIgSUQ9Il8yNTk2NTFlOTY3ZGIwOGZjYTQ4MjdkODI3YWY1M2RkMCIgSW5SZXNwb25zZVRvPSJURVNUX0lEIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMDUtMDlUMDM6NTc6NDMuNzkyWiIgVmVyc2lvbj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI%2BaHR0cHM6Ly9pZHAudGVzdHNoaWIub3JnL2lkcC9zaGliYm9sZXRoPC9zYW1sMjpJc3N1ZXI%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkVuY3J5cHRlZEFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHhlbmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiIElkPSJfMGM0NzYzNzIyOWFkNmEzMTY1OGU0MDc2ZDNlYzBmNmQiIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNhZXMxMjgtY2JjIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiLz48ZHM6S2V5SW5mbyB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPHhlbmM6RW5jcnlwdGVkS2V5IElkPSJfYjZmNmU2YWZjMzYyNGI3NmM1N2JmOWZhODA5YzAzNmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1nZjFwIiB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyMiPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiLz48L3hlbmM6RW5jcnlwdGlvbk1ldGhvZD48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE%2BPGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDc0RDQ0FobWdBd0lCQWdJSkFPN0J3ZGpEWmNVV01BMEdDU3FHU0liM0RRRUJCUVVBTUVVeEN6QUpCZ05WQkFZVEFrTkJNUmt3CkZ3WURWUVFJRXhCQ2NtbDBhWE5vSUVOdmJIVnRZbWxoTVJzd0dRWURWUVFLRXhKd2VYUm9iMjR0YzI5amFXRnNMV0YxZEdnd0hoY04KTVRVd05UQTRNRGMxT0RRMldoY05NalV3TlRBM01EYzFPRFEyV2pCRk1Rc3dDUVlEVlFRR0V3SkRRVEVaTUJjR0ExVUVDQk1RUW5KcApkR2x6YUNCRGIyeDFiV0pwWVRFYk1Ca0dBMVVFQ2hNU2NIbDBhRzl1TFhOdlkybGhiQzFoZFhSb01JR2ZNQTBHQ1NxR1NJYjNEUUVCCkFRVUFBNEdOQURDQmlRS0JnUUNxM2cxQ2wrM3VSNXZDbk40SGJnalRnK20zbkhodGVFTXliKyt5Y1pZcmUyYnhVZnNzaEVSNngzM2wKMjN0SGNrUll3bTdNZEJicnAzTHJWb2lPQ2RQYmxUbWwxSWhFUFRDd0tNaEJLdnZXcVR2Z2ZjU1NuUnpBV2tMbFFZU3VzYXl5Wks0bgo5cWNZa1Y1TUZuaTFyYmp4K01yNWFPRW1iNXUzM2FtTUtMd1NUd0lEQVFBQm80R25NSUdrTUIwR0ExVWREZ1FXQkJSUmlCUjZ6UzY2CmZLVm9rcDB5SkhiZ3YzUlltakIxQmdOVkhTTUViakJzZ0JSUmlCUjZ6UzY2ZktWb2twMHlKSGJndjNSWW1xRkpwRWN3UlRFTE1Ba0cKQTFVRUJoTUNRMEV4R1RBWEJnTlZCQWdURUVKeWFYUnBjMmdnUTI5c2RXMWlhV0V4R3pBWkJnTlZCQW9URW5CNWRHaHZiaTF6YjJOcApZV3d0WVhWMGFJSUpBTzdCd2RqRFpjVVdNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUp3c01VM1lTCmF5YlZqdUo4VVMwZlVobFBPbE00MFFGQ0dMNHZCM1RFYmIyNE1xOEhyalV3clUwSkZQR2xzOWEyT1l6TjJCM2UzNU5vck11eHMrZ3IKR3RyMnlQNkx2dVgrblY2QTkzd2I0b29HSG9HZkM3VkxseXhTU25zOTM3U1M1UjFwelE0Z1d6Wm1hMktHV0tJQ1dwaDV6UTBBUlZoTAo2Mzk2N21HTG1vST08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BTElQdkVNVUVGeXhrVHowQ2N4QVA5TjV4Y3NYT2V4aVV4cXBvR2VIeVFMV0R5RVBBUDVnZ1daL3NLZ1ViL2xWSk92bCtuQXhSdVhXUlc5dGxSWWx3R2orRVhIOWhIbmdEY1BWMDNqSUJMQnFJbElBL1RmMGw4cVliOHFKRy9ZM0RTS2RQNkwvUURtYXBtTXpFM29YOEJxMW5Ea3YrUWh4cmQwMGVGK2ZMYVQ0PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHM6S2V5SW5mbz48eGVuYzpDaXBoZXJEYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPHhlbmM6Q2lwaGVyVmFsdWU%2BRVpUWDhHTkM0My9yWStTUVlBMXRudHlUTTVVNkN2dUNCaktsVEVlekZPRjBZZHhCWUdFQVVjYU8xNVNKOXBMemJ1L1h0WGxzTkVMZTdKdEx4RUpwYUxubWFENnIranNWczdLaTBLNHRTMGNBUERDWHV2R1FoMmFOVjVQOGJ3N1JWUGhLOGQwYlJ1RklGR09FOHMwTTZYOUpxWDN4S0MvL1lSbVVoeDlybnU3ZWlwMGh5ZitPaUZiVGR2SDY2NTB2LzQ3aVdKcDNZeFlUV0QyMHBNbVRJMUpwWUEwYjByWVFQRkR0RU93d0JxYktxanRJc3ZYVFJzeXJhQkxvbnFOeHN5dHpEWHEra0JsMXp3WGUvSE5QcUVQblczdnNxaFhZcDVGM3dkWThkKzNCOTRMZlpOdUd4a0p3VDNzdVR0OGY5VHRBSlI4VytBUmtzT2M4eDBVaVNsVG5BNHFHOTBLMTR5dkVoVHcvd2drZjFXV01RT3dpZDNpakFYbUV4MU5MbVZvYUxYb3p4VExkTjN6YnJ6VEJIRXc3R2J3ZEdrdU5pMlhZOW16YUgwaWtGRm51VUxjMHUwc0pycEdGdzlaK0VlUk44RzNVUVZ5MjhtS2g3ZFBwWU5KbzhyajIxZFFaK2JaeUtTUHZablU3REkyakdJRE5US1g2ZkVyVWFINGlOTzN4cUU2Vk90L2d4T3BMNE5VNUhLV0Q0bG93VzcwdUJjVEVQRmhwaThpYUovdTB6YzUvTEhvdVBjMzByc1RLZFc5cmJLL2NWaHNQUHErZzA5WHZpZ0QweTJvN2tOc1pVL25tRXFiSzBKOTBrazhCR3I5cXRSczY4bUJnSURtUHVwUkhwWjM4eXNnU2VZN3V0VlVaSG5tQ0dzTzZ2NDJ6OTVOK05Pb3RCTEVZbFd1ZEdzYnowQWc4VkRDSlY5ak95QW95MDZyL1AyUHBsOFhjdmJza2d2T1BMMWdDNnVYbVJJS1lmOEw4UDJCNXVjN0haK0dtUHNOWXRLS2VKRDFFUHovdCt2NlBIbXNVb3dsSDhSd3FMRHdtMUF4dlNLQTR3UXBlQ0dQd3A5YXRYS0lWMS84NUZzRWMzajVzNjd6VlRybThrVEpydXV2MDZEdFVRZDNMOFdwTkV4cWhQait6RUp6U3RxSG04ckhNMVhNQUVxdVozc0xycTVqLzFSNlpqS0dOdFJCbjhwOE5ERGtrWm0vWTV5TXlJNXJJS3U5bnA3bXdaaEVpeWVHeHdxblV3VVMvUzVDRjNnMHVidnd4eVVnalVvd1ZvTkNqYktBbkdtT2VCSW5abkh0eGdIVUhVOUVlTFdyd2pRc3JtUmpJV0R2RkZQa3l6SzJDL20yaitubmNxc2E1OGRLVXZxcGR1VTRJYnNPQng3UGpXdXRBNmY5bXd6YWxyRU1NK0lGR3VPdk9HMC93eUdzQjZLREV6bldjUC83NkQ4angzaHZFSlAzN3REbFgreGM4Qno5TXdKdkd6VG4xbTdCb2xoR0lzSXlCTys1ZXpXa3RDWVVIUURGVE9wbXA0MDlOWHp6ZUNTUGY1U2NDWG5YYjRPd01ULy9VM1JFUnRRbGMrNmU2WG1JRjhoRkJVc0taUUJsS2ppSDkwZHlzYWlsNmN2V3UyQW55Q3QxbWxXcHFLc0MzU2RTRVZDTG1qRjlUQUFUMEtFSGdZQjg3RjZtZUpTTysvOXkyZkRuYVVvUUlUVzdubnVuSCtkT3dWSGZMU0wyL2N5YTltNlQzR29TSVNMbGJPMVRzalhKclVkZW55OTcvM2tkNmhFQlphdGY1U3NETFQ3SjNsQUVJNDROeXJ0NkIxQWdod2JNdkpqd1JNTXRNdUJLc3ltUytKVzc4UFNEWXQ4MG9waDJQTTc1N0tBNCtUMTAvYnZaQkE5Vk1OdVpqNVV3NXRWMnFIS3dwS0t6ZVVETUFiQlBRaGpYcXlQZzFKa09rd2RQMUpnOHRITjJTelBZQTlmT1htV0pBZGJDS2tMb0F4ZTV6cDZBUzYzS3FXMmFmSUt6SHJ3RTJmS1VtamppeURvMnNuMkJHbWtBaTRzbnpiVzc2SUQvSVgwd044aDBaQ2VRc29vKzdtb1RCMEJxSnBkS1MycXlsUktoc3BSTC9henVQdmxaK1pwckJxdXpJdEZkNFVLMkpzQkp6VXcwZkpxcTV1bk9PZENzVWM3SUU3QTNmZ1NmZ3NBd1R3WFZJMEVoME5ySWZpMkFKV1Z2VFpEMys2eFZ3dS96WWhuVjc0VXkvMFE4Mi8yQWtpSGpFRjNJVGNLWHdTNTB6bWtLakxjZDJqa2h5TUFYMWRoQ0wwZElFMUJoN0RNamVvNC9YbjBqSlpPL3Rrbi9xZmYzc3RNb1BYVG9KTnBIU1RjR2ZheGtaMzJYNCt3Q0xPc0VBRWxlMVZSY0kwUkZyOFhHTSsxWU9BTjBodFdGcFMxaG9kSi9OczJqL1FnUVNEemNpQ1FZeUFDd3lFRWZDZjZybnR0VmJyTlJQZWlmSHhBM3B2UnZ5ZGRhNDE5cXl0ZXI0akJ3cmw3ZUpuVnJ2VEprR2VhU2FRbDdXWk5SQXBscXRnNnZPYmpiMHZDRWlFaFhKbmNzQUhxcXp5QTRGeWFUVGQ2R0FySU9adUNxRWVoWk51T01lOVlrMVpya0VkR3pIalJESWk3Q1BKQk12NEZ4ZHI3bnJvN0I1WEhKb0ZMNE1DSUtOWWU2aWZiTUtYOU5uN1FWdnphUmY2UXlaSW1BWENQZndvU1BkN2x6NXl3UDJLSUIyaGhFMWt5eVZ5YVc5T0praWpUY3dvUnZrSXhIU0RqMXFqeGxueXh0QzhVZ1pNWmlwcGgzQXJpcjRiekIzUDhIbGIzejZ0OW51KzZMemNiN2ZObVo0UHluaU50Vk9OQ0lHbEh4dTBSY3hQK3cwUXNsM1BtTzJLaHBpc2RIanhvSUJ1YVY1NXdoTlFFNmdNNFBrT0xINDc4Rzg4bUxkd2s2RFpkWVl4L2d6RWE3b3ZIL0pReFp2TzRLdFVTNmZjZHJxV2thTFg1cEhkNkdneFBGZ2NFc2Nad1ZqM2hCS0xFQmE5L0dodERINEhzRnNRbmpPZnNDQkNzN0tjRitmTi9oSUdUeHFqTVlKVHJRYmNtdWF5dk9xR3RQMDFPcXltR24rVm5FSVkzKytQcm95SFN3K0Q0b0JIVG1maFNXRmJLZCtuTlVFS3BhRVIxNkdCU256WktQRVRVSmdRWEw5QWJRQ3RXVjFHb0UzRWNnMDZYaVd2aHFHakpGNldtdEU4dHY4Q25rZmxMNm91TDRvNldpbmx2WnNEdkZrS0R6TDkwUTNsWC9NanBtRTFpWU9uYzdISXdEVGwraFRRcHdsYXJiTDVUNGNkZTg1akNwYU0xU3p1TStiQU5zMHlXVDA0ZXJUVFc2cnhlbXFDTHAra202TVVMTlZOcE1CazBiQjJpRU82UlRtc3VpRlhDUU1xdU5xZjdkWXUwTFFCZzQ0MkJzU1pBV1ZrWEVZblduOURLdTRSby8veEFsb2h5VHozWlZmSkhuWVBSdDloSUErRHVUL3c4T2ZzTURIWnlCelUvL0JEa1NiNkxjMHdraVA3QlhIdjBoNVdud2dNWUxlZDBPalR5UWI2aGxpVnQ5b0FjaDRFVy9EZUlBdkpaQ1BYVm1pUFFYTGVsOVJIRko2bXFiYVo0TCtaZG1ONmQwcFZNZ1FveXhmQTR3dEwwYVpiNnFZYkhibjJMd2VBQVZwL3M2TzVlMVExdnZpZDRTWHo0a2l3RW1LSStIeXZEQ1pnekpQQVN5Z1gvWDJFWEZ0NGV3SjVmUFQyVXZmWnhQWlpqMFZGSFpyUFQwWVd2VE16bjUva3hoT09oM2drVGdDSmNwNWVsZnp4cEFPNFl1a0NoNHJXdVNndDRqVUJyaWNYbFdWdWo5U3JSZVhUalNHTktLK202NWovUDllNHRHT0RkMk9BbjNKTVQ3Q3FuaDhreTZpZjVjbmpVMmU3UDhTZnBONGwxWEFiZEZEcGk5bVJYamEyTzR1RWFHNGNvNW4xcWNDT3ZNMWYyblFBY1ZGNUFoSXhueS96TWhmU2l2RXdOQ0Zyd2tBWDRyQVE0WldUNldFakFyUG5jb1Y4Z1VRclhxQVA4NDJmK1lNWWI5RHFncmFicEg1a3ZuMnQzcWRldGJHODJ0QWlTamhPcUxNYW9iU2F4cXdWa1lUOHRTMW9rUUt2MWZoZ2t6elpEOE5IQnVQQzdNVHdXS0VCS2tDRUUzRWRFMXhNQURLd1B1M3NSaGpSaExXZyszZ2srejJtdlU4cTBhTlc0Y3hObUdoekx4eEY0Q3NFNStMQ1cwOWFpUVJOM1VvWmg1aktBZzBiMlh3WHBLS3pycUVTY1BYdnI0L1dWUTMyMm5qRWRvQVdXR0t2WnBKMlRlREo0eDdiT21LVElFc2RHWU1UZzFVaEU2eFFQcnhqS3dWeGFJNVJyaVE4a0xpaGgwa0t0WHQvYTVsSDhzUjVwR0ZISGZ3dlNVb3liQTB1eUVDNnNRVitPbTVReUZmRmpqZHFCOGNpOGxQS1hLTHFCTHJ6bjNmUkh3TmQwbzFiRTg0aGllTkx5UlhZVmhrRCtFNEpGaVd3ZWt3U3VWM3BjQk9ybnRVU3RoWmx6M3hIUURUVGNJNWliOFJyQ2swZEZ6YTgvQmw3VUdtWlUwSXZ2UmdvVXF2TXNHT2dMY3pGWmRpZnJ5aGNiUTY4a2ZzZ3lCMHppdC9MN1BSV3V4RkdYdDFoTVZSVUZ3WXBJS04zVkI3cXVKZlgwamZsU1JaRndMaXdlK3VhYndmTVZ6c2doajUvOXZNNzcwK0JaMGtJcE45NzBTMG5BbHl6R0h0aW1nTUl1RXFhbUt5QTNTQlI1aHZIYmRyNENnTHFUbXIzbFFnWmpnSkNvN1FXYUJWTXdCR0RpdzVOVVhUUnBycWc4U3h2eDlnNWZwbXMrL0o2QjFEelNTM3ZRZzgxdHFRU1ZDWVJpc0Y3M2VqZlFuZk4zcUszd3RJRDkxQnRISmFvMEFaUUdKVFpKOXVsZ0kzV3hzdWR4ejB0VHVpNlJlSWpmSWsxekZRdFpwRExGMnB3NGpTQVdQTlJqNDBYdVIrRzFUVlI3OVFiME9FYkw4RDFoTU5zWmo3MTZNbUhSOTlKaUxNdm1FWHV5a1V4VGhGYjRMTzZVbW1kU3UwTlBpMXQ2NmNkYURpQWhMaVBFTGdUNkZsenA2T2FGSGNSNjRncEtyemtTNDJONEhJeFpNa2R6M0FsYkRhK2pOWHZPR1l3UWl5K0xNNENZWGtrTWtHR3ZTWis5R2xWQ0l5RXBJaXIzbEQ3bmdzZGk4emxGWDYvekNaczlQSUtwZFZlSGJGZi9GS20wV3AreHI0Ykd0R0RrVHR2Nk1Manh2YU8zanFHaUFWeERKVWFkTVBlS2VHSm5uempTdnpKbGdOVHV3c3grRnF5L2dPMkwxMGowWmhDWi92dE9NelVjNjl3cGhKZm9FNzU3V3lOeFJOcThJc0Y1Tkg5Y0x0b3UvbUNxOTc3YnZPSkRrSURCN3lKWEJ6YUhVQkJuSXJra1Qyemg3bGJmUm5SREJUSFZraVZMazVESUxqeC9XL1BSZEZpUUM2SzRmZGx4Y29JbzlMcnM4ZFVWZkt2TTNNYnJ6c1hGT3ZtVVh0K3NsZldvd3UyTC9ndG9mRFhvTUJZZnlEcWIvWlRaRWZ0MC83blliRm1relBEUlZacU5SR0F3YWZVNTU1UjB2SWtNbGR2VjdKUzhNT1BNYWlXQVBpelNLRG4yRzNvcys1MzRFQytaOGZnWmFPVWpZL0xLME9vME9RMmhvNUV6MGNMYWpwUjFINk9FNEhvUm1ydjQzZkFjdGpYc0hYdi81RXg3emdrWk1NZXZhTFNEdjZtcjFGcDk4QXR4L296VTFGVDBoMDUxcVcwR0g2VWpRRXk5aExSZDBBMnFkUTRMZXpReDNvbDFTblhsamt2MG4zTXFlaFozOC94bzZhdHFDdkJtQkc3amlUdXd6YnlVUngzRm1TM0NCNllOYnFON3hPYVRZRnlkOEZDL01nY0xGQmMwS3F4MXllQ2VUd1hucldQb0dvdllVQlYxYjA1cWtIa1d5V0RUaCsveXJFNzF0RjNxbUQvd3F6cUJyNE04NERtWWVuQkdFOWxtb3FIZEMyWnRpK09KVFZKcmlHZWxQQ3RjZnZRaUlQcHdDZ3BFNmg1ekZhRndLajRuZGtBUkRpTC95L1EwWTZxNU5rM1g5RURlTmdjY1pIcFdmOUpKQ3M2a29wdXRtYjdDczIrbVJYdER1S09DaGY5UVUyN3Bmb1NJaklYK3NGdHY1c0hhSms2aHBZMlpzUUhzaTBYbFowc3FMTnQ5ayszdTVnYnBSU1JCczlHaC9BaVY0dkNyYTRkOTh5U0dCdzRSR1FhSStpQ29RaG9YK3lxc3VrYkx6bXJUU3FXMVRXaXJReUlHZ1Q5VnFERE1mUzAxeGdQSlNFSTlIWlp6TGlFVXVGMm1CMi81Y2dqaEFUaWQrdGV1UVB4aldhN2NSc2t5YUhuTENjQURVUU9ESUFPVjJDWXROcnAwY29ZL091S3ZzaXlJT0lacVJ5dE1PMGVNZ1ZJWTBzWmdxeVEycXlubUx0NDBmWmd3SFVyV245Zm9TYTNtMkVRTy9uOS8yU2NuelJWdVZpVnNjM0tCSElQL3AzNlJlSWowTGlNcCtPQ0p3SHlLVW1UeDRBU1V0dXVhWktlRHl1QjlxcXJuUEFNWUVCeElsTGFvdXMzV1pHakIrcW9ub3QvNmk1UE40bUZjbHFDcUxhMGJHbks4ZnJxYy9yd2tuVGV0YUE0c2tXTEw1L21qNEd5MitFQkh3a0x3UXd2K0FKdmZTOXYvNDl1LzY0N1ZFYW15UzdZQ2ZEUHNBQUREQ1FFcWJNQ1h2Ui8xVmEwWi9YUWhoNlkrZUt0MEVpRDdpNmRZODJtQkFoNEJMRmRVV3VGZHVrdUVwaGZ2WXB3N2loVjNxTjB1NFM1NTRXU0dUa0ZsdlpYNG1hbkF4a1g2ekQxS0NWaEFMdEJnSDgzdkhxam9uc0lwOFMydHgwZ0tiYzEreHVaRVppVWlNVVlVdTByQVFsRFcrZHJoN3lVRHZqekFHSnBmTk01eThaMW45em93VzZ5YW5VZWFBNjhSZDd5TUxobFd0NVh6bGhBTVZDZmZYZ0pFelR1YzJEbENVOXNMLzVTVkRaV2N4R1E5aFM1cnJtK2VyQ1Jxd2FJQk1DNUtza0RCZHdOWmh2Q0FCdEpqS2Vla1FUSjd5MFp4SGNhbGVCaU1rbkYwZVRDZzFvUEhPUVZLQ3V3NE94cHRZUS9xS1V0TEFIWFZ2OTlLMGRWcWZDMmpVQWlHQmVYa0t3aGRYTGtJYlZxU0EyZmxraXBBeEhYNnByUEExQjF3eTVab3hPUFg4RVExOW92eXpBbFg1dHU0OXEwWC9PSExFN1o5T1cxenltRXR6ZFpyNXJZbWtFcVdtcHVSNU5jeHFwTWlZam93dUNXZWhubzIyeG5JM09IQ0xDZkFKaHRrcklhL1hPc0tZRFpCRzFJMGJsN2taR2R5cEtUQlhYdXl6WE5WUlU5L005ejhaVytwdG1oZ2NOUzBJS2VaaSs5bFl4cWRlS3lnbldTTTV3czdSYUpmNlRRZTNSaWJZUjFvNkhwRzB2VHpiTEtQZTZnRjJGODdiWlBJei9mcTNLWnZiM3UrSnhZcCtJVjBtQi9VN29YelhRRk1RK3VmWllpNzUxbkx6WlVxRE1ybU53TFJPVUFNUk8rVnJtblkwSVB1cFBVMXc0b0hBb1dnVGRnTk5pNk1uTFQ4V0pmUlhjT0pKMk1lbUc2K2ZNeHNZUU52UVJwa1RGY05vaFV6Y3ZjcHJ3NUV3WEVZQTJzbzczL2MvY3RIRGcreU05YlF4REppUlltRnFydkhYb29hS1JyekxnUjZLVWdoM3ltaWxaQ0lSSm9KbTE3aEtHM1pxTTE0Lzl5OUc5OE9BZjNkVTlqMDk3aUNlaEc3a2VxYXRJQ2hFWmJqbmQ4Y00rS3djN2FtVWp2ekQzQmNvMHl3MDJxT054OWF3OGhSblZiWDZhdkRJbGhySHZ6SU44MzFvUjljRHBwMG1DUEJXZFVDQlNqVGJ1RkZqRC90WElSbGxlT2JraFFKSUdSNlE2U1MxcXkzT29WT1VheFl6THY0U2s3dndrQUMwUitGREVIeVFZbFVhbVVkTWcyUmdwRUdhSVd1V3IxaGNnRm10QmREV2g3ZFBuWTF0U3VKOC95MXp4NkRvN2ZJYmNFenBBK2E0ODNtRG5vemdld3VmaFdqVCsvUS85WlEreFQ5UWJBT1pQSXhHV3VhSXVrVk8zSWxvZDhJM1NGZFJCTHY5ZXBDNzFLeXpSdVlpMktkOHJ5NVNINit1WnMxUHlZUlpRakdDK3Q4VzRtSE82Z1lFRWVXSkJ1UWhnSHdmV2xhZXlWb3hac0NBQVZKRUllT3hPZDZtNW45OHRCUDdHTmgxT1M0eDRCS2FVN1A0UVQzNVVIZW5meE84WWFQUThmbXlobUJhSVJVZklBTVN2ZTJZRFp5SWNNTTkrN0tNSVVabzJ0eXRvYzdCOGVvZzBNaUkrVkpFdFg0c29FRjFSWkhQZVV3NWlCTjI4OTh2MmVTcGNnVUJhWHFzOUN5VlZtTVJQMEtLUDJ1REt4MUdJcUhjS0ZCOXVQVWRkQS9vT3dNa0tVUWsraFZVVDVPbEVMdjd1a0FBUEE0eE4rZkczVmYxeUVKV0FiVGx5dWtGcThjNXBTRkY1cXVHbUgwVmVpQzVvVEFka1VES3Z6WGhWWUs5c3BRYjNVZ1Z0Qld6N1ZScnlOUVVST3BIZU5xeDlhZHA4YWREWCtRSHJUKytYblN4VVI3SVdGanlNTkZJRWlMWmkxdks1UVVrZlRDUU9qdjh2SHdiUi9MRHF3Z3M5bXdsT3pPY0RLdVBVK0dTb2lnVFdRejRWN0N2SHRaVDI3WUdKVG44RFFFM3IzdjB4aWxvODJ2U3VXSDg0WEU3VEJsTUpFb2R5eDNDRngwVUVkc3VhRHBPSEV3UjZYNlUyU0xseERYSXVZeEhlNXh2NjI4bXU0bDRMSnBYUjhkYmljTEZKQW55Q0FVeDJLb2dDamt1cmU4bXNUZktDbG8wamFlN1hNR05PSk15b0ZYbVlHZUh2eGhNUGMzTEtYLy9VY1p0c3p3dFJrQmNFdURXQysvQWNWZVBOSHVOWWI5MEpIcnRucGg1ZDlhL1lpTkpzY1N3QTFwUVZrdW1TQWtPQWdLdWRzcnl3c0N3Zkg1anNydVpHUTJDd1hKRXQzUU4wU2NLUlVnT1NCQ3FYa1BqZDVSVzJuOFZpamt4anovbWptakhCNmk0eHM5NEU2Nzk5STAyaldYNVd3UDZhTFRaTGt5TjhxNDUxT0RmeUZVZEY5WWsyZXQ5VUpsV1NzRFJMSWVCd0ZyQkEyZTdyRWsybWFLVUNCRW5PUWM2bUhVMXQvZ3gzK1VXVVFXbkpMZVUxbWUvbkFEdy96UGUwd3d0Vm9BaERZdDBoR1hQblJydjFoUHRGS01CeWtqckg3a0J5U0R3WDlQMi9XZkNkQlE5K1J4cHRsR2hvRmdpMUs0NVlOeEpEd05wTmd5MDV2WXUzVUtrMkpRYVNGUzcwK0Y1NzluRE5RenZpK0pPRlRsdDFmWDJGNXk5NEV2NHZobWRQSmRVOFVVRjU2Ymx0emxKREVFdmsySlFrOTM0aHpwTXJGZ1d3ZHUxUkxxSEhCN2h2T2hnaHNqV0ZGY01zNjZaRUtWcVhKUytxWWNVMHk0akwySVQrNlF2N2pvQ3BWbUdzUWtGY1FyblhxOUJiOTdaUS96UCtwaldmWTU0UmNRVlMydUU1YURObVVyVkdLK3E0d0xRcUhuRVViT2puSHFFeGlacUtxOVdRaUtUK2c3QS96bVlIQ2k0YzFTejRNVWhHb0t6U2l4aXoxYUNJUEJXdy9vczR2cUVqbXgzOGx6YnV0OWNWbElzeGNkTUpUTERRK3ZOZ0YyY1ZRaVcxRTQ0d3lWcnI3TUFaOE9KRVpFSzlEZWt5MzJQUkFuSkRUVXVqdGFscmJ0T2VOczhyS09uTjcvNFRqUEwvZmRlbEI4bjA4WXdSNXdmbU42VGpGWUhRSDFjbUZmK1AvNUxVMTI4Q1pEYjNQUStxMlFJazV3aE40eGwvcy9lb29pallmeWtDcm5aSEhHWkluTGhoU2pWbk5ISWdTL203VWV0NlhBTDdvZUl5UFRLeHVnbDJzRWtUQzNnZ0tjTnFZR0E5U3ZlYVlaQ00vWHNQRUtQbWs3QmlRNmprWFBKaE1yREd4Vkc0SW9aSDgrYjBrUWJYR2l0Mkw0L3hZdHh1bTVzcFNPSjdsTDltVFpRNnBxM2JOaTEwZU1mZ0ZWaDc3NU5JRlc0SEp3U1FtaTU0bk11blZTQjhxdjZKc0w3SGlsZ2N0ZHFSNThTTjVad1lCa2dOR1hzYjA1QXJWemVXbHh1Y21BSHNPT3dyczFnMzh6bTRZN2ZPZmducmFhV1kxanZZOFlEODZQZThkZzR4cE5paTg3UnNDZk5WK2NKVmMraktFdnpuZVY1Zzd0RmlxZCtsZHp4STlKemdSS2t0WUV6RUpRSVU5M2UvclJaN1lrVkZtNVV1cjVhMWYzcG83T0VtYkJUc2MrQ1FaOGNnYmIvbUphRXJoa3NyL3JURjBNcjNxeDl5SlJWSEJ6YWNWd0dScEFRaURPdnJkWU4xQXBVOTRyR1lrVFVzdWs1YjE1Wll2QVZxRlRzVlVMaS9HY29mbEljMm01Z2RFTFZOblRmdXY1Zlk5S1NlWHFoUU80S0pOYVZmbHAwQ0VKYWFFZFNLUXJJNXRaT2w1RkE4VXZlNmxTWVd5TVk0REl4a1RiT1JoWHVBdzR6b1RTMjgrN3d2TXhydVBkZnlKbUJCTkhQdCtEYmdKNHovcHJZWUhpTmFMTXNZamtQZE44ajNKZDczQXJFZk92Um52MzYxSVVVMFg1RDc1dlRSdlpkbzMzWERzanRlOU4weUo3K2lIQnF1a1FJY2pIVW9ic2RQN0hOajBVYWNSMHIvTmRlVTlGNFBNc1VLY2t6Tk4rZGhyMVI2d1J2R1VZb1pDRWJaWlJMWEt4QnA3SElUNEVQUktHakIvdW1xTFhhMXl6RWx2QW1WQUJhMDFZN3dGdk4wM2Ywb25FbUhTM2w1d1paRmV6cjVibnN5T01XVGxhMU5kaW1ZNXNVeE15VFliZmc4dzB2cXNEc28zWFAxYndLdzZ3M3VIRGQ1UHBSWnVDSnR0eWk0ZzJGeWI0Ymg1UU42ZkdORTI2ekRGN1Y4QmJwZXJLNkFKQ0xTWm5kaDZMMTlPUTBram4xUGpEMGk4c1BZcGFXOWxVeVJkZElPKzRWQS9LemxPUzJ4M2s5VUtUdElsTTBUSVdtZXFIS0dYUVpocGpvVGI2VlNKN203cjZaaVlQMnVsQVVvZmVWL0o2eCtzckxEQXkyQ2ZFNnFrREZ1OU9NWDBBSXVnN3loQUtOMDRyT3hVNk5tcGtjOUZ4bXUvVS9vR3hHdmIzeFVFTDYwdE1sSE9EaWtqY1I5RDJrKzRwbEc1WnV0d0FIY2kwRU02WHRrVEhQOU5QMlRTR1VFN1E5SGYvU0VEc2V0a25hZXhvWmhDczJLWDFMeU5JS0U0N2pkMkR3MTUreDRRVXV0VUFTbzU5Q1lHMVFBeW9BVVhrV3dtbXkzTGdTUWp5T3ZLV25qaE8veWpPd0FyWGd0NFBrSVVnZDQ1N05ReFpMbU41K0J4NVJoQ0FHdkUxYmxOZjlMek9keGJiaG5VZ2Z1RDM5MXVSRkhjS2RYREY3ZmVqb3gveThtaWZJcTRWVzQyajBHQnFOQUtkK0prMnJCMW9hOTRiT2hxcVVzanhqWnlRaGRXTzhNblR6T2tOaGVpZXU2blYxcW5yZ3JHU2huWTNJMlczb29GNFNnczRjZ3drZ2h2dHpFa0xUbU5OUm83RTdudVRuMkxJcmlGSnlvTmZQdUp0aWN0S0JtNzRGZytkWVBTMlIzTzNmOWxBZWxiVWZjbzZGNU9EL3hkS1VuRTh0V3FOMExVcDlWQUptWVZYZFVDaGJ4MjM4MWtDaStLNDJoRzUydFNQYU1hb1dTb0xQY2Zrb24rc1pYdjdEdEtwZi9HTzdhcUMza1pzRGpva29haHJGZGJWSlNTZWhrNGp5K3RzRHplQnJKSjBrMVZrUnJHN1NoVHZjTmd1cjVucVRUTEE5dlJMQmJNTTlhNlI1NEZ0Z1pQOWFKMU1aMEdCcUVpMnF6Ui8yd2tYQlhwcFhZdi9TcU1RV1dhbTVsSHBMVktxaDN4ZHRjNFdmck9mYldsbU1PNXA5Z0JUSFp1YUcxVGFkZXFRVVpKQmZBS01ENFdSR0NsMDFaeDRTVzE0YzZrdnFKdXExL080N215L3RsVHlLWndpYlBkQTNRMVVGd0I3R2Z4anEwaDN2ckxFbUNrS3Vsc0VBUkN6UnZNVjJSVnBVbFpUV240Y1Boc0hjcTNROElHSUYyKy9nOENFSU4vMU8xcVMvMkpXcXlDNmtIb0w4Y2R2R0VHbmkxSTNDTk1JcXhxaHhJL1V0R3REc2VwYmwrSHI0elh4MzZna3BCbXBoT2xkTFVYTHAzVEtibVVZRWJSWHcvZmRmeFQ3WDdZUFhHQ0hHVG1uTzk4WkxDOTA2Zmkvekd2b04rNlpzbCs3MkpWMGxJWEo0V3dZdWxFUmZHbkFDWGNoa0Yzei9ITWR3elcwTUFFaXptQmwvREo2ZUoyU01PSG1Uc25YbElGRDRlcFRrYnFBQ0dpZ2I1UExFdHdQRVRjYkNRckM5YUtTU1FnSTdEZXd1aWlxM2J0Y0RUWkIzeEI5WWxlbmhpU0FXNjIwcmwzc2ZjY3d3eGFSOHBDV2Rzd0x3dmFxcDhjM01PV3RCc2xPcmVTSkNEcWgvdzBYbm1WMFJVWFpNM2JvUmkwVXhsaHVUeDFlM1NTd09pbTlOczNYV3NoTmI4Lzc3VkhnUWhRVFlSUU1NRllYaWRmMElCKzBtSUpocWNoQTlUeUY3dGRjSDhrUUJUSHNEWS96bFpqK3EwNlFMd0JkbTkxc3IyK3VzZmxlaXB3WUMrcmdiNHROVnA3VU5rYkVqTnR6ZWZsTi9VRTlkbHZtT2x6V1dtZkh2NGVkUGkzMmJmeUNRS1d6SGJVVEV3NU0yVFpsZnpNaTFWUjVsaDBxQ1lqaDNITUlmL2MwcHBKd2I1b1lFTnBBenlxbnlmdmlTV3lBYzc2L1l1VWwvb2FVaysrYzBZc2d1TGo5ZGFQdVVvemhoZ3VjSytQRGlNckI0ODU1Mk83VWg0aHRwNmZ3S2dJa1JCTVFIUTd6MmV5WXovV1AwQm9ZZVhjOGc3aUprclhFNzA1bFo1bXhGU0poT3E1WlNleVJSb21pUm41K3VRemM5ZFdWQjBYb2JURXdOc0VRM2FIZ25JY29BczY2UGplUT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg== \ No newline at end of file diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/legacy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/legacy.py new file mode 100644 index 0000000000000000000000000000000000000000..7453a3ae2399d06d977b4cda076da4ee6e69b804 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/legacy.py @@ -0,0 +1,44 @@ +import requests +from httpretty import HTTPretty + +from ...utils import parse_qs +from .base import BaseBackendTest + + +class BaseLegacyTest(BaseBackendTest): + form = "" + response_body = "" + + def setUp(self): + super().setUp() + self.strategy.set_settings( + { + f"SOCIAL_AUTH_{self.name}_FORM_URL": self.strategy.build_absolute_uri( + f"/login/{self.backend.name}" + ) + } + ) + + def extra_settings(self): + return {f"SOCIAL_AUTH_{self.name}_FORM_URL": f"/login/{self.backend.name}"} + + def do_start(self): + start_url = self.strategy.build_absolute_uri(self.backend.start().url) + HTTPretty.register_uri( + HTTPretty.GET, + start_url, + status=200, + body=self.form.format(self.complete_url), + ) + HTTPretty.register_uri( + HTTPretty.POST, + self.complete_url, + status=200, + body=self.response_body, + content_type="application/x-www-form-urlencoded", + ) + response = requests.get(start_url) + self.assertEqual(response.text, self.form.format(self.complete_url)) + response = requests.post(self.complete_url, data=parse_qs(self.response_body)) + self.strategy.set_request_data(parse_qs(response.text), self.backend) + return self.backend.complete() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/oauth.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/oauth.py new file mode 100644 index 0000000000000000000000000000000000000000..44946d419ef1c599bc35a3269b0565fa3ffa72a5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/oauth.py @@ -0,0 +1,123 @@ +from urllib.parse import urlparse + +import requests +from httpretty import HTTPretty + +from ...utils import parse_qs, url_add_parameters +from ..models import User +from .base import BaseBackendTest + + +class BaseOAuthTest(BaseBackendTest): + backend = None + backend_path = None + user_data_body = None + user_data_url = "" + user_data_url_post = False + user_data_content_type = "application/json" + access_token_body = None + access_token_status = 200 + expected_username = "" + + def extra_settings(self): + return { + "SOCIAL_AUTH_" + self.name + "_KEY": "a-key", + "SOCIAL_AUTH_" + self.name + "_SECRET": "a-secret-key", + } + + def _method(self, method): + return {"GET": HTTPretty.GET, "POST": HTTPretty.POST}[method] + + def handle_state(self, start_url, target_url): + start_query = parse_qs(urlparse(start_url).query) + redirect_uri = start_query.get("redirect_uri") + + if getattr(self.backend, "STATE_PARAMETER", False) and start_query.get("state"): + target_url = url_add_parameters(target_url, {"state": start_query["state"]}) + + if redirect_uri and getattr(self.backend, "REDIRECT_STATE", False): + redirect_query = parse_qs(urlparse(redirect_uri).query) + if redirect_query.get("redirect_state"): + target_url = url_add_parameters( + target_url, {"redirect_state": redirect_query["redirect_state"]} + ) + return target_url + + def auth_handlers(self, start_url): + target_url = self.handle_state( + start_url, self.strategy.build_absolute_uri(self.complete_url) + ) + HTTPretty.register_uri( + HTTPretty.GET, start_url, status=301, location=target_url + ) + HTTPretty.register_uri(HTTPretty.GET, target_url, status=200, body="foobar") + if self.user_data_url: + HTTPretty.register_uri( + HTTPretty.POST if self.user_data_url_post else HTTPretty.GET, + self.user_data_url, + body=self.user_data_body or "", + content_type=self.user_data_content_type, + ) + return target_url + + def pre_complete_callback(self, start_url): + HTTPretty.register_uri( + self._method(self.backend.ACCESS_TOKEN_METHOD), + uri=self.backend.access_token_url(), + status=self.access_token_status, + body=self.access_token_body or "", + content_type="text/json", + ) + + def do_start(self): + start_url = self.backend.start().url + target_url = self.auth_handlers(start_url) + response = requests.get(start_url) + self.assertEqual(response.url, target_url) + self.assertEqual(response.text, "foobar") + self.strategy.set_request_data( + parse_qs(urlparse(start_url).query), self.backend + ) + self.strategy.set_request_data( + parse_qs(urlparse(target_url).query), self.backend + ) + self.pre_complete_callback(start_url) + return self.backend.complete() + + +class OAuth1Test(BaseOAuthTest): + request_token_body = None + raw_complete_url = "/complete/{0}/?oauth_verifier=bazqux&" "oauth_token=foobar" + + def request_token_handler(self): + HTTPretty.register_uri( + self._method(self.backend.REQUEST_TOKEN_METHOD), + self.backend.REQUEST_TOKEN_URL, + body=self.request_token_body, + status=200, + ) + + def do_start(self): + self.request_token_handler() + return super().do_start() + + +class OAuth2Test(BaseOAuthTest): + raw_complete_url = "/complete/{0}/?code=foobar" + refresh_token_body = "" + + def refresh_token_arguments(self): + return {} + + def do_refresh_token(self): + self.do_login() + HTTPretty.register_uri( + self._method(self.backend.REFRESH_TOKEN_METHOD), + self.backend.refresh_token_url(), + status=200, + body=self.refresh_token_body, + ) + user = list(User.cache.values())[0] + social = user.social[0] + social.refresh_token(strategy=self.strategy, **self.refresh_token_arguments()) + return user, social diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/open_id.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/open_id.py new file mode 100644 index 0000000000000000000000000000000000000000..67885becbed30cdeba4370f5a4ffe6158e493d5d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/open_id.py @@ -0,0 +1,103 @@ +import sys +from html.parser import HTMLParser + +import requests +from httpretty import HTTPretty +from openid import oidutil + +from ...backends.utils import load_backends +from ...utils import module_member, parse_qs +from ..models import TestAssociation, TestNonce, TestStorage, TestUserSocialAuth, User +from ..strategy import TestStrategy +from .base import BaseBackendTest + +sys.path.insert(0, "..") + + +# Patch to remove the too-verbose output until a new version is released +oidutil.log = lambda *args, **kwargs: None + + +class FormHTMLParser(HTMLParser): + form = {} + inputs = {} + + def handle_starttag(self, tag, attrs): + attrs = dict(attrs) + if tag == "form": + self.form.update(attrs) + elif tag == "input" and "name" in attrs: + self.inputs[attrs["name"]] = attrs["value"] + + +class OpenIdTest(BaseBackendTest): + backend_path = None + backend = None + access_token_body = None + user_data_body = None + user_data_url = "" + expected_username = "" + settings = None + partial_login_settings = None + raw_complete_url = "/complete/{0}/" + + def setUp(self): + HTTPretty.enable(allow_net_connect=False) + Backend = module_member(self.backend_path) + self.strategy = TestStrategy(TestStorage) + self.complete_url = self.raw_complete_url.format(Backend.name) + self.backend = Backend(self.strategy, redirect_uri=self.complete_url) + self.strategy.set_settings( + { + "SOCIAL_AUTH_AUTHENTICATION_BACKENDS": ( + self.backend_path, + "social_core.tests.backends.test_broken.BrokenBackendAuth", + ) + } + ) + # Force backends loading to trash PSA cache + load_backends( + self.strategy.get_setting("SOCIAL_AUTH_AUTHENTICATION_BACKENDS"), + force_load=True, + ) + + def tearDown(self): + self.strategy = None + User.reset_cache() + TestUserSocialAuth.reset_cache() + TestNonce.reset_cache() + TestAssociation.reset_cache() + HTTPretty.disable() + HTTPretty.reset() + + def get_form_data(self, html): + parser = FormHTMLParser() + parser.feed(html) + return parser.form, parser.inputs + + def openid_url(self): + return self.backend.openid_url() + + def post_start(self): + pass + + def do_start(self): + HTTPretty.register_uri( + HTTPretty.GET, + self.openid_url(), + status=200, + body=self.discovery_body, + content_type="application/xrds+xml", + ) + start = self.backend.start() + self.post_start() + form, inputs = self.get_form_data(start) + HTTPretty.register_uri( + HTTPretty.POST, form.get("action"), status=200, body=self.server_response + ) + response = requests.post(form.get("action"), data=inputs) + self.strategy.set_request_data(parse_qs(response.content), self.backend) + HTTPretty.register_uri( + HTTPretty.POST, form.get("action"), status=200, body="is_valid:true\n" + ) + return self.backend.complete() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_amazon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_amazon.py new file mode 100644 index 0000000000000000000000000000000000000000..24cebae1031ae42ffcc6b682afc59ef3d4f75be2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_amazon.py @@ -0,0 +1,58 @@ +import json + +from httpretty import HTTPretty + +from .oauth import OAuth2Test + + +class AmazonOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.amazon.AmazonOAuth2" + user_data_url = "https://api.amazon.com/user/profile" + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "user_id": "amzn1.account.ABCDE1234", + "email": "foo@bar.com", + "name": "Foo Bar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class AmazonOAuth2BrokenServerResponseTest(OAuth2Test): + backend_path = "social_core.backends.amazon.AmazonOAuth2" + user_data_url = "https://www.amazon.com/ap/user/profile" + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "Request-Id": "02GGTU7CWMNFTV3KH3J6", + "Profile": { + "Name": "Foo Bar", + "CustomerId": "amzn1.account.ABCDE1234", + "PrimaryEmail": "foo@bar.com", + }, + } + ) + + def setUp(self): + super().setUp() + HTTPretty.register_uri( + HTTPretty.GET, + "https://api.amazon.com/user/profile", + status=200, + body=self.user_data_body, + content_type="application/json", + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_angel.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_angel.py new file mode 100644 index 0000000000000000000000000000000000000000..cfeb85e6a505d234416f796968c99dd1c5296640 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_angel.py @@ -0,0 +1,38 @@ +import json + +from .oauth import OAuth2Test + + +class AngelOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.angel.AngelOAuth2" + user_data_url = "https://api.angel.co/1/me/" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "facebook_url": "http://www.facebook.com/foobar", + "bio": None, + "name": "Foo Bar", + "roles": [], + "github_url": None, + "angellist_url": "https://angel.co/foobar", + "image": "https://graph.facebook.com/foobar/picture?type=square", + "linkedin_url": None, + "locations": [], + "twitter_url": None, + "what_ive_built": None, + "dribbble_url": None, + "behance_url": None, + "blog_url": None, + "aboutme_url": None, + "follower_count": 0, + "online_bio_url": None, + "id": 101010, + } + ) + expected_username = "foobar" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_apple.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_apple.py new file mode 100644 index 0000000000000000000000000000000000000000..7d58ee0e6bb07743c1b01bcab55500a4b2aba603 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_apple.py @@ -0,0 +1,57 @@ +import json +from unittest.mock import patch + +from .oauth import OAuth2Test + +TEST_KEY = """ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIKQya8aIoeoOLeThk7Ad/lLyAo2fTp9IuhIpy2CivH/qoAoGCCqGSM49 +AwEHoUQDQgAEyEY7IMlNJtyaF/pdcM/PpQ8OCe19Sf1Yxq4HQsrB2b7QogB95Vjt +6mTZDAhlXIBtuM/JLrdkMfPmwjVKLgxHAQ== +-----END EC PRIVATE KEY----- +""" + + +token_data = { + "sub": "11011110101011011011111011101111", + "first_name": "Foo", + "last_name": "Bar", + "email": "foobar@apple.com", +} + + +class AppleIdTest(OAuth2Test): + backend_path = "social_core.backends.apple.AppleIdAuth" + user_data_url = "https://appleid.apple.com/auth/authorize/" + id_token = "a-id-token" + access_token_body = json.dumps( + {"id_token": id_token, "access_token": "a-test-token"} + ) + expected_username = token_data["sub"] + + def extra_settings(self): + return { + "SOCIAL_AUTH_" + self.name + "_TEAM": "a-team-id", + "SOCIAL_AUTH_" + self.name + "_KEY": "a-key-id", + "SOCIAL_AUTH_" + self.name + "_CLIENT": "a-client-id", + "SOCIAL_AUTH_" + self.name + "_SECRET": TEST_KEY, + "SOCIAL_AUTH_" + self.name + "_SCOPE": ["name", "email"], + } + + def test_login(self): + with patch( + "{}.{}".format(self.backend_path, "decode_id_token"), + return_value=token_data, + ) as decode_mock: + self.do_login() + assert decode_mock.called + assert decode_mock.call_args[0] == (self.id_token,) + + def test_partial_pipeline(self): + with patch( + "{}.{}".format(self.backend_path, "decode_id_token"), + return_value=token_data, + ) as decode_mock: + self.do_partial_pipeline() + assert decode_mock.called + assert decode_mock.call_args[0] == (self.id_token,) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_arcgis.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_arcgis.py new file mode 100644 index 0000000000000000000000000000000000000000..e8164c36807062bfcc1e27334abc5f9f540029c9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_arcgis.py @@ -0,0 +1,34 @@ +import json + +from .oauth import OAuth2Test + + +class ArcGISOAuth2Test(OAuth2Test): + user_data_url = "https://www.arcgis.com/sharing/rest/community/self" + backend_path = "social_core.backends.arcgis.ArcGISOAuth2" + expected_username = "gis@rocks.com" + + user_data_body = json.dumps( + { + "first_name": "Gis", + "last_name": "Rocks", + "email": "gis@rocks.com", + "fullName": "Gis Rocks", + "username": "gis@rocks.com", + } + ) + + access_token_body = json.dumps( + { + "access_token": "CM-gcB85taGhRmoI7l3PSGaXUNsaLkTg-dHH7XtA9Dnlin" + "PYKBBrIvFzhd1JtDhh7hEwSv_6eLLcLtUqe3gD6i1yaYYF" + "pUQJwy8KEujke5AE87tP9XIoMtp4_l320pUL", + "expires_in": 86400, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_asana.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_asana.py new file mode 100644 index 0000000000000000000000000000000000000000..efc394a0b72157d6ff304e60c86b269099ad49c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_asana.py @@ -0,0 +1,28 @@ +import json + +from .oauth import OAuth2Test + + +class AsanaOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.asana.AsanaOAuth2" + user_data_url = "https://app.asana.com/api/1.0/users/me" + expected_username = "erlich@bachmanity.com" + access_token_body = json.dumps({"access_token": "aviato", "token_type": "bearer"}) + # https://asana.com/developers/api-reference/users + user_data_body = json.dumps( + { + "data": { + "id": 12345, + "name": "Erlich Bachman", + "email": "erlich@bachmanity.com", + "photo": None, + "workspaces": [{"id": 123456, "name": "Pied Piper"}], + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_atlassian.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_atlassian.py new file mode 100644 index 0000000000000000000000000000000000000000..caa26e1935687187441813262d13df2289979aba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_atlassian.py @@ -0,0 +1,59 @@ +import json + +from httpretty import HTTPretty + +from .oauth import OAuth2Test + + +class AtlassianOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.atlassian.AtlassianOAuth2" + tenant_url = "https://api.atlassian.com/oauth/token/accessible-resources" + user_data_url = "https://api.atlassian.com/ex/jira/FAKED_CLOUD_ID/rest/api/2/myself" + expected_username = "erlich" + access_token_body = json.dumps({"access_token": "aviato", "token_type": "bearer"}) + tenant_data_body = json.dumps( + [ + { + "id": "FAKED_CLOUD_ID", + "name": "bachmanity.com", + "avatarUrl": "https://bachmanity.atlassian.net/avatars/240/site.png", + "scopes": ["read:jira-user"], + } + ] + ) + user_data_body = json.dumps( + { + "self": "http://bachmanity.atlassian.net/rest/api/3/user?username=erlich", + "key": "erlich", + "accountId": "99:27935d01-92a7-4687-8272-a9b8d3b2ae2e", + "name": "erlich", + "emailAddress": "erlich@bachmanity.com", + "avatarUrls": { + "48x48": "http://bachmanity.atlassian.net/secure/useravatar?size=large&ownerId=erlich", + "24x24": "http://bachmanity.atlassian.net/secure/useravatar?size=small&ownerId=erlich", + "16x16": "http://bachmanity.atlassian.net/secure/useravatar?size=xsmall&ownerId=erlich", + "32x32": "http://bachmanity.atlassian.net/secure/useravatar?size=medium&ownerId=erlich", + }, + "displayName": "Erlich Bachman", + "active": True, + "timeZone": "Australia/Sydney", + "groups": {"size": 3, "items": []}, + "applicationRoles": {"size": 1, "items": []}, + } + ) + + def auth_handlers(self, start_url): + target_url = super().auth_handlers(start_url) + HTTPretty.register_uri( + HTTPretty.GET, + self.tenant_url, + body=self.tenant_data_body, + content_type="application/json", + ) + return target_url + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_auth0.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_auth0.py new file mode 100644 index 0000000000000000000000000000000000000000..4c3725eeec198ea1f6d6519432949ca9d70472cd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_auth0.py @@ -0,0 +1,75 @@ +import json + +from httpretty import HTTPretty +from jose import jwt + +from .oauth import OAuth2Test + +JWK_KEY = { + "kty": "RSA", + "d": "ZmswNokEvBcxW_Kvcy8mWUQOQCBdGbnM0xR7nhvGHC-Q24z3XAQWlMWbsmGc_R1o" + "_F3zK7DBlc3BokdRaO1KJirNmnHCw5TlnBlJrXiWpFBtVglUg98-4sRRO0VWnGXK" + "JPOkBQ6b_DYRO3b0o8CSpWowpiV6HB71cjXTqKPZf-aXU9WjCCAtxVjfIxgQFu5I" + "-G1Qah8mZeY8HK_y99L4f0siZcbUoaIcfeWBhxi14ODyuSAHt0sNEkhiIVBZE7QZ" + "m-SEP1ryT9VAaljbwHHPmg7NC26vtLZhvaBGbTTJnEH0ZubbN2PMzsfeNyoCIHy4" + "4QDSpQDCHfgcGOlHY_t5gQ", + "e": "AQAB", + "use": "sig", + "kid": "foobar", + "alg": "RS256", + "n": "pUfcJ8WFrVue98Ygzb6KEQXHBzi8HavCu8VENB2As943--bHPcQ-nScXnrRFAUg8" + "H5ZltuOcHWvsGw_AQifSLmOCSWJAPkdNb0w0QzY7Re8NrPjCsP58Tytp5LicF0Ao" + "Ag28UK3JioY9hXHGvdZsWR1Rp3I-Z3nRBP6HyO18pEgcZ91c9aAzsqu80An9X4DA" + "b1lExtZorvcd5yTBzZgr-MUeytVRni2lDNEpa6OFuopHXmg27Hn3oWAaQlbymd4g" + "ifc01oahcwl3ze2tMK6gJxa_TdCf1y99Yq6oilmVvZJ8kwWWnbPE-oDmOVPVnEyT" + "vYVCvN4rBT1DQ-x0F1mo2Q", +} + +JWK_PUBLIC_KEY = {key: value for key, value in JWK_KEY.items() if key != "d"} + +DOMAIN = "foobar.auth0.com" + + +class Auth0OAuth2Test(OAuth2Test): + backend_path = "social_core.backends.auth0.Auth0OAuth2" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "expires_in": 86400, + "id_token": jwt.encode( + { + "nickname": "foobar", + "email": "foobar@auth0.com", + "name": "John Doe", + "picture": "http://example.com/image.png", + "sub": "123456", + "iss": f"https://{DOMAIN}/", + }, + JWK_KEY, + algorithm="RS256", + ), + } + ) + expected_username = "foobar" + jwks_url = "https://foobar.auth0.com/.well-known/jwks.json" + + def extra_settings(self): + settings = super().extra_settings() + settings["SOCIAL_AUTH_" + self.name + "_DOMAIN"] = DOMAIN + return settings + + def auth_handlers(self, start_url): + HTTPretty.register_uri( + HTTPretty.GET, + self.jwks_url, + body=json.dumps({"keys": [JWK_PUBLIC_KEY]}), + content_type="application/json", + ) + return super().auth_handlers(start_url) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread.py new file mode 100644 index 0000000000000000000000000000000000000000..a24b87dfa2633098d7a2c80d57d43bc5f4f59794 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread.py @@ -0,0 +1,77 @@ +""" +Copyright (c) 2015 Microsoft Open Technologies, Inc. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import json + +from .oauth import OAuth2Test + + +class AzureADOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.azuread.AzureADOAuth2" + user_data_url = "https://graph.windows.net/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL" + "3N0cy53aW5kb3dzLm5ldC83Mjc0MDZhYy03MDY4LTQ4ZmEtOTJiOS1jMmQ" + "2NzIxMWJjNTAvIiwiaWF0IjpudWxsLCJleHAiOm51bGwsImF1ZCI6IjAyO" + "WNjMDEwLWJiNzQtNGQyYi1hMDQwLWY5Y2VkM2ZkMmM3NiIsInN1YiI6In" + "FVOHhrczltSHFuVjZRMzR6aDdTQVpvY2loOUV6cnJJOW1wVlhPSWJWQTg" + "iLCJ2ZXIiOiIxLjAiLCJ0aWQiOiI3Mjc0MDZhYy03MDY4LTQ4ZmEtOTJi" + "OS1jMmQ2NzIxMWJjNTAiLCJvaWQiOiI3ZjhlMTk2OS04YjgxLTQzOGMtO" + "GQ0ZS1hZDZmNTYyYjI4YmIiLCJ1cG4iOiJmb29iYXJAdGVzdC5vbm1pY3" + "Jvc29mdC5jb20iLCJnaXZlbl9uYW1lIjoiZm9vIiwiZmFtaWx5X25hbWU" + "iOiJiYXIiLCJuYW1lIjoiZm9vIGJhciIsInVuaXF1ZV9uYW1lIjoiZm9v" + "YmFyQHRlc3Qub25taWNyb3NvZnQuY29tIiwicHdkX2V4cCI6IjQ3MzMwO" + "TY4IiwicHdkX3VybCI6Imh0dHBzOi8vcG9ydGFsLm1pY3Jvc29mdG9ubG" + "luZS5jb20vQ2hhbmdlUGFzc3dvcmQuYXNweCJ9.3V50dHXTZOHj9UWtkn" + "2g7BjX5JxNe8skYlK4PdhiLz4", + "expires_in": 3600, + "expires_on": 1423650396, + "not_before": 1423646496, + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "bearer", + "expires_in": 3600, + "refresh_token": "foobar-new-refresh-token", + "scope": "identity", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread_b2c.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread_b2c.py new file mode 100644 index 0000000000000000000000000000000000000000..5731da578b695a0c3781199ce03cdea2845ba0d9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_azuread_b2c.py @@ -0,0 +1,184 @@ +""" +Copyright (c) 2017 Noderabbit Inc., d.b.a. Appsembler + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" +import json +from time import time + +import jwt +from httpretty import HTTPretty +from jwt.algorithms import RSAAlgorithm + +from .oauth import OAuth2Test + +# Dummy private and private keys: +RSA_PUBLIC_JWT_KEY = { + # https://github.com/jpadilla/pyjwt/blob/06f461a/tests/keys/jwk_rsa_pub.json + "kty": "RSA", + "kid": "bilbo.baggins@hobbiton.example", + "use": "sig", + "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-" + + "XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-" + + "QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-" + + "OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrt" + + "IQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7" + + "jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw", + "e": "AQAB", +} + +RSA_PRIVATE_JWT_KEY = { + # https://github.com/jpadilla/pyjwt/blob/06f461a/tests/keys/jwk_rsa_key.json + "kty": "RSA", + "kid": "bilbo.baggins@hobbiton.example", + "use": "sig", + "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-" + + "XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-" + + "QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-" + + "OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQ" + + "bS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3" + + "__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw", + "e": "AQAB", + "d": "bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0" + + "UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_" + + "42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqO" + + "e04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoR" + + "ioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFa" + + "u7gdsPfHPxxjVOcOpBrQzwQ", + "p": "3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-" + + "SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7I" + + "yEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k", + "q": "uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_" + + "cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7" + + "z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc", + "dp": "B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD" + + "-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD" + + "4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik", + "dq": "CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl4" + + "1DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX" + + "2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8", + "qi": "3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3H" + + "aEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH" + + "0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4", +} + + +class AzureADOAuth2Test(OAuth2Test): + AUTH_KEY = "abcdef12-1234-9876-0000-abcdef098765" + EXPIRES_IN = 3600 + AUTH_TIME = int(time()) + EXPIRES_ON = AUTH_TIME + EXPIRES_IN + + backend_path = "social_core.backends.azuread_b2c.AzureADB2COAuth2" + expected_username = "FooBar" + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "bearer", + "expires_in": EXPIRES_IN, + "refresh_token": "foobar-new-refresh-token", + "scope": "identity", + } + ) + + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "id_token": jwt.encode( + key=RSAAlgorithm.from_jwk(json.dumps(RSA_PRIVATE_JWT_KEY)), + headers={ + "kid": RSA_PRIVATE_JWT_KEY["kid"], + }, + algorithm="RS256", + payload={ + "aud": AUTH_KEY, + "auth_time": AUTH_TIME, + "country": "Axphain", + "emails": ["foobar@example.com"], + "exp": EXPIRES_ON, + "family_name": "Bar", + "given_name": "Foo", + "iat": AUTH_TIME, + "iss": "https://login.microsoftonline.com/9a9a9a9a-1111-5555-0000-bc24adfdae00/v2.0/", + "name": "FooBar", + "nbf": AUTH_TIME, + "oid": "11223344-5566-7788-9999-aabbccddeeff", + "postalCode": "00000", + "sub": "11223344-5566-7788-9999-aabbccddeeff", + "tfp": "B2C_1_SignIn", + "ver": "1.0", + }, + ), + "expires_in": EXPIRES_IN, + "expires_on": EXPIRES_ON, + "not_before": AUTH_TIME, + } + ) + + def extra_settings(self): + settings = super().extra_settings() + settings.update( + { + "SOCIAL_AUTH_" + self.name + "_POLICY": "b2c_1_signin", + "SOCIAL_AUTH_" + self.name + "_KEY": self.AUTH_KEY, + "SOCIAL_AUTH_" + self.name + "_TENANT_ID": "footenant.onmicrosoft.com", + } + ) + return settings + + def setUp(self): + super().setUp() + + keys_url = "https://login.microsoftonline.com/footenant.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_signin" + keys_body = json.dumps( + { + "keys": [ + { + # Dummy public key that pairs with `access_token_body` key: + # https://github.com/jpadilla/pyjwt/blob/06f461a/tests/keys/jwk_rsa_pub.json + "kty": "RSA", + "kid": "bilbo.baggins@hobbiton.example", + "use": "sig", + "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-X" + "V2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_Ns" + "YOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHY" + "pPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCu" + "EHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_" + "mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw", + "e": "AQAB", + } + ], + } + ) + HTTPretty.register_uri(HTTPretty.GET, keys_url, status=200, body=keys_body) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_behance.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_behance.py new file mode 100644 index 0000000000000000000000000000000000000000..d94caf920fa87227ec1f188a596a55b9f69ca458 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_behance.py @@ -0,0 +1,49 @@ +import json + +from .oauth import OAuth2Test + + +class BehanceOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.behance.BehanceOAuth2" + access_token_body = json.dumps( + { + "access_token": "foobar", + "valid": 1, + "user": { + "username": "foobar", + "city": "Foo City", + "first_name": "Foo", + "last_name": "Bar", + "display_name": "Foo Bar", + "url": "http://www.behance.net/foobar", + "country": "Fooland", + "company": "", + "created_on": 1355152329, + "state": "", + "fields": ["Programming", "Web Design", "Web Development"], + "images": { + "32": "https://www.behance.net/assets/img/profile/" + "no-image-32.jpg", + "50": "https://www.behance.net/assets/img/profile/" + "no-image-50.jpg", + "115": "https://www.behance.net/assets/img/profile/" + "no-image-138.jpg", + "129": "https://www.behance.net/assets/img/profile/" + "no-image-138.jpg", + "138": "https://www.behance.net/assets/img/profile/" + "no-image-138.jpg", + "78": "https://www.behance.net/assets/img/profile/" + "no-image-78.jpg", + }, + "id": 1010101, + "occupation": "Software Developer", + }, + } + ) + expected_username = "foobar" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_bitbucket.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_bitbucket.py new file mode 100644 index 0000000000000000000000000000000000000000..e8259d0999f52cd0778cac5eb81ce6fd67fee4b6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_bitbucket.py @@ -0,0 +1,194 @@ +import json +from urllib.parse import urlencode + +from httpretty import HTTPretty + +from ...exceptions import AuthForbidden +from .oauth import OAuth1Test, OAuth2Test + + +class BitbucketOAuthMixin: + user_data_url = "https://api.bitbucket.org/2.0/user" + expected_username = "foobar" + bb_api_user_emails = "https://api.bitbucket.org/2.0/user/emails" + + user_data_body = json.dumps( + { + "created_on": "2012-03-29T18:07:38+00:00", + "display_name": "Foo Bar", + "links": { + "avatar": {"href": "https://bitbucket.org/account/foobar/avatar/32/"}, + "followers": { + "href": "https://api.bitbucket.org/2.0/users/foobar/followers" + }, + "following": { + "href": "https://api.bitbucket.org/2.0/users/foobar/following" + }, + "hooks": {"href": "https://api.bitbucket.org/2.0/users/foobar/hooks"}, + "html": {"href": "https://bitbucket.org/foobar"}, + "repositories": { + "href": "https://api.bitbucket.org/2.0/repositories/foobar" + }, + "self": {"href": "https://api.bitbucket.org/2.0/users/foobar"}, + }, + "location": "Fooville, Bar", + "type": "user", + "username": "foobar", + "uuid": "{397621dc-0f78-329f-8d6d-727396248e3f}", + "website": "http://foobar.com", + } + ) + + emails_body = json.dumps( + { + "page": 1, + "pagelen": 10, + "size": 2, + "values": [ + { + "email": "foo@bar.com", + "is_confirmed": True, + "is_primary": True, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/user/emails/foo@bar.com" + } + }, + "type": "email", + }, + { + "email": "not@confirme.com", + "is_confirmed": False, + "is_primary": False, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/user/emails/not@confirmed.com" + } + }, + "type": "email", + }, + ], + } + ) + + +class BitbucketOAuth1Test(BitbucketOAuthMixin, OAuth1Test): + backend_path = "social_core.backends.bitbucket.BitbucketOAuth" + + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + + def test_login(self): + HTTPretty.register_uri( + HTTPretty.GET, self.bb_api_user_emails, status=200, body=self.emails_body + ) + self.do_login() + + def test_partial_pipeline(self): + HTTPretty.register_uri( + HTTPretty.GET, self.bb_api_user_emails, status=200, body=self.emails_body + ) + self.do_partial_pipeline() + + +class BitbucketOAuth1FailTest(BitbucketOAuth1Test): + emails_body = json.dumps( + { + "page": 1, + "pagelen": 10, + "size": 1, + "values": [ + { + "email": "foo@bar.com", + "is_confirmed": False, + "is_primary": True, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/user/emails/foo@bar.com" + } + }, + "type": "email", + } + ], + } + ) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY": True}) + with self.assertRaises(AuthForbidden): + super().test_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY": True}) + with self.assertRaises(AuthForbidden): + super().test_partial_pipeline() + + +class BitbucketOAuth2Test(BitbucketOAuthMixin, OAuth2Test): + backend_path = "social_core.backends.bitbucket.BitbucketOAuth2" + + access_token_body = json.dumps( + { + "access_token": "foobar_access", + "scopes": "foo_scope", + "expires_in": 3600, + "refresh_token": "foobar_refresh", + "token_type": "bearer", + } + ) + + def test_login(self): + HTTPretty.register_uri( + HTTPretty.GET, self.bb_api_user_emails, status=200, body=self.emails_body + ) + self.do_login() + + def test_partial_pipeline(self): + HTTPretty.register_uri( + HTTPretty.GET, self.bb_api_user_emails, status=200, body=self.emails_body + ) + self.do_partial_pipeline() + + +class BitbucketOAuth2FailTest(BitbucketOAuth2Test): + emails_body = json.dumps( + { + "page": 1, + "pagelen": 10, + "size": 1, + "values": [ + { + "email": "foo@bar.com", + "is_confirmed": False, + "is_primary": True, + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/user/emails/foo@bar.com" + } + }, + "type": "email", + } + ], + } + ) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_BITBUCKET_OAUTH2_VERIFIED_EMAILS_ONLY": True} + ) + with self.assertRaises(AuthForbidden): + super().test_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_BITBUCKET_OAUTH2_VERIFIED_EMAILS_ONLY": True} + ) + with self.assertRaises(AuthForbidden): + super().test_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_box.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_box.py new file mode 100644 index 0000000000000000000000000000000000000000..5f70394ce2c5f944b3c1ea19e6db4401f6b1e1e1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_box.py @@ -0,0 +1,75 @@ +import json + +from .oauth import OAuth2Test + + +class BoxOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.box.BoxOAuth2" + user_data_url = "https://api.box.com/2.0/users/me" + expected_username = "sean+awesome@box.com" + access_token_body = json.dumps( + { + "access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl", + "expires_in": 3600, + "restricted_to": [], + "token_type": "bearer", + "refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bU" + "nsUfGMinKBDLZWP9BgR", + } + ) + user_data_body = json.dumps( + { + "type": "user", + "id": "181216415", + "name": "sean rose", + "login": "sean+awesome@box.com", + "created_at": "2012-05-03T21:39:11-07:00", + "modified_at": "2012-11-14T11:21:32-08:00", + "role": "admin", + "language": "en", + "space_amount": 11345156112, + "space_used": 1237009912, + "max_upload_size": 2147483648, + "tracking_codes": [], + "can_see_managed_users": True, + "is_sync_enabled": True, + "status": "active", + "job_title": "", + "phone": "6509241374", + "address": "", + "avatar_url": "https://www.box.com/api/avatar/large/181216415", + "is_exempt_from_device_limits": False, + "is_exempt_from_login_verification": False, + "enterprise": { + "type": "enterprise", + "id": "17077211", + "name": "seanrose enterprise", + }, + } + ) + refresh_token_body = json.dumps( + { + "access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl", + "expires_in": 3600, + "restricted_to": [], + "token_type": "bearer", + "refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9b" + "UnsUfGMinKBDLZWP9BgR", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def refresh_token_arguments(self): + uri = self.strategy.build_absolute_uri("/complete/box/") + return {"redirect_uri": uri} + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual( + social.extra_data["access_token"], "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl" + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_broken.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_broken.py new file mode 100644 index 0000000000000000000000000000000000000000..294c3e982db42ed16b50ba6d84da12690bc7b1df --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_broken.py @@ -0,0 +1,33 @@ +import unittest + +from ...backends.base import BaseAuth +from ..models import TestStorage +from ..strategy import TestStrategy + + +class BrokenBackendAuth(BaseAuth): + name = "broken" + + +class BrokenBackendTest(unittest.TestCase): + def setUp(self): + self.backend = BrokenBackendAuth(TestStrategy(TestStorage)) + + def tearDown(self): + self.backend = None + + def test_auth_url(self): + with self.assertRaisesRegex(NotImplementedError, "Implement in subclass"): + self.backend.auth_url() + + def test_auth_html(self): + with self.assertRaisesRegex(NotImplementedError, "Implement in subclass"): + self.backend.auth_html() + + def test_auth_complete(self): + with self.assertRaisesRegex(NotImplementedError, "Implement in subclass"): + self.backend.auth_complete() + + def test_get_user_details(self): + with self.assertRaisesRegex(NotImplementedError, "Implement in subclass"): + self.backend.get_user_details(None) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_chatwork.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_chatwork.py new file mode 100644 index 0000000000000000000000000000000000000000..ce4ae92b49d212c6b5bfaf3fa4ab0c9435a34aaa --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_chatwork.py @@ -0,0 +1,48 @@ +import json + +from .oauth import OAuth2Test + + +class ChatworkOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.chatwork.ChatworkOAuth2" + user_data_url = "https://api.chatwork.com/v2/me" + expected_username = "hogehoge" + access_token_body = json.dumps( + { + "access_token": "pyopyopyopyopyopyopyopyopyopyo", + "token_type": "Bearer", + "expires_in": "1501138041000", + "refresh_token": "pyopyopyopyopyopyo", + "scope": "rooms.all:read_write", + } + ) + + user_data_body = json.dumps( + { + "account_id": 123, + "room_id": 322, + "name": "Foo Bar", + "chatwork_id": "hogehoge", + "organization_id": 101, + "organization_name": "Foo foobar", + "department": "Support", + "title": "CMO", + "url": "http://www.example.com", + "introduction": "", + "mail": "hogehoge@example.com", + "tel_organization": "", + "tel_extension": "", + "tel_mobile": "", + "skype": "", + "facebook": "", + "twitter": "", + "avatar_image_url": "https://www.example.com/hogehoge.jpg", + "login_mail": "hogehoge@example.com", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cilogon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cilogon.py new file mode 100644 index 0000000000000000000000000000000000000000..b8b9feb1c191a4fdd2cc762bc7282e79f8807cd4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cilogon.py @@ -0,0 +1,39 @@ +import json + +from .oauth import OAuth2Test + + +class CILogonOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.cilogon.CILogonOAuth2" + user_data_url = "https://cilogon.org/oauth2/userinfo" + user_data_url_post = True + expected_username = "jbasney@illinois.edu" + access_token_body = json.dumps( + { + "access_token": "https://cilogon.org/oauth2/accessToken/sample-token123", + "refresh_token": "https://cilogon.org/oauth2/refreshToken/sample123/refresh-token123", + "id_token": "aBigStringOfRandomChars.123abc", + "token_type": "Bearer", + "expires_in": 900, + } + ) + user_data_body = json.dumps( + { + "sub": "http://cilogon.org/serverA/users/534", + "idp_name": "University of Illinois at Urbana-Champaign", + "idp": "urn:mace:incommon:uiuc.edu", + "affiliation": "employee@illinois.edu;member@illinois.edu;staff@illinois.edu", + "eppn": "jbasney@illinois.edu", + "eptid": "urn:mace:incommon:uiuc.edu!https://cilogon.org/shibboleth!cyXC3O5fi0t1NBsW1NsOxZDyDd4=", + "name": "James Alan Basney", + "given_name": "James", + "family_name": "Basney", + "email": "jbasney@illinois.edu", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_clef.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_clef.py new file mode 100644 index 0000000000000000000000000000000000000000..d50e05f5999b74991a76dd2c1264babd6923c43d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_clef.py @@ -0,0 +1,26 @@ +import json + +from .oauth import OAuth2Test + + +class ClefOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.clef.ClefOAuth2" + user_data_url = "https://clef.io/api/v1/info" + expected_username = "test" + access_token_body = json.dumps({"access_token": "foobar"}) + user_data_body = json.dumps( + { + "info": { + "id": "123456789", + "first_name": "Test", + "last_name": "User", + "email": "test@example.com", + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cognito.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cognito.py new file mode 100644 index 0000000000000000000000000000000000000000..aa4f8228b3588963f5ca28a9274ee4cf75a48165 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_cognito.py @@ -0,0 +1,37 @@ +import json + +from .oauth import OAuth2Test + + +class CognitoAuth2Test(OAuth2Test): + backend_path = "social_core.backends.cognito.CognitoOAuth2" + pool_domain = "https://social_core.auth.eu-west-1.amazoncognito.com" + expected_username = "cognito.account.ABCDE1234" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "given_name": "John", + "family_name": "Doe", + "username": "cognito.account.ABCDE1234", + "email": "john@doe.test", + } + ) + + @property + def user_data_url(self): + return self.backend.user_data_url() + + def extra_settings(self): + settings = super().extra_settings() + settings.update( + { + "SOCIAL_AUTH_" + self.name + "_POOL_DOMAIN": self.pool_domain, + } + ) + return settings + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coinbase.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coinbase.py new file mode 100644 index 0000000000000000000000000000000000000000..5d3c0d2d549edce613dc6629b87719f756217da8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coinbase.py @@ -0,0 +1,31 @@ +import json + +from .oauth import OAuth2Test + + +class CoinbaseOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.coinbase.CoinbaseOAuth2" + user_data_url = "https://api.coinbase.com/v2/user" + expected_username = "satoshi_nakomoto" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "data": { + "id": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", + "name": "Satoshi Nakamoto", + "username": "satoshi_nakomoto", + "profile_location": None, + "profile_bio": None, + "profile_url": "https://coinbase.com/satoshi_nakomoto", + "avatar_url": None, + "resource": "user", + "resource_path": "/v2/user", + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coursera.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coursera.py new file mode 100644 index 0000000000000000000000000000000000000000..b85ca702ae7d3f677b3a615ec9ebf22de89449e4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_coursera.py @@ -0,0 +1,37 @@ +import json + +from .oauth import OAuth2Test + + +class CourseraOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.coursera.CourseraOAuth2" + user_data_url = "https://api.coursera.org/api/externalBasicProfiles.v1?q=me" + expected_username = "560e7ed2076e0d589e88bd74b6aad4b7" + access_token_body = json.dumps( + {"access_token": "foobar", "token_type": "Bearer", "expires_in": 1795} + ) + request_token_body = json.dumps( + { + "code": "foobar-code", + "client_id": "foobar-client-id", + "client_secret": "foobar-client-secret", + "redirect_uri": "http://localhost:8000/accounts/coursera/", + "grant_type": "authorization_code", + } + ) + user_data_body = json.dumps( + { + "token_type": "Bearer", + "paging": None, + "elements": [{"id": "560e7ed2076e0d589e88bd74b6aad4b7"}], + "access_token": "foobar", + "expires_in": 1800, + "linked": None, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dailymotion.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dailymotion.py new file mode 100644 index 0000000000000000000000000000000000000000..2204f11a2c19c50cae7bfa5820483cdbd2eb98d0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dailymotion.py @@ -0,0 +1,17 @@ +import json + +from .oauth import OAuth2Test + + +class DailymotionOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.dailymotion.DailymotionOAuth2" + user_data_url = "https://api.dailymotion.com/auth/" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps({"id": "foobar", "screenname": "foobar"}) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_deezer.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_deezer.py new file mode 100644 index 0000000000000000000000000000000000000000..3fe682280f75e51276361d09b01f5201e7c425fc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_deezer.py @@ -0,0 +1,38 @@ +import json + +from .oauth import OAuth2Test + + +class DeezerOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.deezer.DeezerOAuth2" + user_data_url = "http://api.deezer.com/user/me" + expected_username = "foobar" + access_token_body = "access_token=foobar&expires=0" + user_data_body = json.dumps( + { + "id": "1", + "name": "foobar", + "lastname": "", + "firstname": "", + "status": 0, + "birthday": "1970-01-01", + "inscription_date": "2015-01-01", + "gender": "M", + "link": "https://www.deezer.com/profile/1", + "picture": "https://api.deezer.com/user/1/image", + "picture_small": "https://cdns-images.dzcdn.net/images/user//56x56-000000-80-0-0.jpg", + "picture_medium": "https://cdns-images.dzcdn.net/images/user//250x250-000000-80-0-0.jpg", + "picture_big": "https://cdns-images.dzcdn.net/images/user//500x500-000000-80-0-0.jpg", + "country": "FR", + "lang": "FR", + "is_kid": False, + "tracklist": "https://api.deezer.com/user/1/flow", + "type": "user", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_digitalocean.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_digitalocean.py new file mode 100644 index 0000000000000000000000000000000000000000..67f69271b96bca1682b5d58e4a8dce4d1d55113d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_digitalocean.py @@ -0,0 +1,35 @@ +import json + +from .oauth import OAuth2Test + + +class DigitalOceanOAuthTest(OAuth2Test): + backend_path = "social_core.backends.digitalocean.DigitalOceanOAuth" + user_data_url = "https://api.digitalocean.com/v2/account" + expected_username = "sammy@digitalocean.com" + access_token_body = json.dumps( + { + "access_token": "547cac21118ae7", + "token_type": "bearer", + "expires_in": 2592000, + "refresh_token": "00a3aae641658d", + "scope": "read write", + "info": {"name": "Sammy Shark", "email": "sammy@digitalocean.com"}, + } + ) + user_data_body = json.dumps( + { + "account": { + "droplet_limit": 25, + "email": "sammy@digitalocean.com", + "uuid": "b6fr89dbf6d9156cace5f3c78dc9851d957381ef", + "email_verified": True, + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_discourse.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_discourse.py new file mode 100644 index 0000000000000000000000000000000000000000..ae290461873752f676c2c87f8c0fde6ff001d650 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_discourse.py @@ -0,0 +1,80 @@ +from urllib.parse import parse_qs, urlparse + +import requests +from httpretty import HTTPretty + +from ...exceptions import AuthException +from .base import BaseBackendTest + + +class DiscourseTest(BaseBackendTest): + backend_path = "social_core.backends.discourse.DiscourseAuth" + expected_username = "beepboop" + raw_complete_url = "/complete/{0}/" + + def post_start(self): + pass + + def do_start(self): + self.post_start() + start = self.backend.start() + start_url = start.url + return_url = self.backend.redirect_uri + # NOTE: This is how we generated sso: + # sso = b64encode(urlencode({ + # 'email': 'user@example.com', + # 'username': 'beepboop', + # 'nonce': '6YRje7xlXhpyeJ6qtvBeTUjHkXo1UCTQmCrzN8GXfja3AoAFk2' + \ + # 'CieDRYgSqMYi4W', + # 'return_sso_url': 'http://myapp.com' + # })) + sso = ( + "dXNlcm5hbWU9YmVlcGJvb3Ambm9uY2U9NllSamU3eGxYaHB5ZUo2cXR2QmV" + + "UVWpIa1hvMVVDVFFtQ3J6TjhHWGZqYTNBb0FGazJDaWVEUllnU3FNWWk0Vy" + + "ZlbWFpbD11c2VyJTQwZXhhbXBsZS5jb20mcmV0dXJuX3Nzb191cmw9aHR0c" + + "CUzQSUyRiUyRm15YXBwLmNvbQ==" + ) + # NOTE: the signature was verified using the 'foo' key, like so: + # hmac.new('foo', sso, sha256).hexdigest() + sig = "04063f17c99a97b1a765c1e0d7bbb61afb8471d79a39ddcd6af5ba3c93eb10e1" + response_query_params = f"sso={sso}&sig={sig}" + + response_url = f"{return_url}?{response_query_params}" + HTTPretty.register_uri( + HTTPretty.GET, start_url, status=301, location=response_url + ) + HTTPretty.register_uri( + HTTPretty.GET, + return_url, + status=200, + content_type="text/html", + ) + + response = requests.get(start_url) + query_values = { + k: v[0] for k, v in parse_qs(urlparse(response.url).query).items() + } + self.strategy.set_request_data(query_values, self.backend) + + return self.backend.complete() + + def test_login(self): + """ + Test that we can authenticate with the Discourse IdP + """ + # pretend we've started with a URL like /login/discourse: + self.strategy.set_settings( + {"SERVER_URL": "http://example.com", "SECRET": "foo"} + ) + self.do_login() + + def test_failed_login(self): + """ + Test that authentication fails when our request is signed with a + different secret than our payload + """ + self.strategy.set_settings( + {"SERVER_URL": "http://example.com", "SECRET": "bar"} + ) + with self.assertRaises(AuthException): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_disqus.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_disqus.py new file mode 100644 index 0000000000000000000000000000000000000000..5b6dfef29e875f472c2267d987379a6c00301761 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_disqus.py @@ -0,0 +1,61 @@ +import json + +from .oauth import OAuth2Test + + +class DisqusOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.disqus.DisqusOAuth2" + user_data_url = "https://disqus.com/api/3.0/users/details.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "code": 0, + "response": { + "username": "foobar", + "numFollowers": 0, + "isFollowing": False, + "numFollowing": 0, + "name": "Foo Bar", + "numPosts": 0, + "url": "", + "isAnonymous": False, + "rep": 1.231755, + "about": "", + "isFollowedBy": False, + "connections": {}, + "emailHash": "5280f14cedf530b544aecc31fcfe0240", + "reputation": 1.231755, + "avatar": { + "small": { + "permalink": "https://disqus.com/api/users/avatars/" + "foobar.jpg", + "cache": "https://securecdn.disqus.com/uploads/" + "users/453/4556/avatar32.jpg?1285535379", + }, + "isCustom": False, + "permalink": "https://disqus.com/api/users/avatars/foobar.jpg", + "cache": "https://securecdn.disqus.com/uploads/users/453/" + "4556/avatar92.jpg?1285535379", + "large": { + "permalink": "https://disqus.com/api/users/avatars/" + "foobar.jpg", + "cache": "https://securecdn.disqus.com/uploads/users/" + "453/4556/avatar92.jpg?1285535379", + }, + }, + "profileUrl": "http://disqus.com/foobar/", + "numLikesReceived": 0, + "isPrimary": True, + "joinedAt": "2010-09-26T21:09:39", + "id": "1010101", + "location": "", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dribbble.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dribbble.py new file mode 100644 index 0000000000000000000000000000000000000000..e6f5be499ea74bb57a9ab1488627119d439bcbbe --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dribbble.py @@ -0,0 +1,21 @@ +import json + +from .oauth import OAuth2Test + + +class DribbbleOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.dribbble.DribbbleOAuth2" + user_data_url = "https://api.dribbble.com/v1/user" + expected_username = "foobar" + + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + + user_data_body = json.dumps( + {"id": "foobar", "username": "foobar", "name": "Foo Bar"} + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_drip.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_drip.py new file mode 100644 index 0000000000000000000000000000000000000000..117707d51302fed59906103278903a02dad344c5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_drip.py @@ -0,0 +1,22 @@ +import json + +from .oauth import OAuth2Test + + +class DripOAuthTest(OAuth2Test): + backend_path = "social_core.backends.drip.DripOAuth" + user_data_url = "https://api.getdrip.com/v2/user" + expected_username = "other@example.com" + access_token_body = json.dumps( + {"access_token": "822bbf7cd12243df", "token_type": "bearer", "scope": "public"} + ) + + user_data_body = json.dumps( + {"users": [{"email": "other@example.com", "name": None}]} + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dropbox.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dropbox.py new file mode 100644 index 0000000000000000000000000000000000000000..65154aef113788c65b1acb463f97e548760de838 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dropbox.py @@ -0,0 +1,29 @@ +import json + +from .oauth import OAuth2Test + + +class DropboxOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.dropbox.DropboxOAuth2V2" + user_data_url = "https://api.dropboxapi.com/2/users/get_current_account" + user_data_url_post = True + expected_username = "dbidAAH4f99T0taONIb-OurWxbNQ6ywGRopQngc" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "account_id": "dbid:AAH4f99T0taONIb-OurWxbNQ6ywGRopQngc", + "name": { + "given_name": "Franz", + "surname": "Ferdinand", + "familiar_name": "Franz", + "display_name": "Franz Ferdinand (Personal)", + "abbreviated_name": "FF", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dummy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dummy.py new file mode 100644 index 0000000000000000000000000000000000000000..71531a37fa0921ff33eaf40bdde50f24281aba7d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_dummy.py @@ -0,0 +1,154 @@ +import datetime +import json +import time + +from httpretty import HTTPretty + +from ...actions import do_disconnect +from ...backends.oauth import BaseOAuth2 +from ...exceptions import AuthForbidden +from ..models import User +from .oauth import OAuth2Test + + +class DummyOAuth2(BaseOAuth2): + name = "dummy" + AUTHORIZATION_URL = "http://dummy.com/oauth/authorize" + ACCESS_TOKEN_URL = "http://dummy.com/oauth/access_token" + REVOKE_TOKEN_URL = "https://dummy.com/oauth/revoke" + REVOKE_TOKEN_METHOD = "GET" + GET_ALL_EXTRA_DATA = False + EXTRA_DATA = [("id", "id"), ("expires", "expires"), ("empty", "empty", True), "url"] + + def get_user_details(self, response): + """Return user details from Github account""" + return { + "username": response.get("username"), + "email": response.get("email", ""), + "first_name": response.get("first_name", ""), + "last_name": response.get("last_name", ""), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + return self.get_json( + "http://dummy.com/user", params={"access_token": access_token} + ) + + +class Dummy2OAuth2(DummyOAuth2): + GET_ALL_EXTRA_DATA = True + + +class DummyOAuth2Test(OAuth2Test): + backend_path = "social_core.tests.backends.test_dummy.DummyOAuth2" + user_data_url = "http://dummy.com/user" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "id": 1, + "username": "foobar", + "url": "http://dummy.com/user/foobar", + "first_name": "Foo", + "last_name": "Bar", + "email": "foo@bAr.coM", # mixed case domain for testing case sensitivity + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_tokens(self): + user = self.do_login() + self.assertEqual(user.social[0].access_token, "foobar") + + def test_revoke_token(self): + self.strategy.set_settings({"SOCIAL_AUTH_REVOKE_TOKENS_ON_DISCONNECT": True}) + self.do_login() + user = User.get(self.expected_username) + user.password = "password" + HTTPretty.register_uri( + self._method(self.backend.REVOKE_TOKEN_METHOD), + self.backend.REVOKE_TOKEN_URL, + status=200, + ) + do_disconnect(self.backend, user) + + +class WhitelistEmailsTest(DummyOAuth2Test): + def test_valid_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_EMAILS": ["foo@bar.com"]}) + self.do_login() + + def test_invalid_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_EMAILS": ["foo2@bar.com"]}) + with self.assertRaises(AuthForbidden): + self.do_login() + + def test_login_case_sensitive_local_part(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_EMAILS": ["fOo@bar.com"]}) + self.do_login() + + def test_login_case_sensitive_domain(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_EMAILS": ["foo@bAR.com"]}) + self.do_login() + + +class WhitelistDomainsTest(DummyOAuth2Test): + def test_valid_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_DOMAINS": ["bar.com"]}) + self.do_login() + + def test_invalid_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_WHITELISTED_EMAILS": ["bar2.com"]}) + with self.assertRaises(AuthForbidden): + self.do_login() + + +DELTA = datetime.timedelta(days=1) + + +class ExpirationTimeTest(DummyOAuth2Test): + user_data_body = json.dumps( + { + "id": 1, + "username": "foobar", + "url": "http://dummy.com/user/foobar", + "first_name": "Foo", + "last_name": "Bar", + "email": "foo@bar.com", + "expires": time.mktime((datetime.datetime.utcnow() + DELTA).timetuple()), + } + ) + + def test_expires_time(self): + user = self.do_login() + social = user.social[0] + expiration = social.expiration_timedelta() + self.assertEqual(expiration <= DELTA, True) + + +class AllExtraDataTest(DummyOAuth2Test): + backend_path = "social_core.tests.backends.test_dummy.Dummy2OAuth2" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "id": 1, + "username": "foobar", + "url": "http://dummy.com/user/foobar", + "first_name": "Foo", + "last_name": "Bar", + "email": "foo@bar.com", + "not_normally_in_extra_data": "value", + } + ) + + def test_get_all_extra_data(self): + user = self.do_login() + social = user.social[0] + self.assertIn("not_normally_in_extra_data", social.extra_data) + self.assertEqual(len(social.extra_data), 10) # Includes auth_time. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_edmodo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_edmodo.py new file mode 100644 index 0000000000000000000000000000000000000000..b2ea1bd6d03b3882b3ff7c6d70c8aae686f15fb5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_edmodo.py @@ -0,0 +1,43 @@ +import json + +from .oauth import OAuth2Test + + +class EdmodoOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.edmodo.EdmodoOAuth2" + user_data_url = "https://api.edmodo.com/users/me" + expected_username = "foobar12345" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "username": "foobar12345", + "coppa_verified": False, + "first_name": "Foo", + "last_name": "Bar", + "premium": False, + "verified_institution_member": False, + "url": "https://api.edmodo.com/users/12345", + "type": "teacher", + "time_zone": None, + "end_level": None, + "start_level": None, + "locale": "en", + "subjects": None, + "utc_offset": None, + "email": "foo.bar@example.com", + "gender": None, + "about": None, + "user_title": None, + "id": 12345, + "avatars": { + "small": "https://api.edmodo.com/users/12345/avatar?type=small&u=5a15xug93m53mi4ey3ck4fvkq", + "large": "https://api.edmodo.com/users/12345/avatar?type=large&u=5a15xug93m53mi4ey3ck4fvkq", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_elixir.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_elixir.py new file mode 100644 index 0000000000000000000000000000000000000000..2792eead7f914c120f09e41e97301bc565d9faf9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_elixir.py @@ -0,0 +1,183 @@ +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class ElixirOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.elixir.ElixirOpenIdConnect" + issuer = "https://login.elixir-czech.org/oidc/" + openid_config_body = """ + { + "claims_supported": [ + "sub", + "name", + "preferred_username", + "given_name", + "family_name", + "middle_name", + "nickname", + "profile", + "picture", + "website", + "gender", + "zoneinfo", + "locale", + "updated_at", + "birthdate", + "email", + "email_verified", + "phone_number", + "phone_number_verified", + "address" + ], + "op_policy_uri": "https://login.elixir-czech.org/oidc/about", + "subject_types_supported": [ + "public", + "pairwise" + ], + "request_parameter_supported": true, + "userinfo_signing_alg_values_supported": [ + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512", + "ES256", + "ES384", + "ES512", + "PS256", + "PS384", + "PS512" + ], + "revocation_endpoint": "https://login.elixir-czech.org/oidc/revoke", + "issuer": "https://login.elixir-czech.org/oidc/", + "id_token_encryption_enc_values_supported": [ + "A256CBC+HS512", + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512", + "A128CBC+HS256" + ], + "require_request_uri_registration": false, + "grant_types_supported": [ + "authorization_code", + "implicit", + "urn:ietf:params:oauth:grant-type:jwt-bearer", + "client_credentials", + "urn:ietf:params:oauth:grant_type:redelegate", + "urn:ietf:params:oauth:grant-type:device_code" + ], + "token_endpoint": "https://login.elixir-czech.org/oidc/token", + "request_uri_parameter_supported": false, + "service_documentation": "https://login.elixir-czech.org/oidc/about", + "registration_endpoint": "https://login.elixir-czech.org/oidc/register", + "jwks_uri": "https://login.elixir-czech.org/oidc/jwk", + "userinfo_encryption_alg_values_supported": [ + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5" + ], + "scopes_supported": [], + "token_endpoint_auth_methods_supported": [ + "client_secret_post", + "client_secret_basic", + "client_secret_jwt", + "private_key_jwt", + "none" + ], + "userinfo_encryption_enc_values_supported": [ + "A256CBC+HS512", + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512", + "A128CBC+HS256" + ], + "claim_types_supported": [ + "normal" + ], + "request_object_encryption_enc_values_supported": [ + "A256CBC+HS512", + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512", + "A128CBC+HS256" + ], + "claims_parameter_supported": false, + "id_token_encryption_alg_values_supported": [ + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5" + ], + "code_challenge_methods_supported": [ + "plain", + "S256" + ], + "token_endpoint_auth_signing_alg_values_supported": [ + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512", + "ES256", + "ES384", + "ES512", + "PS256", + "PS384", + "PS512" + ], + "userinfo_endpoint": "https://login.elixir-czech.org/oidc/userinfo", + "introspection_endpoint": "https://login.elixir-czech.org/oidc/introspect", + "id_token_signing_alg_values_supported": [ + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512", + "ES256", + "ES384", + "ES512", + "PS256", + "PS384", + "PS512", + "none" + ], + "device_authorization_endpoint": "https://login.elixir-czech.org/oidc/devicecode", + "op_tos_uri": "https://login.elixir-czech.org/oidc/about", + "request_object_encryption_alg_values_supported": [ + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5" + ], + "request_object_signing_alg_values_supported": [ + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512", + "ES256", + "ES384", + "ES512", + "PS256", + "PS384", + "PS512" + ], + "response_types_supported": [ + "code", + "token" + ], + "end_session_endpoint": "https://login.elixir-czech.org/oidc/endsession", + "authorization_endpoint": "https://login.elixir-czech.org/oidc/authorize" + } + """ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_email.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_email.py new file mode 100644 index 0000000000000000000000000000000000000000..9ff83f8bf38cd9a95302141a255af3b98e0f9686 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_email.py @@ -0,0 +1,19 @@ +from .legacy import BaseLegacyTest + + +class EmailTest(BaseLegacyTest): + backend_path = "social_core.backends.email.EmailAuth" + expected_username = "foo" + response_body = "email=foo@bar.com" + form = """ + <form method="post" action="{0}"> + <input name="email" type="text"> + <button>Submit</button> + </form> + """ + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_eventbrite.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_eventbrite.py new file mode 100644 index 0000000000000000000000000000000000000000..76ef5aa0dea48ce21c87a03fe76c08cd64cfee17 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_eventbrite.py @@ -0,0 +1,37 @@ +import json + +from .oauth import OAuth2Test + + +class EventbriteAuth2Test(OAuth2Test): + backend_path = "social_core.backends.eventbrite.EventbriteOAuth2" + user_data_url = "https://www.eventbriteapi.com/v3/users/me" + expected_username = "sean+awesome@eventbrite.com" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "first_name": "sean", + "last_name": "rose", + "name": "sean rose", + "access_token": "YQEN5H2W2OTKQZWZMYER", + "emails": [ + { + "verified": True, + "email": "sean+awesome2@eventbrite.com", + "primary": False, + }, + { + "verified": True, + "email": "sean+awesome@eventbrite.com", + "primary": True, + }, + ], + "token_type": "bearer", + "image_id": None, + "is_public": False, + "id": "128559602587", + } + ) + + def test_login(self): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_evernote.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_evernote.py new file mode 100644 index 0000000000000000000000000000000000000000..d61c82afa716da85afcc46d004a6f52be6499028 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_evernote.py @@ -0,0 +1,60 @@ +from urllib.parse import urlencode + +from requests import HTTPError + +from ...exceptions import AuthCanceled +from .oauth import OAuth1Test + + +class EvernoteOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.evernote.EvernoteOAuth" + expected_username = "101010" + access_token_body = urlencode( + { + "edam_webApiUrlPrefix": "https://sandbox.evernote.com/shard/s1/", + "edam_shard": "s1", + "oauth_token": "foobar", + "edam_expires": "1395118279645", + "edam_userId": "101010", + "edam_noteStoreUrl": "https://sandbox.evernote.com/shard/s1/notestore", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class EvernoteOAuth1CanceledTest(EvernoteOAuth1Test): + access_token_status = 401 + + def test_login(self): + with self.assertRaises(AuthCanceled) as cm: + self.do_login() + self.assertTrue(cm.exception.response is not None) + + def test_partial_pipeline(self): + with self.assertRaises(AuthCanceled) as cm: + self.do_partial_pipeline() + self.assertTrue(cm.exception.response is not None) + + +class EvernoteOAuth1ErrorTest(EvernoteOAuth1Test): + access_token_status = 500 + + def test_login(self): + with self.assertRaises(HTTPError): + self.do_login() + + def test_partial_pipeline(self): + with self.assertRaises(HTTPError): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_facebook.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_facebook.py new file mode 100644 index 0000000000000000000000000000000000000000..1dc3fa0e879dda6ecaba210aca457423626e4ea4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_facebook.py @@ -0,0 +1,110 @@ +import json + +from ...backends.facebook import API_VERSION +from ...exceptions import AuthCanceled, AuthUnknownError +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class FacebookOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.facebook.FacebookOAuth2" + user_data_url = "https://graph.facebook.com/v{version}/me".format( + version=API_VERSION + ) + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "username": "foobar", + "first_name": "Foo", + "last_name": "Bar", + "verified": True, + "name": "Foo Bar", + "gender": "male", + "updated_time": "2013-02-13T14:59:42+0000", + "link": "http://www.facebook.com/foobar", + "id": "110011001100010", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class FacebookOAuth2WrongUserDataTest(FacebookOAuth2Test): + user_data_body = "null" + + def test_login(self): + with self.assertRaises(AuthUnknownError): + self.do_login() + + def test_partial_pipeline(self): + with self.assertRaises(AuthUnknownError): + self.do_partial_pipeline() + + +class FacebookOAuth2AuthCancelTest(FacebookOAuth2Test): + access_token_status = 400 + access_token_body = json.dumps( + { + "error": { + "message": "redirect_uri isn't an absolute URI. Check RFC 3986.", + "code": 191, + "type": "OAuthException", + "fbtrace_id": "123Abc", + } + } + ) + + def test_login(self): + with self.assertRaises(AuthCanceled) as cm: + self.do_login() + self.assertIn("error", cm.exception.response.json()) + + def test_partial_pipeline(self): + with self.assertRaises(AuthCanceled) as cm: + self.do_partial_pipeline() + self.assertIn("error", cm.exception.response.json()) + + +class FacebookLimitedLoginTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.facebook.FacebookLimitedLogin" + issuer = "https://facebook.com" + openid_config_body = """ + { + "issuer": "https://facebook.com", + "authorization_endpoint": "https://facebook.com/dialog/oauth/", + "jwks_uri": "https://facebook.com/.well-known/oauth/openid/jwks/", + "response_types_supported": [ + "id_token", + "token id_token" + ], + "subject_types_supported": "pairwise", + "id_token_signing_alg_values_supported": [ + "RS256" + ], + "claims_supported": [ + "iss", + "aud", + "sub", + "iat", + "exp", + "jti", + "nonce", + "at_hash", + "name", + "email", + "picture", + "user_friends", + "user_birthday", + "user_age_range" + ] + } + """ + + def test_invalid_nonce(self): + # The nonce isn't generated server-side so the test isn't relevant here. + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fence.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fence.py new file mode 100644 index 0000000000000000000000000000000000000000..83f1368485a95e9ec77c97840fda70000bb6e6b0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fence.py @@ -0,0 +1,45 @@ +import json + +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class FenceOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.fence.Fence" + issuer = "https://nci-crdc.datacommons.io/" + openid_config_body = json.dumps( + { + "issuer": "https://nci-crdc.datacommons.io/", + "authorization_endpoint": "https://nci-crdc.datacommons.io/user/oauth2/authorize", + "userinfo_endpoint": "https://nci-crdc.datacommons.io/user/user/", + "token_endpoint": "https://nci-crdc.datacommons.io/user/oauth2/token", + "revocation_endpoint": "https://nci-crdc.datacommons.io/user/oauth2/revoke", + "jwks_uri": "https://auth.globus.org/jwk.json", + "response_types_supported": ["code", "token", "token id_token", "id_token"], + "id_token_signing_alg_values_supported": ["RS512"], + "scopes_supported": [ + "ga4gh_passport_v1", + "openid", + "google_credentials", + "google_service_account", + "data", + "user", + "google_link", + "admin", + "fence", + ], + "token_endpoint_auth_methods_supported": ["authorization_code", "implicit"], + "claims_supported": [ + "aud", + "sub", + "iss", + "exp", + "jti", + "auth_time", + "azp", + "nonce", + "context", + ], + "subject_types_supported": ["public"], + } + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fitbit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fitbit.py new file mode 100644 index 0000000000000000000000000000000000000000..3734d3f3739f6196ed300450e33f1d4079c3396e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_fitbit.py @@ -0,0 +1,56 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class FitbitOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.fitbit.FitbitOAuth1" + expected_username = "foobar" + access_token_body = urlencode( + { + "oauth_token_secret": "a-secret", + "encoded_user_id": "101010", + "oauth_token": "foobar", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_url = "https://api.fitbit.com/1/user/-/profile.json" + user_data_body = json.dumps( + { + "user": { + "weightUnit": "en_US", + "strideLengthWalking": 0, + "displayName": "foobar", + "weight": 62.6, + "foodsLocale": "en_US", + "heightUnit": "en_US", + "locale": "en_US", + "gender": "NA", + "memberSince": "2011-12-26", + "offsetFromUTCMillis": -25200000, + "height": 0, + "timezone": "America/Los_Angeles", + "dateOfBirth": "", + "encodedId": "101010", + "avatar": "http://www.fitbit.com/images/profile/" + "defaultProfile_100_male.gif", + "waterUnit": "en_US", + "distanceUnit": "en_US", + "glucoseUnit": "en_US", + "strideLengthRunning": 0, + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_five_hundred_px.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_five_hundred_px.py new file mode 100644 index 0000000000000000000000000000000000000000..3d2100135c691b2bd53f587fbe086aef2f61064e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_five_hundred_px.py @@ -0,0 +1,102 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class FiveHundredPxOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.five_hundred_px.FiveHundredPxOAuth" + user_data_url = "https://api.500px.com/v1/users" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "user": { + "id": 10101010, + "username": "foobar", + "firstname": "", + "lastname": "", + "birthday": None, + "sex": 1, + "city": "", + "state": "", + "country": "", + "registration_date": "2011-11-11T00:00:00-00:00", + "about": "", + "usertype": 0, + "domain": "UserName.500px.com", + "fotomoto_on": False, + "locale": "en", + "show_nude": False, + "allow_sale_requests": 1, + "fullname": "UserName", + "userpic_url": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + "userpic_https_url": "https://graph.facebook.com/v2.7/" + "1000000000/picture?" + "height=100&width=100", + "cover_url": None, + "upgrade_status": 0, + "store_on": False, + "photos_count": 0, + "galleries_count": 0, + "affection": 51, + "in_favorites_count": 0, + "friends_count": 2, + "followers_count": 3, + "analytics_code": None, + "invite_pending": False, + "invite_accepted": False, + "email": "user@user.com", + "shadow_email": "user@user.com", + "upload_limit": 20, + "upload_limit_expiry": "2021-11-11T00:00:00-00:00", + "upgrade_type": 0, + "upgrade_status_expiry": "2011-11-21", + "portfolio_enabled": False, + "auth": {"facebook": 1, "twitter": 0, "google_oauth2": 1}, + "presubmit_for_licensing": None, + "contacts": {"facebook": "1000000000"}, + "equipment": {}, + "avatars": { + "default": { + "http": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + "https": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + }, + "large": { + "http": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + "https": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + }, + "small": { + "http": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + "https": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + }, + "tiny": { + "http": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + "https": "https://graph.facebook.com/v2.7/" + "1000000000/picture?height=100&width=100", + }, + }, + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flat.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flat.py new file mode 100644 index 0000000000000000000000000000000000000000..5a3005683fb3a34bcbffce783d84ddbef70d5f68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flat.py @@ -0,0 +1,35 @@ +import json + +from .oauth import OAuth2Test + + +class FlatOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.flat.FlatOAuth2" + user_data_url = "https://api.flat.io/v2/me" + expected_username = "vincent" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "id": "541a137946fd04d57cb2e3c0", + "username": "vincent", + "name": "Vincent Foo", + "printableName": "Vincent Foo", + "bio": "Foo bio", + "instruments": [], + "picture": "https://flat-prod-public.s3.amazonaws.com/00000000/a0d2cb86-ab1e-4fdb-9286-dd94aa6d386c.jpeg", + "registrationDate": "2014-09-17T23:04:25.042Z", + "htmlUrl": "https://flat.io/vincent", + "starredScoresCount": 85, + "likedScoresCount": 85, + "followersCount": 183, + "followingCount": 52, + "ownedPublicScoresCount": 15, + "isPowerUser": True, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flickr.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flickr.py new file mode 100644 index 0000000000000000000000000000000000000000..2c4409727a38e9a39293f13b4e0c764ab09f073f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_flickr.py @@ -0,0 +1,29 @@ +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class FlickrOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.flickr.FlickrOAuth" + expected_username = "foobar" + access_token_body = urlencode( + { + "oauth_token_secret": "a-secret", + "username": "foobar", + "oauth_token": "foobar", + "user_nsid": "10101010@N01", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_foursquare.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_foursquare.py new file mode 100644 index 0000000000000000000000000000000000000000..64c2878fb4da23e97987840fa297bb6de571ab9f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_foursquare.py @@ -0,0 +1,94 @@ +import json + +from .oauth import OAuth2Test + + +class FoursquareOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.foursquare.FoursquareOAuth2" + user_data_url = "https://api.foursquare.com/v2/users/self" + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "notifications": [{"item": {"unreadCount": 0}, "type": "notificationTray"}], + "meta": { + "errorType": "deprecated", + "code": 200, + "errorDetail": "Please provide an API version to avoid future " + "errors.See http://bit.ly/vywCav", + }, + "response": { + "user": { + "photo": "https://is0.4sqi.net/userpix_thumbs/" + "BYKIT01VN4T4BISN.jpg", + "pings": False, + "homeCity": "Foo, Bar", + "id": "1010101", + "badges": {"count": 0, "items": []}, + "friends": { + "count": 1, + "groups": [ + { + "count": 0, + "items": [], + "type": "friends", + "name": "Mutual friends", + }, + { + "count": 1, + "items": [ + { + "bio": "", + "gender": "male", + "firstName": "Baz", + "relationship": "friend", + "photo": "https://is0.4sqi.net/userpix_thumbs/" + "BYKIT01VN4T4BISN.jpg", + "lists": { + "groups": [ + { + "count": 1, + "items": [], + "type": "created", + } + ] + }, + "homeCity": "Baz, Qux", + "lastName": "Qux", + "tips": {"count": 0}, + "id": "10101010", + } + ], + "type": "others", + "name": "Other friends", + }, + ], + }, + "referralId": "u-1010101", + "tips": {"count": 0}, + "type": "user", + "todos": {"count": 0}, + "bio": "", + "relationship": "self", + "lists": {"groups": [{"count": 1, "items": [], "type": "created"}]}, + "photos": {"count": 0, "items": []}, + "checkinPings": "off", + "scores": {"max": 0, "checkinsCount": 0, "goal": 50, "recent": 0}, + "checkins": {"count": 0}, + "firstName": "Foo", + "gender": "male", + "contact": {"email": "foo@bar.com"}, + "lastName": "Bar", + "following": {"count": 0}, + "requests": {"count": 0}, + "mayorships": {"count": 0, "items": []}, + } + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitea.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitea.py new file mode 100644 index 0000000000000000000000000000000000000000..fb0c46cb062cbbfa1b4761fe1b1222df79300962 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitea.py @@ -0,0 +1,75 @@ +import json + +from .oauth import OAuth2Test + + +class GiteaOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.gitea.GiteaOAuth2" + user_data_url = "https://gitea.com/api/v1/user" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "expires_in": 7200, + "refresh_token": "barfoo", + } + ) + user_data_body = json.dumps( + { + "id": 123456, + "login": "foobar", + "full_name": "Foo Bar", + "email": "foobar@example.com", + "avatar_url": "https://gitea.com/user/avatar/foobar/-1", + "language": "en-US", + "is_admin": False, + "last_login": "2016-12-28T12:26:19+01:00", + "created": "2016-12-28T12:26:19+01:00", + "restricted": False, + "username": "foobar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class GiteaCustomDomainOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.gitea.GiteaOAuth2" + user_data_url = "https://example.com/api/v1/user" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "expires_in": 7200, + "refresh_token": "barfoo", + } + ) + user_data_body = json.dumps( + { + "id": 123456, + "login": "foobar", + "full_name": "Foo Bar", + "email": "foobar@example.com", + "avatar_url": "https://example.com/user/avatar/foobar/-1", + "language": "en-US", + "is_admin": False, + "last_login": "2016-12-28T12:26:19+01:00", + "created": "2016-12-28T12:26:19+01:00", + "restricted": False, + "username": "foobar", + } + ) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITEA_API_URL": "https://example.com"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITEA_API_URL": "https://example.com"}) + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github.py new file mode 100644 index 0000000000000000000000000000000000000000..a4edc8d67bb2b4efa9bd5d675287510a5bd079da --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github.py @@ -0,0 +1,207 @@ +import json + +from httpretty import HTTPretty + +from ...exceptions import AuthFailed +from .oauth import OAuth2Test + + +class GithubOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.github.GithubOAuth2" + user_data_url = "https://api.github.com/user" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "login": "foobar", + "id": 1, + "avatar_url": "https://github.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class GithubOAuth2NoEmailTest(GithubOAuth2Test): + user_data_body = json.dumps( + { + "login": "foobar", + "id": 1, + "avatar_url": "https://github.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_login(self): + url = "https://api.github.com/user/emails" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=200, + body=json.dumps(["foo@bar.com"]), + content_type="application/json", + ) + self.do_login() + + def test_login_next_format(self): + url = "https://api.github.com/user/emails" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=200, + body=json.dumps([{"email": "foo@bar.com"}]), + content_type="application/json", + ) + self.do_login() + + def test_partial_pipeline(self): + url = "https://api.github.com/user/emails" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=200, + body=json.dumps([{"email": "foo@bar.com"}]), + content_type="application/json", + ) + self.do_partial_pipeline() + + +class GithubOrganizationOAuth2Test(GithubOAuth2Test): + backend_path = "social_core.backends.github.GithubOrganizationOAuth2" + + def auth_handlers(self, start_url): + url = "https://api.github.com/orgs/foobar/members/foobar" + HTTPretty.register_uri(HTTPretty.GET, url, status=204, body="") + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ORG_NAME": "foobar"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ORG_NAME": "foobar"}) + self.do_partial_pipeline() + + +class GithubOrganizationOAuth2FailTest(GithubOAuth2Test): + backend_path = "social_core.backends.github.GithubOrganizationOAuth2" + + def auth_handlers(self, start_url): + url = "https://api.github.com/orgs/foobar/members/foobar" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=404, + body='{"message": "Not Found"}', + content_type="application/json", + ) + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ORG_NAME": "foobar"}) + with self.assertRaises(AuthFailed): + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ORG_NAME": "foobar"}) + with self.assertRaises(AuthFailed): + self.do_partial_pipeline() + + +class GithubTeamOAuth2Test(GithubOAuth2Test): + backend_path = "social_core.backends.github.GithubTeamOAuth2" + + def auth_handlers(self, start_url): + url = "https://api.github.com/teams/123/members/foobar" + HTTPretty.register_uri(HTTPretty.GET, url, status=204, body="") + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_TEAM_ID": "123"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_TEAM_ID": "123"}) + self.do_partial_pipeline() + + +class GithubTeamOAuth2FailTest(GithubOAuth2Test): + backend_path = "social_core.backends.github.GithubTeamOAuth2" + + def auth_handlers(self, start_url): + url = "https://api.github.com/teams/123/members/foobar" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=404, + body='{"message": "Not Found"}', + content_type="application/json", + ) + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_TEAM_ID": "123"}) + with self.assertRaises(AuthFailed): + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_TEAM_ID": "123"}) + with self.assertRaises(AuthFailed): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github_enterprise.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github_enterprise.py new file mode 100644 index 0000000000000000000000000000000000000000..115be7873d5739c6b0896ca40d5c85fc1c84be80 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_github_enterprise.py @@ -0,0 +1,304 @@ +import json + +from httpretty import HTTPretty + +from ...exceptions import AuthFailed +from .oauth import OAuth2Test + + +class GithubEnterpriseOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.github_enterprise.GithubEnterpriseOAuth2" + user_data_url = "https://www.example.com/api/v3/user" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "login": "foobar", + "id": 1, + "avatar_url": "https://www.example.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://www.example.com/api/v3/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://www.example.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://www.example.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": "https://www.example.com/api/v3"} + ) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": "https://www.example.com/api/v3"} + ) + self.do_partial_pipeline() + + +class GithubEnterpriseOAuth2NoEmailTest(GithubEnterpriseOAuth2Test): + user_data_body = json.dumps( + { + "login": "foobar", + "id": 1, + "avatar_url": "https://www.example.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://www.example.com/api/v3/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://www.example.com/blog", + "location": "San Francisco", + "email": "", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://www.example.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": "https://www.example.com/api/v3"} + ) + url = "https://www.example.com/api/v3/user/emails" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=200, + body=json.dumps(["foo@bar.com"]), + content_type="application/json", + ) + self.do_login() + + def test_login_next_format(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": "https://www.example.com/api/v3"} + ) + url = "https://www.example.com/api/v3/user/emails" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=200, + body=json.dumps([{"email": "foo@bar.com"}]), + content_type="application/json", + ) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": "https://www.example.com/api/v3"} + ) + HTTPretty.register_uri( + HTTPretty.GET, + "https://www.example.com/api/v3/user/emails", + status=200, + body=json.dumps([{"email": "foo@bar.com"}]), + content_type="application/json", + ) + self.do_partial_pipeline() + + +class GithubEnterpriseOrganizationOAuth2Test(GithubEnterpriseOAuth2Test): + backend_path = ( + "social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2" + ) + + def auth_handlers(self, start_url): + url = "https://www.example.com/api/v3/orgs/foobar/members/foobar" + HTTPretty.register_uri(HTTPretty.GET, url, status=204, body="") + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": "foobar"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": "foobar"}) + self.do_partial_pipeline() + + +class GithubEnterpriseOrganizationOAuth2FailTest(GithubEnterpriseOAuth2Test): + backend_path = ( + "social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2" + ) + + def auth_handlers(self, start_url): + url = "https://www.example.com/api/v3/orgs/foobar/members/foobar" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=404, + body='{"message": "Not Found"}', + content_type="application/json", + ) + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": "foobar"}) + with self.assertRaises(AuthFailed): + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": "foobar"}) + with self.assertRaises(AuthFailed): + self.do_partial_pipeline() + + +class GithubEnterpriseTeamOAuth2Test(GithubEnterpriseOAuth2Test): + backend_path = "social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2" + + def auth_handlers(self, start_url): + url = "https://www.example.com/api/v3/teams/123/members/foobar" + HTTPretty.register_uri(HTTPretty.GET, url, status=204, body="") + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": "123"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": "123"}) + self.do_partial_pipeline() + + +class GithubEnterpriseTeamOAuth2FailTest(GithubEnterpriseOAuth2Test): + backend_path = "social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2" + + def auth_handlers(self, start_url): + url = "https://www.example.com/api/v3/teams/123/members/foobar" + HTTPretty.register_uri( + HTTPretty.GET, + url, + status=404, + body='{"message": "Not Found"}', + content_type="application/json", + ) + return super().auth_handlers(start_url) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": "123"}) + with self.assertRaises(AuthFailed): + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": "https://www.example.com"} + ) + self.strategy.set_settings( + { + "SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": "https://www.example.com/api/v3" + } + ) + self.strategy.set_settings({"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": "123"}) + with self.assertRaises(AuthFailed): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitlab.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitlab.py new file mode 100644 index 0000000000000000000000000000000000000000..97048191d841cb0ec89ecd3254500207f951de06 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_gitlab.py @@ -0,0 +1,111 @@ +import json + +from .oauth import OAuth2Test + + +class GitLabOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.gitlab.GitLabOAuth2" + user_data_url = "https://gitlab.com/api/v4/user" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "expires_in": 7200, + "refresh_token": "barfoo", + } + ) + user_data_body = json.dumps( + { + "two_factor_enabled": False, + "can_create_project": True, + "confirmed_at": "2016-12-28T12:26:19.256Z", + "twitter": "", + "linkedin": "", + "color_scheme_id": 1, + "web_url": "https://gitlab.com/foobar", + "skype": "", + "identities": [], + "id": 123456, + "projects_limit": 100000, + "current_sign_in_at": "2016-12-28T12:26:19.795Z", + "state": "active", + "location": None, + "email": "foobar@example.com", + "website_url": "", + "username": "foobar", + "bio": None, + "last_sign_in_at": "2016-12-28T12:26:19.795Z", + "is_admin": False, + "external": False, + "organization": None, + "name": "Foo Bar", + "can_create_group": True, + "created_at": "2016-12-28T12:26:19.638Z", + "avatar_url": "https://secure.gravatar.com/avatar/94d093eda664addd6e450d7e9881bcae?s=32&d=identicon", + "theme_id": 2, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class GitLabCustomDomainOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.gitlab.GitLabOAuth2" + user_data_url = "https://example.com/api/v4/user" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "expires_in": 7200, + "refresh_token": "barfoo", + } + ) + user_data_body = json.dumps( + { + "two_factor_enabled": False, + "can_create_project": True, + "confirmed_at": "2016-12-28T12:26:19.256Z", + "twitter": "", + "linkedin": "", + "color_scheme_id": 1, + "web_url": "https://example.com/foobar", + "skype": "", + "identities": [], + "id": 123456, + "projects_limit": 100000, + "current_sign_in_at": "2016-12-28T12:26:19.795Z", + "state": "active", + "location": None, + "email": "foobar@example.com", + "website_url": "", + "username": "foobar", + "bio": None, + "last_sign_in_at": "2016-12-28T12:26:19.795Z", + "is_admin": False, + "external": False, + "organization": None, + "name": "Foo Bar", + "can_create_group": True, + "created_at": "2016-12-28T12:26:19.638Z", + "avatar_url": "https://secure.gravatar.com/avatar/94d093eda664addd6e450d7e9881bcae?s=32&d=identicon", + "theme_id": 2, + } + ) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITLAB_API_URL": "https://example.com"} + ) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GITLAB_API_URL": "https://example.com"} + ) + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_globus.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_globus.py new file mode 100644 index 0000000000000000000000000000000000000000..b5eecf22174f7827d16abbd9be3464bd33ae5500 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_globus.py @@ -0,0 +1,36 @@ +import json + +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class GlobusOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.globus.GlobusOpenIdConnect" + issuer = "https://auth.globus.org" + openid_config_body = json.dumps( + { + "issuer": "https://auth.globus.org", + "authorization_endpoint": "https://auth.globus.org/v2/oauth2/authorize", + "userinfo_endpoint": "https://auth.globus.org/v2/oauth2/userinfo", + "token_endpoint": "https://auth.globus.org/v2/oauth2/token", + "revocation_endpoint": "https://auth.globus.org/v2/oauth2/token/revoke", + "jwks_uri": "https://auth.globus.org/jwk.json", + "response_types_supported": ["code", "token", "token id_token", "id_token"], + "id_token_signing_alg_values_supported": ["RS512"], + "scopes_supported": ["openid", "email", "profile"], + "token_endpoint_auth_methods_supported": ["client_secret_basic"], + "claims_supported": [ + "at_hash", + "aud", + "email", + "exp", + "name", + "nonce", + "preferred_username", + "iat", + "iss", + "sub", + ], + "subject_types_supported": ["public"], + } + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_google.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_google.py new file mode 100644 index 0000000000000000000000000000000000000000..c20021cbbf1dffbde9f1ade8cab68bc6bbc278ea --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_google.py @@ -0,0 +1,165 @@ +import json +from urllib.parse import urlencode + +from httpretty import HTTPretty + +from ...actions import do_disconnect +from ..models import User +from .oauth import OAuth1Test, OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class GoogleOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.google.GoogleOAuth2" + user_data_url = "https://www.googleapis.com/oauth2/v3/userinfo" + expected_username = "foo" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "profile": "https://plus.google.com/101010101010101010101", + "family_name": "Bar", + "sub": "101010101010101010101", + "picture": "https://lh5.googleusercontent.com/-ui-GqpNh5Ms/" + "AAAAAAAAAAI/AAAAAAAAAZw/a7puhHMO_fg/photo.jpg", + "locale": "en", + "email_verified": True, + "given_name": "Foo", + "email": "foo@bar.com", + "name": "Foo Bar", + } + ) + + def test_login(self): + self.do_login() + last_request = HTTPretty.last_request + self.assertEqual(last_request.method, "GET") + self.assertTrue(self.user_data_url.endswith(last_request.path)) + self.assertEqual( + last_request.headers["Authorization"], + "Bearer foobar", + ) + self.assertEqual(last_request.querystring, {}) + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_with_unique_user_id(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_GOOGLE_OAUTH2_USE_UNIQUE_USER_ID": True, + } + ) + self.do_login() + + +class GoogleOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.google.GoogleOAuth" + user_data_url = "https://www.googleapis.com/userinfo/email" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = urlencode( + { + "email": "foobar@gmail.com", + "isVerified": "true", + "id": "101010101010101010101", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_with_unique_user_id(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GOOGLE_OAUTH_USE_UNIQUE_USER_ID": True} + ) + self.do_login() + + def test_with_anonymous_key_and_secret(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_GOOGLE_OAUTH_KEY": None, + "SOCIAL_AUTH_GOOGLE_OAUTH_SECRET": None, + } + ) + self.do_login() + + +class GoogleRevokeTokenTest(GoogleOAuth2Test): + def test_revoke_token(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_GOOGLE_OAUTH2_REVOKE_TOKENS_ON_DISCONNECT": True} + ) + self.do_login() + user = User.get(self.expected_username) + user.password = "password" + HTTPretty.register_uri( + self._method(self.backend.REVOKE_TOKEN_METHOD), + self.backend.REVOKE_TOKEN_URL, + status=200, + ) + do_disconnect(self.backend, user) + + +class GoogleOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.google_openidconnect.GoogleOpenIdConnect" + user_data_url = "https://www.googleapis.com/plus/v1/people/me/openIdConnect" + issuer = "accounts.google.com" + openid_config_body = json.dumps( + { + "issuer": "https://accounts.google.com", + "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth", + "token_endpoint": "https://www.googleapis.com/oauth2/v4/token", + "userinfo_endpoint": "https://www.googleapis.com/oauth2/v3/userinfo", + "revocation_endpoint": "https://accounts.google.com/o/oauth2/revoke", + "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs", + "response_types_supported": [ + "code", + "token", + "id_token", + "code token", + "code id_token", + "token id_token", + "code token id_token", + "none", + ], + "subject_types_supported": [ + "public", + ], + "id_token_signing_alg_values_supported": [ + "RS256", + ], + "scopes_supported": [ + "openid", + "email", + "profile", + ], + "token_endpoint_auth_methods_supported": [ + "client_secret_post", + "client_secret_basic", + ], + "claims_supported": [ + "aud", + "email", + "email_verified", + "exp", + "family_name", + "given_name", + "iat", + "iss", + "locale", + "name", + "picture", + "sub", + ], + } + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_grafana.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_grafana.py new file mode 100644 index 0000000000000000000000000000000000000000..36df09c4c01fdf4f712f7864713ca33400757d6e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_grafana.py @@ -0,0 +1,24 @@ +import json + +from .oauth import OAuth2Test + + +class GrafanaOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.grafana.GrafanaOAuth2" + user_data_url = "https://grafana.com/api/oauth2/user" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + } + ) + user_data_body = json.dumps( + {"login": "fooboy", "email": "foo@bar.com", "name": "Foo Bar"} + ) + expected_username = "fooboy" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_instagram.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_instagram.py new file mode 100644 index 0000000000000000000000000000000000000000..eb4fd3b42cef381145ef32b6c6a8396780562dab --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_instagram.py @@ -0,0 +1,26 @@ +import json + +from .oauth import OAuth2Test + + +class InstagramOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.instagram.InstagramOAuth2" + user_data_url = "https://graph.instagram.com/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "meta": {"code": 200}, + "user": {"username": "foobar", "id": "101010101"}, + } + ) + user_data_body = json.dumps( + {"meta": {"code": 200}, "username": "foobar", "id": "101010101"} + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_itembase.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_itembase.py new file mode 100644 index 0000000000000000000000000000000000000000..1e4a7baf782e35d51eac4fa02bc158007057eb75 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_itembase.py @@ -0,0 +1,51 @@ +import json + +from .oauth import OAuth2Test + + +class ItembaseOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.itembase.ItembaseOAuth2" + user_data_url = "https://users.itembase.com/v1/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar-token", + "expires_in": 2592000, + "token_type": "bearer", + "scope": "user.minimal", + "refresh_token": "foobar-refresh-token", + } + ) + user_data_body = json.dumps( + { + "uuid": "a4b91ee7-ec1a-49b9-afce-371dc8797749", + "username": "foobar", + "email": "foobar@itembase.biz", + "first_name": "Foo", + "middle_name": None, + "last_name": "Bar", + "name_format": "first middle last", + "locale": "en", + "preferred_currency": "EUR", + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "expires_in": 2592000, + "token_type": "bearer", + "scope": "user.minimal", + "refresh_token": "foobar-new-refresh-token", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class ItembaseOAuth2SandboxTest(OAuth2Test): + backend_path = "social_core.backends.itembase.ItembaseOAuth2Sandbox" + user_data_url = "http://sandbox.users.itembase.io/v1/me" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_kakao.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_kakao.py new file mode 100644 index 0000000000000000000000000000000000000000..ebb48f3baf56e4b3aa4af3e657c111aa769cefc2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_kakao.py @@ -0,0 +1,29 @@ +import json + +from .oauth import OAuth2Test + + +class KakaoOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.kakao.KakaoOAuth2" + user_data_url = "https://kapi.kakao.com/v2/user/me" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar"}) + user_data_body = json.dumps( + { + "id": "101010101", + "properties": { + "nickname": "foobar", + "thumbnail_image": "http://mud-kage.kakao.co.kr/14/dn/btqbh1AKmRf/" + "ujlHpQhxtMSbhKrBisrxe1/o.jpg", + "profile_image": "http://mud-kage.kakao.co.kr/14/dn/btqbjCnl06Q/" + "wbMJSVAUZB7lzSImgGdsoK/o.jpg", + }, + "kakao_account": {"email": "a"}, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_keycloak.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_keycloak.py new file mode 100644 index 0000000000000000000000000000000000000000..2c88b37bb41040472655599780bc67c830618241 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_keycloak.py @@ -0,0 +1,125 @@ +import json +import time + +import jwt + +from .oauth import OAuth2Test + +_PRIVATE_KEY_HEADERLESS = """ +MIIEowIBAAKCAQEAvyo2hx1L3ALHeUd/6xk/lIhTyZ/HJZ+Sss/ge6T6gPdES4Dw +BvwGlAp21iEbmjmizsv6+ZsyuKZUiC1J4A90lmIA57aYXHHoh9GBWQZzXeCNgghP +JpGYYSCN+1qeD4nbwD9cQBtPrGBpPpPtv2a/xdPqDm5ko6adMhmbm8e4Me/ppWPi +0U+skWQJepBhjEt3x+AOMKDv2TUBWOc3mYFNkr9qNOPe7FxnqUk6ZtkI3QNjZTky +AU7cat87u1vT5thAxVY18i1GfSZwtQbU3Ba6hXI5SIHB1lS88SJ9/+E/flJJPD2N +Nzv2z3HAVuTUOYi48fnXFHpJLGv+mGLNtE77hwIDAQABAoIBAQCUyQYno2Wnl4Ip +orys/rm9oV2VUAZwAgLrqV/O3Fkch1dgbLpktUNpdbuIbbxODQ3qZliwbVrM3Khu +VNFq0pyrbxvFPRjY2s9g5m8GGz8vkdaRnmX8XtV6wxu+xoi/D006FBZ4zsj0IRXI +3tnsXsxj7Mv+72zk8ojmtYend4qlUfzBVTpMRDc4XDC4Ya91fgFgfibtUE1qc8Ap +ctCzk9wZgN9SOKXHcKANhqC8BmQv7NspI0RT0Oq0n/U921P/+y1M++Z0Z2vQvjiR +GvDpSlnmlLB3S3E7zHbmksyUyK4Ab7xYi51yFKgrYjtaM3QLCTlSmTQBM8EhjZNG +VJvgEI4BAoGBAOQzd4PdB3jW6OnUXDrzWqfCAgpMxWtAmP5h+LrmsrV+upXggRnv +iNzTqiq0QpdrgYrikFGDkGEsqfrnd7IkskDMT8PMuncmDkuF67kg6G4/vzyz5QyA +jolf6qmHQPMCfxtCPUZZOUcuRKnj5KVIGfJu2gu5Z2lEysuV5ZQE0OiNAoGBANZz +wqLhqN376MT3YEbsOcWXYBDXX+FzWAYHsxf4APHJrNr6pkM4dTsvXU2tQIUV4N3c +SJvMVSI91VL8mdgQxHKaECUizye19brJ1BysbeFjBCK+Y6bYMd8n0Hdxxi/ZyeF9 +AzfIPQN2uZSzU/I+Nt0tlz/SCoL4Qi3FQpgtLoFjAoGAb8XVsDy+wC1jf8SIOEei +C7E3FpxrxhCp309VaRY+Si98bJS+J1nwC1mRa8FHLKt3k/NNBOAQA8jAqShetF7N +AHgSSbEpU9rL/anmv5Kixf1rSexDMFB3gEn+wnKBGYYLg+p54M8rAvZio2QARgR+ +0QQCwONbB3Cuc/FDtbB2MrECgYAhSqtGmf2bKIZEPZsGp5l4YT2an7TUzRE3Lm7R +I8ERyBs7i3nQKa2ZWIsFigXgIztbdd0Xwqrcu/in/2rqrf+xQtWKzlKWeZsCOl7h +bKtKOBLmSeQyfJGRcR7dzB3WQ9shVETxnfZK2V2KBiTcEGh4AaHfWH4lQuETNfJW +qXz0vQKBgDVz+ZvULA/OZWXrOI1il7KoahWdb9vr8VhWgHKnDW7hInDFh6SEQHn6 +mSNns0AssDwr4TheET7klb7AvbBKrNSP/Tz9AzkwMz148T2ffkPFMZRuvRT+eQ5Z +ey4gIBKESJF6X9fefiawCrI3+PC7x9x0ngP9R4t/OzDWVAYn9gmd +""".strip() + +_PRIVATE_KEY = """ +-----BEGIN RSA PRIVATE KEY----- +{_PRIVATE_KEY_HEADERLESS} +-----END RSA PRIVATE KEY----- +""".format( + _PRIVATE_KEY_HEADERLESS=_PRIVATE_KEY_HEADERLESS +) + +_PUBLIC_KEY_HEADERLESS = """ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyo2hx1L3ALHeUd/6xk/ +lIhTyZ/HJZ+Sss/ge6T6gPdES4DwBvwGlAp21iEbmjmizsv6+ZsyuKZUiC1J4A90 +lmIA57aYXHHoh9GBWQZzXeCNgghPJpGYYSCN+1qeD4nbwD9cQBtPrGBpPpPtv2a/ +xdPqDm5ko6adMhmbm8e4Me/ppWPi0U+skWQJepBhjEt3x+AOMKDv2TUBWOc3mYFN +kr9qNOPe7FxnqUk6ZtkI3QNjZTkyAU7cat87u1vT5thAxVY18i1GfSZwtQbU3Ba6 +hXI5SIHB1lS88SJ9/+E/flJJPD2NNzv2z3HAVuTUOYi48fnXFHpJLGv+mGLNtE77 +hwIDAQAB +""".strip() + +_PUBLIC_KEY = """ +-----BEGIN PUBLIC KEY----- +{_PUBLIC_KEY_HEADERLESS} +-----END PUBLIC KEY----- +""".format( + _PUBLIC_KEY_HEADERLESS=_PUBLIC_KEY_HEADERLESS +) + +_KEY = "example" +_SECRET = "1234abcd-1234-abcd-1234-abcd1234adcd" + +_AUTHORIZATION_URL = ( + "https://sso.example.com/auth/realms/example/protocol/openid-connect/auth" +) +_ACCESS_TOKEN_URL = ( + "https://sso.example.com/auth/realms/example/protocol/openid-connect/token" +) + +_ALGORITHM = "RS256" +_AUTH_TIME = int(time.time()) +_PAYLOAD = { + "preferred_username": "john.doe", + "email": "john.doe@example.com", + "name": "John Doe", + "given_name": "John", + "family_name": "Doe", + "iss": "https://sso.example.com", + "sub": "john.doe", + "aud": _KEY, + "exp": _AUTH_TIME + 3600, + "iat": _AUTH_TIME, +} + + +def _encode(payload, key=_PRIVATE_KEY, algorithm=_ALGORITHM): + return jwt.encode(payload, key=key, algorithm=algorithm) + + +def _decode(token, key=_PUBLIC_KEY, algorithms=[_ALGORITHM], audience=_KEY): + return jwt.decode(token, key=key, algorithms=algorithms, audience=audience) + + +class KeycloakOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.keycloak.KeycloakOAuth2" + expected_username = "john.doe" + access_token_body = json.dumps( + { + "token_type": "Bearer", + "id_token": _encode(_PAYLOAD), + "access_token": _encode(_PAYLOAD), + } + ) + + def extra_settings(self): + return { + "SOCIAL_AUTH_KEYCLOAK_KEY": _KEY, + "SOCIAL_AUTH_KEYCLOAK_SECRET": _SECRET, + "SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY": _PUBLIC_KEY_HEADERLESS, + "SOCIAL_AUTH_KEYCLOAK_ALGORITHM": _ALGORITHM, + "SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL": _AUTHORIZATION_URL, + "SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL": _ACCESS_TOKEN_URL, + } + + def test_encode_decode(self): + token = _encode(_PAYLOAD) + self.assertEqual(_PAYLOAD, _decode(token)) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_khanacademy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_khanacademy.py new file mode 100644 index 0000000000000000000000000000000000000000..c9a426ff837a7e443bf4fd140923f7f9f0fb2f9a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_khanacademy.py @@ -0,0 +1,30 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class KhanAcademyOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.khanacademy.KhanAcademyOAuth1" + user_data_url = "https://www.khanacademy.org/api/v1/user" + expected_username = "foo@bar.com" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "email": "foo@bar.com", + "user_id": "http://googleid.khanacademy.org/11111111111111", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_linkedin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_linkedin.py new file mode 100644 index 0000000000000000000000000000000000000000..ff9f7d27c46fb88a144aef8705052d2aeb44cc2a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_linkedin.py @@ -0,0 +1,42 @@ +import json + +from .oauth import OAuth2Test + + +class BaseLinkedinTest: + user_data_url = ( + "https://api.linkedin.com/v2/me" "?projection=(firstName,id,lastName)" + ) + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + + # Reference: + # https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self + # -serve/sign-in-with-linkedin?context=linkedin/consumer/context#api-request + user_data_body = json.dumps( + { + "id": "1010101010", + "firstName": { + "localized": {"en_US": "Foo"}, + "preferredLocale": {"country": "US", "language": "en"}, + }, + "lastName": { + "localized": {"en_US": "Bar"}, + "preferredLocale": {"country": "US", "language": "en"}, + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class LinkedinOAuth2Test(BaseLinkedinTest, OAuth2Test): + backend_path = "social_core.backends.linkedin.LinkedinOAuth2" + + +class LinkedinMobileOAuth2Test(BaseLinkedinTest, OAuth2Test): + backend_path = "social_core.backends.linkedin.LinkedinMobileOAuth2" diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_live.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_live.py new file mode 100644 index 0000000000000000000000000000000000000000..0edebee93893a56679a5c6a52a42dca4cf39ae0e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_live.py @@ -0,0 +1,34 @@ +import json + +from .oauth import OAuth2Test + + +class LiveOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.live.LiveOAuth2" + user_data_url = "https://apis.live.net/v5.0/me" + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "first_name": "Foo", + "last_name": "Bar", + "name": "Foo Bar", + "locale": "en_US", + "gender": None, + "emails": { + "personal": None, + "account": "foobar@live.com", + "business": None, + "preferred": "foobar@live.com", + }, + "link": "https://profile.live.com/", + "updated_time": "2013-03-17T05:51:30+0000", + "id": "1010101010101010", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_livejournal.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_livejournal.py new file mode 100644 index 0000000000000000000000000000000000000000..6c4f30421e5a1733a295c7057765054aa51d06ae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_livejournal.py @@ -0,0 +1,103 @@ +import datetime +from urllib.parse import urlencode + +from httpretty import HTTPretty + +from ...exceptions import AuthMissingParameter +from .open_id import OpenIdTest + +JANRAIN_NONCE = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + + +class LiveJournalOpenIdTest(OpenIdTest): + backend_path = "social_core.backends.livejournal.LiveJournalOpenId" + expected_username = "foobar" + discovery_body = "".join( + [ + '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">', + "<XRD>", + '<Service priority="0">', + "<Type>http://specs.openid.net/auth/2.0/signon</Type>", + "<URI>http://www.livejournal.com/openid/server.bml</URI>", + "<LocalID>http://foobar.livejournal.com/</LocalID>", + "</Service>", + "</XRD>", + "</xrds:XRDS>", + ] + ) + server_response = urlencode( + { + "janrain_nonce": JANRAIN_NONCE, + "openid.mode": "id_res", + "openid.claimed_id": "http://foobar.livejournal.com/", + "openid.identity": "http://foobar.livejournal.com/", + "openid.op_endpoint": "http://www.livejournal.com/openid/server.bml", + "openid.return_to": "http://myapp.com/complete/livejournal/?" + "janrain_nonce=" + JANRAIN_NONCE, + "openid.response_nonce": JANRAIN_NONCE + "wGp2rj", + "openid.assoc_handle": "1364932966:ZTiur8sem3r2jzZougMZ:4d1cc3b44e", + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.signed": "mode,claimed_id,identity,op_endpoint,return_to," + "response_nonce,assoc_handle", + "openid.sig": "Z8MOozVPTOBhHG5ZS1NeGofxs1Q=", + } + ) + server_bml_body = "\n".join( + [ + "assoc_handle:1364935340:ZhruPQ7DJ9eGgUkeUA9A:27f8c32464", + "assoc_type:HMAC-SHA1", + "dh_server_public:WzsRyLomvAV3vwvGUrfzXDgfqnTF+m1l3JWb55fyHO7visPT4tmQ" + "iTjqFFnSVAtAOvQzoViMiZQisxNwnqSK4lYexoez1z6pP5ry3pqxJAEYj60vFGvRztict" + "Eo0brjhmO1SNfjK1ppjOymdykqLpZeaL5fsuLtMCwTnR/JQZVA=", + "enc_mac_key:LiOEVlLJSVUqfNvb5zPd76nEfvc=", + "expires_in:1207060", + "ns:http://specs.openid.net/auth/2.0", + "session_type:DH-SHA1", + "", + ] + ) + + def openid_url(self): + return super().openid_url() + "/data/yadis" + + def post_start(self): + self.strategy.remove_from_request_data("openid_lj_user") + + def _setup_handlers(self): + HTTPretty.register_uri( + HTTPretty.POST, + "http://www.livejournal.com/openid/server.bml", + headers={ + "Accept-Encoding": "identity", + "Content-Type": "application/x-www-form-urlencoded", + }, + status=200, + body=self.server_bml_body, + ) + HTTPretty.register_uri( + HTTPretty.GET, + "http://foobar.livejournal.com/", + headers={ + "Accept-Encoding": "identity", + "Accept": "text/html; q=0.3," + "application/xhtml+xml; q=0.5," + "application/xrds+xml", + }, + status=200, + body=self.discovery_body, + ) + + def test_login(self): + self.strategy.set_request_data({"openid_lj_user": "foobar"}, self.backend) + self._setup_handlers() + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_request_data({"openid_lj_user": "foobar"}, self.backend) + self._setup_handlers() + self.do_partial_pipeline() + + def test_failed_login(self): + self._setup_handlers() + with self.assertRaises(AuthMissingParameter): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_lyft.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_lyft.py new file mode 100644 index 0000000000000000000000000000000000000000..b71cf1cb8ef3221dd46dea379ae453ccdbddf9e0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_lyft.py @@ -0,0 +1,26 @@ +import json + +from .oauth import OAuth2Test + + +class LyftOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.lyft.LyftOAuth2" + user_data_url = "https://api.lyft.com/v1/profile" + access_token_body = json.dumps( + { + "access_token": "atoken_foo", + "refresh_token": "rtoken_bar", + "token_type": "bearer", + "expires_in": 3600, + "scope": "public profile rides.read rides.request", + "id": "user_foobar", + } + ) + user_data_body = json.dumps({"id": "user_foobar"}) + expected_username = "user_foobar" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mailru.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mailru.py new file mode 100644 index 0000000000000000000000000000000000000000..5a946da6c15de16100aafa2c1dce05b311e397fd --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mailru.py @@ -0,0 +1,28 @@ +import json + +from .oauth import OAuth2Test + + +class MRGOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.mailru.MRGOAuth2" + user_data_url = "https://oauth.mail.ru/userinfo" + expected_username = "FooBar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "first_name": "Foo", + "last_name": "Bar", + "name": "Foo Bar", + "locale": "ru_RU", + "email": "foobar@example.com", + "birthday": "11.07.1970", + "gender": "m", + "image": "http://cs7003.vk.me/v7003815/22a1/xgG9fb-IJ3Y.jpg", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mapmyfitness.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mapmyfitness.py new file mode 100644 index 0000000000000000000000000000000000000000..9c8aac79495a3687f2801809ae0951ebe4c9fb8c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mapmyfitness.py @@ -0,0 +1,120 @@ +import json + +from .oauth import OAuth2Test + + +class MapMyFitnessOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.mapmyfitness.MapMyFitnessOAuth2" + user_data_url = "https://oauth2-api.mapmyapi.com/v7.0/user/self/" + expected_username = "FredFlinstone" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "Bearer", + "expires_in": 4000000, + "refresh_token": "bambaz", + "scope": "read", + } + ) + user_data_body = json.dumps( + { + "last_name": "Flinstone", + "weight": 91.17206637, + "communication": { + "promotions": True, + "newsletter": True, + "system_messages": True, + }, + "height": 1.778, + "token_type": "Bearer", + "id": 112233, + "date_joined": "2011-08-26T06:06:19+00:00", + "first_name": "Fred", + "display_name": "Fred Flinstone", + "display_measurement_system": "imperial", + "expires_in": 4000000, + "_links": { + "stats": [ + { + "href": "/v7.0/user_stats/112233/?" "aggregate_by_period=month", + "id": "112233", + "name": "month", + }, + { + "href": "/v7.0/user_stats/112233/?" "aggregate_by_period=year", + "id": "112233", + "name": "year", + }, + { + "href": "/v7.0/user_stats/112233/?aggregate_by_period=day", + "id": "112233", + "name": "day", + }, + { + "href": "/v7.0/user_stats/112233/?" "aggregate_by_period=week", + "id": "112233", + "name": "week", + }, + { + "href": "/v7.0/user_stats/112233/?" + "aggregate_by_period=lifetime", + "id": "112233", + "name": "lifetime", + }, + ], + "friendships": [{"href": "/v7.0/friendship/?from_user=112233"}], + "privacy": [ + {"href": "/v7.0/privacy_option/3/", "id": "3", "name": "profile"}, + {"href": "/v7.0/privacy_option/3/", "id": "3", "name": "workout"}, + { + "href": "/v7.0/privacy_option/3/", + "id": "3", + "name": "activity_feed", + }, + {"href": "/v7.0/privacy_option/1/", "id": "1", "name": "food_log"}, + { + "href": "/v7.0/privacy_option/3/", + "id": "3", + "name": "email_search", + }, + {"href": "/v7.0/privacy_option/3/", "id": "3", "name": "route"}, + ], + "image": [ + { + "href": "/v7.0/user_profile_photo/112233/", + "id": "112233", + "name": "user_profile_photo", + } + ], + "documentation": [{"href": "https://www.mapmyapi.com/docs/User"}], + "workouts": [ + {"href": "/v7.0/workout/?user=112233&" "order_by=-start_datetime"} + ], + "deactivation": [{"href": "/v7.0/user_deactivation/"}], + "self": [{"href": "/v7.0/user/112233/", "id": "112233"}], + }, + "location": { + "country": "US", + "region": "NC", + "locality": "Bedrock", + "address": "150 Dinosaur Ln", + }, + "last_login": "2014-02-23T22:36:52+00:00", + "email": "fredflinstone@gmail.com", + "username": "FredFlinstone", + "sharing": {"twitter": False, "facebook": False}, + "scope": "read", + "refresh_token": "bambaz", + "last_initial": "S.", + "access_token": "foobar", + "gender": "M", + "time_zone": "America/Denver", + "birthdate": "1983-04-15", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_microsoft.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_microsoft.py new file mode 100644 index 0000000000000000000000000000000000000000..66c988d6903fecbc6f098a5ed07d511fb95ddfec --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_microsoft.py @@ -0,0 +1,52 @@ +import json + +from .oauth import OAuth2Test + + +class MicrosoftOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.microsoft.MicrosoftOAuth2" + user_data_url = "https://graph.microsoft.com/v1.0/me" + expected_username = "foobar" + user_data_body = json.dumps( + { + "displayName": "foo bar", + "givenName": "foobar", + "jobTitle": "Auditor", + "mail": "foobar@foobar.com", + "mobilePhone": None, + "officeLocation": "12/1110", + "preferredLanguage": "en-US", + "surname": "Bowen", + "userPrincipalName": "foobar", + "id": "48d31887-5fad-4d73-a9f5-3c356e68a038", + } + ) + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "id_token": "", + "expires_in": 3600, + "expires_on": 1423650396, + "not_before": 1423646496, + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "bearer", + "expires_in": 3600, + "refresh_token": "foobar-new-refresh-token", + "scope": "identity", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mineid.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mineid.py new file mode 100644 index 0000000000000000000000000000000000000000..c5dd6811317700596996343a79af2735c7089d84 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mineid.py @@ -0,0 +1,22 @@ +import json + +from .oauth import OAuth2Test + + +class MineIDOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.mineid.MineIDOAuth2" + user_data_url = "https://www.mineid.org/api/user" + expected_username = "foo@bar.com" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "email": "foo@bar.com", + "primary_profile": None, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mixcloud.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mixcloud.py new file mode 100644 index 0000000000000000000000000000000000000000..4eb0d65b6ac8eed861fcbb7fcb060cc7caac0738 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_mixcloud.py @@ -0,0 +1,57 @@ +import json + +from .oauth import OAuth2Test + + +class MixcloudOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.mixcloud.MixcloudOAuth2" + user_data_url = "https://api.mixcloud.com/me/" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "username": "foobar", + "cloudcast_count": 0, + "following_count": 0, + "url": "http://www.mixcloud.com/foobar/", + "pictures": { + "medium": "http://images-mix.netdna-ssl.com/w/100/h/100/q/85/" + "images/graphics/33_Profile/default_user_600x600-v4.png", + "320wx320h": "http://images-mix.netdna-ssl.com/w/320/h/320/q/85/" + "images/graphics/33_Profile/" + "default_user_600x600-v4.png", + "extra_large": "http://images-mix.netdna-ssl.com/w/600/h/600/q/85/" + "images/graphics/33_Profile/" + "default_user_600x600-v4.png", + "large": "http://images-mix.netdna-ssl.com/w/300/h/300/q/85/" + "images/graphics/33_Profile/default_user_600x600-v4.png", + "640wx640h": "http://images-mix.netdna-ssl.com/w/640/h/640/q/85/" + "images/graphics/33_Profile/" + "default_user_600x600-v4.png", + "medium_mobile": "http://images-mix.netdna-ssl.com/w/80/h/80/q/75/" + "images/graphics/33_Profile/" + "default_user_600x600-v4.png", + "small": "http://images-mix.netdna-ssl.com/w/25/h/25/q/85/images/" + "graphics/33_Profile/default_user_600x600-v4.png", + "thumbnail": "http://images-mix.netdna-ssl.com/w/50/h/50/q/85/" + "images/graphics/33_Profile/" + "default_user_600x600-v4.png", + }, + "is_current_user": True, + "listen_count": 0, + "updated_time": "2013-03-17T06:26:31Z", + "following": False, + "follower": False, + "key": "/foobar/", + "created_time": "2013-03-17T06:26:31Z", + "follower_count": 0, + "favorite_count": 0, + "name": "foobar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_musicbrainz.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_musicbrainz.py new file mode 100644 index 0000000000000000000000000000000000000000..4c3005df05362167bfd240a36c78a5be4dce7d0d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_musicbrainz.py @@ -0,0 +1,29 @@ +import json + +from .oauth import OAuth2Test + + +class MusicBrainzAuth2Test(OAuth2Test): + backend_path = "social_core.backends.musicbrainz.MusicBrainzOAuth2" + user_data_url = "https://musicbrainz.org/oauth2/userinfo" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "GjtKfJS6G4lupbQcCOiTKo4HcLXUgI1p", + "expires_in": 3600, + "token_type": "Bearer", + "refresh_token": "GjSCBBjp4fnbE0AKo3uFu9qq9K2fFm4u", + } + ) + user_data_body = json.dumps( + { + "sub": "foobar", + "email": "foo@bar.com", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_nationbuilder.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_nationbuilder.py new file mode 100644 index 0000000000000000000000000000000000000000..39e6ad453e32c96d5dfad1275e66cd7ec0c8fa33 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_nationbuilder.py @@ -0,0 +1,232 @@ +import json + +from .oauth import OAuth2Test + + +class NationBuilderOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.nationbuilder.NationBuilderOAuth2" + user_data_url = "https://foobar.nationbuilder.com/api/v1/people/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "created_at": 1422937981, + "expires_in": 2592000, + } + ) + user_data_body = json.dumps( + { + "person": { + "twitter_followers_count": None, + "last_name": "Bar", + "rule_violations_count": 0, + "linkedin_id": None, + "recruiter_id": None, + "membership_expires_at": None, + "donations_raised_count": 0, + "last_contacted_at": None, + "prefix": None, + "profile_content_html": None, + "email4": None, + "email2": None, + "availability": None, + "occupation": None, + "user_submitted_address": None, + "could_vote_status": None, + "state_upper_district": None, + "salesforce_id": None, + "van_id": None, + "phone_time": None, + "profile_content": None, + "auto_import_id": None, + "parent_id": None, + "email4_is_bad": False, + "twitter_updated_at": None, + "email3_is_bad": False, + "bio": None, + "party_member": None, + "unsubscribed_at": None, + "fax_number": None, + "last_contacted_by": None, + "active_customer_expires_at": None, + "federal_donotcall": False, + "warnings_count": 0, + "first_supporter_at": "2015-02-02T19:30:28-08:00", + "previous_party": None, + "donations_raised_amount_this_cycle_in_cents": 0, + "call_status_name": None, + "marital_status": None, + "facebook_updated_at": None, + "donations_count": 0, + "note_updated_at": None, + "closed_invoices_count": None, + "profile_headline": None, + "fire_district": None, + "mobile_normalized": None, + "import_id": None, + "last_call_id": None, + "donations_raised_amount_in_cents": 0, + "facebook_address": None, + "is_profile_private": False, + "last_rule_violation_at": None, + "sex": None, + "full_name": "Foo Bar", + "last_donated_at": None, + "donations_pledged_amount_in_cents": 0, + "primary_email_id": 1, + "media_market_name": None, + "capital_amount_in_cents": 500, + "datatrust_id": None, + "precinct_code": None, + "email3": None, + "religion": None, + "first_prospect_at": None, + "judicial_district": None, + "donations_count_this_cycle": 0, + "work_address": None, + "is_twitter_follower": False, + "email1": "foobar@gmail.com", + "email": "foobar@gmail.com", + "contact_status_name": None, + "mobile_opt_in": True, + "twitter_description": None, + "parent": None, + "tags": [], + "first_volunteer_at": None, + "inferred_support_level": None, + "banned_at": None, + "first_invoice_at": None, + "donations_raised_count_this_cycle": 0, + "is_donor": False, + "twitter_location": None, + "email1_is_bad": False, + "legal_name": None, + "language": None, + "registered_at": None, + "call_status_id": None, + "last_invoice_at": None, + "school_sub_district": None, + "village_district": None, + "twitter_name": None, + "membership_started_at": None, + "subnations": [], + "meetup_address": None, + "author_id": None, + "registered_address": None, + "external_id": None, + "twitter_login": None, + "inferred_party": None, + "spent_capital_amount_in_cents": 0, + "suffix": None, + "mailing_address": None, + "is_leaderboardable": True, + "twitter_website": None, + "nbec_guid": None, + "city_district": None, + "church": None, + "is_profile_searchable": True, + "employer": None, + "is_fundraiser": False, + "email_opt_in": True, + "recruits_count": 0, + "email2_is_bad": False, + "county_district": None, + "recruiter": None, + "twitter_friends_count": None, + "facebook_username": None, + "active_customer_started_at": None, + "pf_strat_id": None, + "locale": None, + "twitter_address": None, + "is_supporter": True, + "do_not_call": False, + "profile_image_url_ssl": "https://d3n8a8pro7vhmx.cloudfront.net" + "/assets/icons/buddy.png", + "invoices_amount_in_cents": None, + "username": None, + "donations_amount_in_cents": 0, + "is_volunteer": False, + "civicrm_id": None, + "supranational_district": None, + "precinct_name": None, + "invoice_payments_amount_in_cents": None, + "work_phone_number": None, + "phone": "213.394.4623", + "received_capital_amount_in_cents": 500, + "primary_address": None, + "is_possible_duplicate": False, + "invoice_payments_referred_amount_in_cents": None, + "donations_amount_this_cycle_in_cents": 0, + "priority_level": None, + "first_fundraised_at": None, + "phone_normalized": "2133944623", + "rnc_regid": None, + "twitter_id": None, + "birthdate": None, + "mobile": None, + "federal_district": None, + "donations_to_raise_amount_in_cents": 0, + "support_probability_score": None, + "invoices_count": None, + "nbec_precinct_code": None, + "website": None, + "closed_invoices_amount_in_cents": None, + "home_address": None, + "school_district": None, + "support_level": None, + "demo": None, + "children_count": 0, + "updated_at": "2015-02-02T19:30:28-08:00", + "membership_level_name": None, + "billing_address": None, + "is_ignore_donation_limits": False, + "signup_type": 0, + "precinct_id": None, + "rnc_id": None, + "id": 2, + "ethnicity": None, + "is_survey_question_private": False, + "middle_name": None, + "author": None, + "last_fundraised_at": None, + "state_file_id": None, + "note": None, + "submitted_address": None, + "support_level_changed_at": None, + "party": None, + "contact_status_id": None, + "outstanding_invoices_amount_in_cents": None, + "page_slug": None, + "outstanding_invoices_count": None, + "first_recruited_at": None, + "county_file_id": None, + "first_name": "Foo", + "facebook_profile_url": None, + "city_sub_district": None, + "has_facebook": False, + "is_deceased": False, + "labour_region": None, + "state_lower_district": None, + "dw_id": None, + "created_at": "2015-02-02T19:30:28-08:00", + "is_prospect": False, + "priority_level_changed_at": None, + "is_mobile_bad": False, + "overdue_invoices_count": None, + "ngp_id": None, + "do_not_contact": False, + "first_donated_at": None, + "turnout_probability_score": None, + }, + "precinct": None, + } + ) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_NATIONBUILDER_SLUG": "foobar"}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_NATIONBUILDER_SLUG": "foobar"}) + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_naver.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_naver.py new file mode 100644 index 0000000000000000000000000000000000000000..b69d8cea5f59946d745a4c7b278a27ac71c978c8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_naver.py @@ -0,0 +1,39 @@ +import json + +from .oauth import OAuth2Test + + +class NaverOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.naver.NaverOAuth2" + user_data_url = "https://openapi.naver.com/v1/nid/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + } + ) + + user_data_content_type = "text/json" + user_data_body = json.dumps( + { + "resultcode": "00", + "message": "success", + "response": { + "email": "openapi@naver.com", + "nickname": "foobar", + "profile_image": "https://ssl.pstatic.net/static/pwe/address/nodata_33x33.gif", + "age": "40-49", + "gender": "F", + "id": "32742776", + "name": "foobar", + "birthday": "10-01", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_ngpvan.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_ngpvan.py new file mode 100644 index 0000000000000000000000000000000000000000..f80cc996346213de8248a294fdd5f17e6cafaf74 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_ngpvan.py @@ -0,0 +1,204 @@ +"""Tests for NGP VAN ActionID Backend""" +import datetime +from urllib.parse import urlencode + +from httpretty import HTTPretty + +from .open_id import OpenIdTest + +JANRAIN_NONCE = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + + +class NGPVANActionIDOpenIDTest(OpenIdTest): + """Test the NGP VAN ActionID OpenID 1.1 Backend""" + + backend_path = "social_core.backends.ngpvan.ActionIDOpenID" + expected_username = "testuser@user.local" + discovery_body = " ".join( + [ + '<?xml version="1.0" encoding="UTF-8"?>', + "<xrds:XRDS", + 'xmlns:xrds="xri://$xrds"', + 'xmlns:openid="http://openid.net/xmlns/1.0"', + 'xmlns="xri://$xrd*($v*2.0)">', + "<XRD>", + '<Service priority="10">', + "<Type>http://specs.openid.net/auth/2.0/signon</Type>", + "<Type>http://openid.net/extensions/sreg/1.1</Type>", + "<Type>http://axschema.org/contact/email</Type>", + "<URI>https://accounts.ngpvan.com/OpenId/Provider</URI>", + "</Service>", + '<Service priority="20">', + "<Type>http://openid.net/signon/1.0</Type>", + "<Type>http://openid.net/extensions/sreg/1.1</Type>", + "<Type>http://axschema.org/contact/email</Type>", + "<URI>https://accounts.ngpvan.com/OpenId/Provider</URI>", + "</Service>", + "</XRD>", + "</xrds:XRDS>", + ] + ) + server_response = urlencode( + { + "openid.claimed_id": "https://accounts.ngpvan.com/user/abcd123", + "openid.identity": "https://accounts.ngpvan.com/user/abcd123", + "openid.sig": "Midw8F/rCDwW7vMz3y+vK6rjz6s=", + "openid.signed": "claimed_id,identity,assoc_handle,op_endpoint,return_" + "to,response_nonce,ns.alias3,alias3.mode,alias3.type." + "alias1,alias3.value.alias1,alias3.type.alias2,alias3" + ".value.alias2,alias3.type.alias3,alias3.value.alias3" + ",alias3.type.alias4,alias3.value.alias4,alias3.type." + "alias5,alias3.value.alias5,alias3.type.alias6,alias3" + ".value.alias6,alias3.type.alias7,alias3.value.alias7" + ",alias3.type.alias8,alias3.value.alias8,ns.sreg,sreg" + ".fullname", + "openid.assoc_handle": "{635790678917902781}{GdSyFA==}{20}", + "openid.op_endpoint": "https://accounts.ngpvan.com/OpenId/Provider", + "openid.return_to": "http://myapp.com/complete/actionid-openid/", + "openid.response_nonce": JANRAIN_NONCE + "MMgBGEre", + "openid.mode": "id_res", + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.ns.alias3": "http://openid.net/srv/ax/1.0", + "openid.alias3.mode": "fetch_response", + "openid.alias3.type.alias1": "http://openid.net/schema/contact/phone/b" + "usiness", + "openid.alias3.value.alias1": "+12015555555", + "openid.alias3.type.alias2": "http://openid.net/schema/contact/interne" + "t/email", + "openid.alias3.value.alias2": "testuser@user.local", + "openid.alias3.type.alias3": "http://openid.net/schema/namePerson/firs" "t", + "openid.alias3.value.alias3": "John", + "openid.alias3.type.alias4": "http://openid.net/schema/namePerson/las" "t", + "openid.alias3.value.alias4": "Smith", + "openid.alias3.type.alias5": "http://axschema.org/namePerson/first", + "openid.alias3.value.alias5": "John", + "openid.alias3.type.alias6": "http://axschema.org/namePerson/last", + "openid.alias3.value.alias6": "Smith", + "openid.alias3.type.alias7": "http://axschema.org/namePerson", + "openid.alias3.value.alias7": "John Smith", + "openid.alias3.type.alias8": "http://openid.net/schema/namePerson", + "openid.alias3.value.alias8": "John Smith", + "openid.ns.sreg": "http://openid.net/extensions/sreg/1.1", + "openid.sreg.fullname": "John Smith", + } + ) + + def setUp(self): + """Setup the test""" + super().setUp() + + # Mock out the NGP VAN endpoints + HTTPretty.register_uri( + HTTPretty.GET, + "https://accounts.ngpvan.com/Home/Xrds", + status=200, + body=self.discovery_body, + ) + HTTPretty.register_uri( + HTTPretty.GET, + "https://accounts.ngpvan.com/user/abcd123", + status=200, + body=self.discovery_body, + ) + HTTPretty.register_uri( + HTTPretty.GET, + "https://accounts.ngpvan.com/OpenId/Provider", + status=200, + body=self.discovery_body, + ) + + def test_login(self): + """Test the login flow using python-social-auth's built in test""" + self.do_login() + + def test_partial_pipeline(self): + """Test the partial flow using python-social-auth's built in test""" + self.do_partial_pipeline() + + def test_get_ax_attributes(self): + """Test that the AX attributes that NGP VAN responds with are present""" + records = self.backend.get_ax_attributes() + + self.assertEqual( + records, + [ + ("http://openid.net/schema/contact/internet/email", "email"), + ("http://openid.net/schema/contact/phone/business", "phone"), + ("http://openid.net/schema/namePerson/first", "first_name"), + ("http://openid.net/schema/namePerson/last", "last_name"), + ("http://openid.net/schema/namePerson", "fullname"), + ], + ) + + def test_setup_request(self): + """Test the setup_request functionality in the NGP VAN backend""" + # We can grab the requested attributes by grabbing the HTML of the + # OpenID auth form and pulling out the hidden fields + _, inputs = self.get_form_data(self.backend.auth_html()) + + # Confirm that the only required attribute is email + self.assertEqual(inputs["openid.ax.required"], "ngpvanemail") + + # Confirm that the 3 optional attributes are requested "if available" + self.assertIn("ngpvanphone", inputs["openid.ax.if_available"]) + self.assertIn("ngpvanfirstname", inputs["openid.ax.if_available"]) + self.assertIn("ngpvanlastname", inputs["openid.ax.if_available"]) + + # Verify the individual attribute properties + self.assertEqual( + inputs["openid.ax.type.ngpvanemail"], + "http://openid.net/schema/contact/internet/email", + ) + self.assertEqual( + inputs["openid.ax.type.ngpvanfirstname"], + "http://openid.net/schema/namePerson/first", + ) + self.assertEqual( + inputs["openid.ax.type.ngpvanlastname"], + "http://openid.net/schema/namePerson/last", + ) + self.assertEqual( + inputs["openid.ax.type.ngpvanphone"], + "http://openid.net/schema/contact/phone/business", + ) + + def test_user_data(self): + """Ensure that the correct user data is being passed to create_user""" + self.strategy.set_settings( + { + "USER_FIELDS": [ + "email", + "first_name", + "last_name", + "username", + "phone", + "fullname", + ] + } + ) + user = self.do_start() + self.assertEqual(user.username, "testuser@user.local") + self.assertEqual(user.email, "testuser@user.local") + self.assertEqual(user.extra_user_fields["phone"], "+12015555555") + self.assertEqual(user.extra_user_fields["first_name"], "John") + self.assertEqual(user.extra_user_fields["last_name"], "Smith") + self.assertEqual(user.extra_user_fields["fullname"], "John Smith") + + def test_extra_data_phone(self): + """Confirm that you can get a phone number via the relevant setting""" + self.strategy.set_settings( + { + "SOCIAL_AUTH_ACTIONID_OPENID_AX_EXTRA_DATA": [ + ("http://openid.net/schema/contact/phone/business", "phone") + ] + } + ) + user = self.do_start() + self.assertEqual(user.social_user.extra_data["phone"], "+12015555555") + + def test_association_uid(self): + """Test that the correct association uid is stored in the database""" + user = self.do_start() + self.assertEqual( + user.social_user.uid, "https://accounts.ngpvan.com/user/abcd123" + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_okta.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_okta.py new file mode 100644 index 0000000000000000000000000000000000000000..5885ecc7a9dbb1a7657219f2f9f19011ceac8e9b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_okta.py @@ -0,0 +1,171 @@ +import json + +from httpretty import HTTPretty + +from social_core.tests.backends.oauth import OAuth2Test +from social_core.tests.backends.test_open_id_connect import OpenIdConnectTestMixin + +JWK_KEY = { + "kty": "RSA", + "d": "ZmswNokEvBcxW_Kvcy8mWUQOQCBdGbnM0xR7nhvGHC-Q24z3XAQWlMWbsmGc_R1o" + "_F3zK7DBlc3BokdRaO1KJirNmnHCw5TlnBlJrXiWpFBtVglUg98-4sRRO0VWnGXK" + "JPOkBQ6b_DYRO3b0o8CSpWowpiV6HB71cjXTqKPZf-aXU9WjCCAtxVjfIxgQFu5I" + "-G1Qah8mZeY8HK_y99L4f0siZcbUoaIcfeWBhxi14ODyuSAHt0sNEkhiIVBZE7QZ" + "m-SEP1ryT9VAaljbwHHPmg7NC26vtLZhvaBGbTTJnEH0ZubbN2PMzsfeNyoCIHy4" + "4QDSpQDCHfgcGOlHY_t5gQ", + "e": "AQAB", + "use": "sig", + "kid": "testkey", + "alg": "RS256", + "n": "pUfcJ8WFrVue98Ygzb6KEQXHBzi8HavCu8VENB2As943--bHPcQ-nScXnrRFAUg8" + "H5ZltuOcHWvsGw_AQifSLmOCSWJAPkdNb0w0QzY7Re8NrPjCsP58Tytp5LicF0Ao" + "Ag28UK3JioY9hXHGvdZsWR1Rp3I-Z3nRBP6HyO18pEgcZ91c9aAzsqu80An9X4DA" + "b1lExtZorvcd5yTBzZgr-MUeytVRni2lDNEpa6OFuopHXmg27Hn3oWAaQlbymd4g" + "ifc01oahcwl3ze2tMK6gJxa_TdCf1y99Yq6oilmVvZJ8kwWWnbPE-oDmOVPVnEyT" + "vYVCvN4rBT1DQ-x0F1mo2Q", +} + +JWK_PUBLIC_KEY = {key: value for key, value in JWK_KEY.items() if key != "d"} + + +class OktaOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.okta.OktaOAuth2" + user_data_url = "https://dev-000000.oktapreview.com/oauth2/v1/userinfo" + expected_username = "foo" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "family_name": "Bar", + "sub": "101010101010101010101", + "locale": "en", + "email_verified": True, + "given_name": "Foo", + "email": "foo@bar.com", + "name": "Foo Bar", + "nickname": "foobar", + "middle_name": "", + "profile": "https://example.com/foo.bar", + "zoneinfo": "America/Los_Angeles", + "updated_at": 1311280970, + "preferred_username": "foo", + } + ) + + def test_login(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_OKTA_OAUTH2_API_URL": "https://dev-000000.oktapreview.com/oauth2" + } + ) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_OKTA_OAUTH2_API_URL": "https://dev-000000.oktapreview.com/oauth2" + } + ) + self.do_partial_pipeline() + + +class OktaOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.okta_openidconnect.OktaOpenIdConnect" + user_data_url = "https://dev-000000.oktapreview.com/oauth2/v1/userinfo" + issuer = "https://dev-000000.oktapreview.com/oauth2" + openid_config_body = json.dumps( + { + "issuer": "https://dev-000000.oktapreview.com/oauth2", + "authorization_endpoint": "https://dev-000000.oktapreview.com/oauth2/v1/authorize", + "token_endpoint": "https://dev-000000.oktapreview.com/oauth2/v1/token", + "userinfo_endpoint": "https://dev-000000.oktapreview.com/oauth2/v1/userinfo", + "jwks_uri": "https://dev-000000.oktapreview.com/oauth2/v1/keys", + "response_types_supported": [ + "code", + "token", + "id_token", + "code token", + "code id_token", + "token id_token", + "code token id_token", + "none", + ], + "subject_types_supported": [ + "public", + ], + "id_token_signing_alg_values_supported": [ + "RS256", + ], + "scopes_supported": [ + "openid", + "email", + "profile", + ], + "token_endpoint_auth_methods_supported": [ + "client_secret_post", + "client_secret_basic", + ], + "claims_supported": [ + "aud", + "email", + "email_verified", + "exp", + "family_name", + "given_name", + "iat", + "iss", + "locale", + "name", + "picture", + "sub", + ], + } + ) + expected_username = "foo" + + def setUp(self): + super(OpenIdConnectTestMixin, self).setUp() + # Settings for Okta + self.strategy.set_settings( + { + "SOCIAL_AUTH_OKTA_OPENIDCONNECT_API_URL": "https://dev-000000.oktapreview.com/oauth2" + } + ) + self.backend.OIDC_ENDPOINT = "https://dev-000000.oktapreview.com/oauth2" + + self.key = JWK_KEY.copy() + self.public_key = JWK_PUBLIC_KEY.copy() + + HTTPretty.register_uri( + HTTPretty.GET, + # Note: okta.py strips the /oauth2 prefix using urljoin with absolute path + "https://dev-000000.oktapreview.com/.well-known/openid-configuration?client_id=a-key", + status=200, + body=self.openid_config_body, + ) + oidc_config = json.loads(self.openid_config_body) + + def jwks(_request, _uri, headers): + return 200, headers, json.dumps({"keys": [self.key]}) + + HTTPretty.register_uri( + HTTPretty.GET, + oidc_config.get("jwks_uri"), + status=200, + body=json.dumps({"keys": [self.public_key]}), + ) + + self.backend.JWKS_URI = oidc_config.get("jwks_uri") + self.backend.ID_TOKEN_ISSUER = oidc_config.get("issuer") + + def pre_complete_callback(self, start_url): + super().pre_complete_callback(start_url) + HTTPretty.register_uri( + "GET", + uri=self.backend.userinfo_url(), + status=200, + body=json.dumps({"preferred_username": self.expected_username}), + content_type="text/json", + ) + + def test_everything_works(self): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_open_id_connect.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_open_id_connect.py new file mode 100644 index 0000000000000000000000000000000000000000..7b375d8a11857945b071fe0e5f6d61c6415f0a55 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_open_id_connect.py @@ -0,0 +1,300 @@ +import base64 +import datetime +import json +import os +import sys +from calendar import timegm +from urllib.parse import urlparse + +from httpretty import HTTPretty +from jose import jwt + +from social_core.backends.open_id_connect import OpenIdConnectAuth + +from ...exceptions import AuthTokenError +from ...utils import parse_qs +from .oauth import OAuth2Test + +sys.path.insert(0, "..") + + +TEST_ROOT = os.path.dirname(os.path.dirname(__file__)) + +JWK_KEY = { + "kty": "RSA", + "d": "ZmswNokEvBcxW_Kvcy8mWUQOQCBdGbnM0xR7nhvGHC-Q24z3XAQWlMWbsmGc_R1o" + "_F3zK7DBlc3BokdRaO1KJirNmnHCw5TlnBlJrXiWpFBtVglUg98-4sRRO0VWnGXK" + "JPOkBQ6b_DYRO3b0o8CSpWowpiV6HB71cjXTqKPZf-aXU9WjCCAtxVjfIxgQFu5I" + "-G1Qah8mZeY8HK_y99L4f0siZcbUoaIcfeWBhxi14ODyuSAHt0sNEkhiIVBZE7QZ" + "m-SEP1ryT9VAaljbwHHPmg7NC26vtLZhvaBGbTTJnEH0ZubbN2PMzsfeNyoCIHy4" + "4QDSpQDCHfgcGOlHY_t5gQ", + "e": "AQAB", + "use": "sig", + "kid": "testkey", + "alg": "RS256", + "n": "pUfcJ8WFrVue98Ygzb6KEQXHBzi8HavCu8VENB2As943--bHPcQ-nScXnrRFAUg8" + "H5ZltuOcHWvsGw_AQifSLmOCSWJAPkdNb0w0QzY7Re8NrPjCsP58Tytp5LicF0Ao" + "Ag28UK3JioY9hXHGvdZsWR1Rp3I-Z3nRBP6HyO18pEgcZ91c9aAzsqu80An9X4DA" + "b1lExtZorvcd5yTBzZgr-MUeytVRni2lDNEpa6OFuopHXmg27Hn3oWAaQlbymd4g" + "ifc01oahcwl3ze2tMK6gJxa_TdCf1y99Yq6oilmVvZJ8kwWWnbPE-oDmOVPVnEyT" + "vYVCvN4rBT1DQ-x0F1mo2Q", +} + +JWK_PUBLIC_KEY = {key: value for key, value in JWK_KEY.items() if key != "d"} + + +class OpenIdConnectTestMixin: + """ + Mixin to test OpenID Connect consumers. Inheriting classes should also + inherit OAuth2Test. + """ + + client_key = "a-key" + client_secret = "a-secret-key" + issuer = None # id_token issuer + openid_config_body = None + key = None + + # Avoid sharing access_token_kwargs between different subclasses + def __init_subclass__(cls, **kwargs): + super().__init_subclass__(**kwargs) + cls.access_token_kwargs = getattr(cls, "access_token_kwargs", {}) + + def setUp(self): + super().setUp() + self.key = JWK_KEY.copy() + self.public_key = JWK_PUBLIC_KEY.copy() + + HTTPretty.register_uri( + HTTPretty.GET, + self.backend.oidc_endpoint() + "/.well-known/openid-configuration", + status=200, + body=self.openid_config_body, + ) + oidc_config = json.loads(self.openid_config_body) + + def jwks(_request, _uri, headers): + return 200, headers, json.dumps({"keys": [self.key]}) + + HTTPretty.register_uri( + HTTPretty.GET, + oidc_config.get("jwks_uri"), + status=200, + body=json.dumps({"keys": [self.public_key]}), + ) + + def extra_settings(self): + settings = super().extra_settings() + settings.update( + { + f"SOCIAL_AUTH_{self.name}_KEY": self.client_key, + f"SOCIAL_AUTH_{self.name}_SECRET": self.client_secret, + f"SOCIAL_AUTH_{self.name}_ID_TOKEN_DECRYPTION_KEY": self.client_secret, + } + ) + return settings + + def get_id_token( + self, + client_key=None, + expiration_datetime=None, + issue_datetime=None, + nonce=None, + issuer=None, + ): + """ + Return the id_token to be added to the access token body. + """ + return { + "iss": issuer, + "nonce": nonce, + "aud": client_key, + "azp": client_key, + "exp": expiration_datetime, + "iat": issue_datetime, + "sub": "1234", + } + + def prepare_access_token_body( + self, + client_key=None, + tamper_message=False, + expiration_datetime=None, + kid=None, + issue_datetime=None, + nonce=None, + issuer=None, + ): + """ + Prepares a provider access token response. Arguments: + + client_id -- (str) OAuth ID for the client that requested + authentication. + expiration_time -- (datetime) Date and time after which the response + should be considered invalid. + """ + + body = {"access_token": "foobar", "token_type": "bearer"} + client_key = client_key or self.client_key + now = datetime.datetime.utcnow() + expiration_datetime = expiration_datetime or ( + now + datetime.timedelta(seconds=30) + ) + issue_datetime = issue_datetime or now + nonce = nonce or "a-nonce" + issuer = issuer or self.issuer + id_token = self.get_id_token( + client_key, + timegm(expiration_datetime.utctimetuple()), + timegm(issue_datetime.utctimetuple()), + nonce, + issuer, + ) + + body["id_token"] = jwt.encode( + claims=id_token, + key=dict(self.key, iat=timegm(issue_datetime.utctimetuple()), nonce=nonce), + algorithm="RS256", + access_token="foobar", + headers=dict(kid=kid), + ) + + if tamper_message: + header, msg, sig = body["id_token"].split(".") + id_token["sub"] = "1235" + msg = base64.encodebytes(json.dumps(id_token).encode()).decode() + body["id_token"] = ".".join([header, msg, sig]) + + return json.dumps(body) + + def authtoken_raised(self, expected_message, **access_token_kwargs): + self.access_token_kwargs = access_token_kwargs + with self.assertRaisesRegex(AuthTokenError, expected_message): + self.do_login() + + def pre_complete_callback(self, start_url): + nonce = parse_qs(urlparse(start_url).query)["nonce"] + + self.access_token_kwargs.setdefault("nonce", nonce) + self.access_token_body = self.prepare_access_token_body( + **self.access_token_kwargs + ) + super().pre_complete_callback(start_url) + + def test_invalid_signature(self): + self.authtoken_raised( + "Token error: Signature verification failed", tamper_message=True + ) + + def test_expired_signature(self): + expiration_datetime = datetime.datetime.utcnow() - datetime.timedelta( + seconds=30 + ) + self.authtoken_raised( + "Token error: Signature has expired", + expiration_datetime=expiration_datetime, + ) + + def test_invalid_issuer(self): + self.authtoken_raised("Token error: Invalid issuer", issuer="someone-else") + + def test_invalid_audience(self): + self.authtoken_raised( + "Token error: Invalid audience", client_key="someone-else" + ) + + def test_invalid_issue_time(self): + expiration_datetime = datetime.datetime.utcnow() - datetime.timedelta( + seconds=self.backend.ID_TOKEN_MAX_AGE * 2 + ) + self.authtoken_raised( + "Token error: Incorrect id_token: iat", issue_datetime=expiration_datetime + ) + + def test_invalid_nonce(self): + self.authtoken_raised( + "Token error: Incorrect id_token: nonce", + nonce="something-wrong", + kid="testkey", + ) + + def test_invalid_kid(self): + self.authtoken_raised( + "Token error: Signature verification failed", kid="doesnotexist" + ) + + +class BaseOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.open_id_connect.OpenIdConnectAuth" + issuer = "https://example.com" + openid_config_body = json.dumps( + { + "issuer": "https://example.com", + "authorization_endpoint": "https://example.com/oidc/auth", + "token_endpoint": "https://example.com/oidc/token", + "userinfo_endpoint": "https://example.com/oidc/userinfo", + "revocation_endpoint": "https://example.com/oidc/revoke", + "jwks_uri": "https://example.com/oidc/certs", + } + ) + + expected_username = "cartman" + + def extra_settings(self): + settings = super().extra_settings() + settings.update( + { + "SOCIAL_AUTH_OIDC_OIDC_ENDPOINT": "https://example.com/oidc", + } + ) + return settings + + def pre_complete_callback(self, start_url): + super().pre_complete_callback(start_url) + HTTPretty.register_uri( + "GET", + uri=self.backend.userinfo_url(), + status=200, + body=json.dumps({"preferred_username": self.expected_username}), + content_type="text/json", + ) + + def test_everything_works(self): + self.do_login() + + +class ExampleOpenIdConnectAuth(OpenIdConnectAuth): + name = "example123" + OIDC_ENDPOINT = "https://example.com/oidc" + + +class ExampleOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = ( + "social_core.tests.backends.test_open_id_connect.ExampleOpenIdConnectAuth" + ) + issuer = "https://example.com" + openid_config_body = json.dumps( + { + "issuer": "https://example.com", + "authorization_endpoint": "https://example.com/oidc/auth", + "token_endpoint": "https://example.com/oidc/token", + "userinfo_endpoint": "https://example.com/oidc/userinfo", + "revocation_endpoint": "https://example.com/oidc/revoke", + "jwks_uri": "https://example.com/oidc/certs", + } + ) + + expected_username = "cartman" + + def pre_complete_callback(self, start_url): + super().pre_complete_callback(start_url) + HTTPretty.register_uri( + "GET", + uri=self.backend.userinfo_url(), + status=200, + body=json.dumps({"preferred_username": self.expected_username}), + content_type="text/json", + ) + + def test_everything_works(self): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orbi.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orbi.py new file mode 100644 index 0000000000000000000000000000000000000000..fac57928dcdf3f7294943b54830549b7cbdd0190 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orbi.py @@ -0,0 +1,33 @@ +import json + +from .oauth import OAuth2Test + + +class OrbiOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.orbi.OrbiOAuth2" + user_data_url = "https://login.orbi.kr/oauth/user/get" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + } + ) + user_data_body = json.dumps( + { + "username": "foobar", + "first_name": "Foo", + "last_name": "Bar", + "name": "Foo Bar", + "imin": "100000", + "nick": "foobar", + "photo": "http://s3.orbi.kr/data/member/wi/wizetdev_132894975780.jpeg", + "sex": "M", + "birth": "1973-08-03", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orcid.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orcid.py new file mode 100644 index 0000000000000000000000000000000000000000..93bb4124d8644b6a94f4f1ce31207ffc929a5c2c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_orcid.py @@ -0,0 +1,78 @@ +import json + +from social_core.backends.orcid import ORCIDOAuth2 + +from .oauth import OAuth2Test + + +class ORCIDOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.orcid.ORCIDOAuth2" + user_data_url = ORCIDOAuth2.USER_ID_URL + expected_username = "0000-0002-2601-8132" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "orcid-identifier": {"path": "0000-0002-2601-8132"}, + } + ) + user_data_body = json.dumps( + { + "orcid-identifier": { + "uri": "http://orcid.org/0000-0002-2601-8132", + "path": "0000-0002-2601-8132", + "host": "orcid.org", + }, + "person": { + "last-modified-date": None, + "name": { + "created-date": {"value": 1578249746904}, + "last-modified-date": {"value": 1578249746904}, + "given-names": {"value": "Janani Kantharooban"}, + "family-name": {"value": "Umachanger"}, + "credit-name": None, + "source": None, + "visibility": "PUBLIC", + "path": "0000-0002-2601-8132", + }, + "other-names": { + "last-modified-date": None, + "other-name": [], + "path": "/0000-0002-2601-8132/other-names", + }, + "biography": None, + "researcher-urls": { + "last-modified-date": None, + "researcher-url": [], + "path": "/0000-0002-2601-8132/researcher-urls", + }, + "emails": { + "last-modified-date": None, + "email": [], + "path": "/0000-0002-2601-8132/email", + }, + "addresses": { + "last-modified-date": None, + "address": [], + "path": "/0000-0002-2601-8132/address", + }, + "keywords": { + "last-modified-date": None, + "keyword": [], + "path": "/0000-0002-2601-8132/keywords", + }, + "external-identifiers": { + "last-modified-date": None, + "external-identifier": [], + "path": "/0000-0002-2601-8132/external-identifiers", + }, + "path": "/0000-0002-2601-8132/person", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_osso.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_osso.py new file mode 100644 index 0000000000000000000000000000000000000000..f720b36435f9c9de8182cc39dbf63d44bb36cd82 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_osso.py @@ -0,0 +1,30 @@ +import json + +from .oauth import OAuth2Test + + +class OssoOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.osso.OssoOAuth2" + user_data_url = "https://demo.ossoapp.com/oauth/me" + expected_username = "user@example.com" + access_token_body = json.dumps( + { + "access_token": "3633395cffe739bb87089235c152155ae73b6794f7af353b2aa189aeeacee1ec", + "token_type": "bearer", + "expires_in": 600, + } + ) + user_data_body = json.dumps( + { + "email": "user@example.com", + "id": "f23611a5-2817-43e2-94b7-99b25235ad2d", + "idp": "Okta", + "requested": {"email": None, "domain": "example.com"}, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_patreon.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_patreon.py new file mode 100644 index 0000000000000000000000000000000000000000..0a0240a124945b1657f6ea9366f235e157bc51f9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_patreon.py @@ -0,0 +1,69 @@ +import json + +from .oauth import OAuth2Test + + +class PatreonOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.patreon.PatreonOAuth2" + user_data_url = ( + "https://www.patreon.com/api/oauth2/v2/identity?" + + "fields%5Buser%5D=about,created,email,first_name,full_name," + + "image_url,last_name,social_connections,thumb_url,url,vanity" + ) + expected_username = "JohnInterwebs" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + } + ) + user_data_body = json.dumps( + { + "data": { + "relationships": { + "pledges": {"data": [{"type": "pledge", "id": "123456"}]} + }, + "attributes": { + "last_name": "Interwebs", + "is_suspended": False, + "has_password": True, + "full_name": "John Interwebs", + "is_nuked": False, + "first_name": "John", + "social_connections": { + "spotify": None, + "discord": None, + "twitter": None, + "youtube": None, + "facebook": None, + "deviantart": None, + "twitch": None, + }, + "twitter": None, + "is_email_verified": True, + "facebook_id": None, + "email": "john@example.com", + "facebook": None, + "thumb_url": "https://c8.patreon.com/100/123456", + "vanity": None, + "about": None, + "is_deleted": False, + "created": "2017-05-05T05:16:34+00:00", + "url": "https://www.patreon.com/user?u=123456", + "gender": 0, + "youtube": None, + "discord_id": None, + "image_url": "https://c8.patreon.com/400/123456", + "twitch": None, + }, + "type": "user", + "id": "123456", + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_paypal.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_paypal.py new file mode 100644 index 0000000000000000000000000000000000000000..52da164efe21ff70c67aa42b76d0f4b75a3b46ae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_paypal.py @@ -0,0 +1,81 @@ +import json + +from social_core.backends.paypal import PayPalOAuth2 + +from .oauth import OAuth2Test + + +class PayPalOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.paypal.PayPalOAuth2" + user_data_url = ( + "https://api.paypal.com/v1/identity/oauth2/userinfo?schema=paypalv1.1" + ) + expected_username = "mWq6_1sU85v5EG9yHdPxJRrhGHrnMJ-1PQKtX6pcsmA" + access_token_body = json.dumps( + { + "token_type": "Bearer", + "expires_in": 28800, + "refresh_token": "foobar-refresh-token", + "access_token": "foobar-token", + } + ) + user_data_body = json.dumps( + { + "user_id": "https://www.paypal.com/webapps/auth/identity/user/mWq6_1sU85v5EG9yHdPxJRrhGHrnMJ-1PQKtX6pcsmA", + "name": "identity test", + "given_name": "identity", + "family_name": "test", + "payer_id": "WDJJHEBZ4X2LY", + "address": { + "street_address": "1 Main St", + "locality": "San Jose", + "region": "CA", + "postal_code": "95131", + "country": "US", + }, + "verified_account": True, + "emails": [{"value": "user1@example.com", "primary": True}], + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "Bearer", + "refresh_token": "foobar-new-refresh-token", + "expires_in": 28800, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(user.username, self.expected_username) + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") + + def test_get_email_no_emails(self): + emails = [] + email = PayPalOAuth2.get_email(emails) + self.assertEqual(email, "") + + def test_get_email_multiple_emails(self): + expected_email = "mail2@example.com" + emails = [ + {"value": "mail1@example.com", "primary": False}, + {"value": expected_email, "primary": True}, + ] + email = PayPalOAuth2.get_email(emails) + self.assertEqual(email, expected_email) + + def test_get_email_multiple_emails_no_primary(self): + expected_email = "mail1@example.com" + emails = [ + {"value": expected_email, "primary": False}, + {"value": "mail2@example.com", "primary": False}, + ] + email = PayPalOAuth2.get_email(emails) + self.assertEqual(email, expected_email) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_phabricator.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_phabricator.py new file mode 100644 index 0000000000000000000000000000000000000000..f694be542e560baaa408455144bbb7c769b0d2b3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_phabricator.py @@ -0,0 +1,81 @@ +import json + +from .oauth import OAuth2Test + + +class PhabricatorOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.phabricator.PhabricatorOAuth2" + user_data_url = "https://secure.phabricator.com/api/user.whoami" + expected_username = "user" + access_token_body = json.dumps( + { + "access_token": "loremipsumdolorsitametenim", + "token_type": "Bearer", + "expires_in": 7200, + "refresh_token": "foobar", + } + ) + + user_data_body = json.dumps( + { + "phid": "PHID-USER-jbfcsj7c6nkt2tv3trb6", + "userName": "user", + "realName": "FirstName LastName", + "image": "https://secure.phabricator.com/file/data/4qjdpmvca4wwkfw2wevc" + "/PHID-FILE-t37vxezr54fjuvbrblkp/alphanumeric_lato-white_U.png" + "-_3f674d-255%2C255%2C255%2C0.7.png", + "uri": "https://secure.phabricator.com/p/user/", + "roles": ["admin", "verified", "approved", "activated"], + "primaryEmail": "user@example.com", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class PhabricatorCustomDomainOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.phabricator.PhabricatorOAuth2" + user_data_url = "https://example.com/api/user.whoami" + expected_username = "user" + access_token_body = json.dumps( + { + "access_token": "loremipsumdolorsitametenim", + "token_type": "Bearer", + "expires_in": 7200, + "refresh_token": "foobar", + } + ) + + user_data_body = json.dumps( + { + "phid": "PHID-USER-jbfcsj7c6nkt2tv3trb6", + "userName": "user", + "realName": "FirstName LastName", + "image": "https://example.com/file/data/4qjdpmvca4wwkfw2wevc/PHID-FILE-" + "t37vxezr54fjuvbrblkp/alphanumeric_lato-white_U.png-_3f674d-25" + "5%2C255%2C255%2C0.7.png", + "uri": "https://example.com/p/user/", + "roles": ["admin", "verified", "approved", "activated"], + "primaryEmail": "user@example.com", + } + ) + + def test_login(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_PHABRICATOR_API_URL": "https://example.com", + } + ) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_PHABRICATOR_API_URL": "https://example.com", + } + ) + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_pinterest.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_pinterest.py new file mode 100644 index 0000000000000000000000000000000000000000..f1b8cbf51beb1e27f77671323798f10f2e785de3 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_pinterest.py @@ -0,0 +1,47 @@ +import json + +from .oauth import OAuth2Test + + +class PinterestOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.pinterest.PinterestOAuth2" + user_data_url = "https://api.pinterest.com/v1/me/" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "id": "4788400174839062", + "first_name": "Foo", + "last_name": "Bar", + "username": "foobar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class PinterestOAuth2BrokenServerResponseTest(OAuth2Test): + backend_path = "social_core.backends.pinterest.PinterestOAuth2" + user_data_url = "https://api.pinterest.com/v1/me/" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "data": { + "id": "4788400174839062", + "first_name": "Foo", + "last_name": "Bar", + "url": "https://www.pinterest.com/foobar/", + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_podio.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_podio.py new file mode 100644 index 0000000000000000000000000000000000000000..3615bac4b3c87f87a89b0d1c38e367b736005ba0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_podio.py @@ -0,0 +1,61 @@ +import json + +from .oauth import OAuth2Test + + +class PodioOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.podio.PodioOAuth2" + user_data_url = "https://api.podio.com/user/status" + expected_username = "user_1010101010" + access_token_body = json.dumps( + { + "token_type": "bearer", + "access_token": "11309ea9016a4ad99f1a3bcb9bc7a9d1", + "refresh_token": "52d01df8b9ac46a4a6be1333d9f81ef2", + "expires_in": 28800, + "ref": { + "type": "user", + "id": 1010101010, + }, + } + ) + user_data_body = json.dumps( + { + "user": { + "user_id": 1010101010, + "activated_on": "2012-11-22 09:37:21", + "created_on": "2012-11-21 12:23:47", + "locale": "en_GB", + "timezone": "Europe/Copenhagen", + "mail": "foo@bar.com", + "mails": [ + { + "disabled": False, + "mail": "foobar@example.com", + "primary": False, + "verified": True, + }, + { + "disabled": False, + "mail": "foo@bar.com", + "primary": True, + "verified": True, + }, + ], + # more properties ... + }, + "profile": { + "last_seen_on": "2013-05-16 12:21:13", + "link": "https://podio.com/users/1010101010", + "name": "Foo Bar", + # more properties ... + } + # more properties ... + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_qiita.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_qiita.py new file mode 100644 index 0000000000000000000000000000000000000000..3b3d7d99252fa4326282e6f4df2f6401f141a82f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_qiita.py @@ -0,0 +1,104 @@ +import json + +from social_core.exceptions import AuthException + +from .oauth import OAuth2Test + + +class QiitaOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.qiita.QiitaOAuth2" + user_data_url = "https://qiita.com/api/v2/authenticated_user" + expected_username = "foobar" + + access_token_body = json.dumps({"token": "foobar", "token_type": "bearer"}) + + user_data_body = json.dumps( + { + "id": "foobar", + "name": "Foo Bar", + "description": "Hello, world.", + "facebook_id": "qiita", + "followees_count": 100, + "followers_count": 200, + "github_login_name": "qiitan", + "items_count": 300, + "linkedin_id": "qiita", + "location": "Tokyo, Japan", + "organization": "Qiita Inc.", + "permanent_id": 12345, + "profile_image_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/88" + "/ccf90b557a406157dbb9d2d7e543dae384dbb561/large.png?1575443439", + "team_only": False, + "twitter_screen_name": "qiita", + "website_url": "https://qiita.com", + "image_monthly_upload_limit": 1048576, + "image_monthly_upload_remaining": 524288, + } + ) + + def test_login(self): + user = self.do_login() + self.assertEqual(len(user.social), 1) + + social = user.social[0] + self.assertEqual(social.uid, "foobar") + self.assertEqual(social.extra_data["permanent_id"], 12345) + + def test_partial_pipeline(self): + user = self.do_partial_pipeline() + self.assertEqual(len(user.social), 1) + + social = user.social[0] + self.assertEqual(social.uid, "foobar") + self.assertEqual(social.extra_data["permanent_id"], 12345) + + +class QiitaOAuth2TestIdentifiedByPermanentId(QiitaOAuth2Test): + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_QIITA_IDENTIFIED_BY_PERMANENT_ID": True} + ) + + user = self.do_login() + self.assertEqual(len(user.social), 1) + + social = user.social[0] + self.assertEqual(social.uid, "12345") + self.assertEqual(social.extra_data["permanent_id"], 12345) + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_QIITA_IDENTIFIED_BY_PERMANENT_ID": True} + ) + + user = self.do_partial_pipeline() + self.assertEqual(len(user.social), 1) + + social = user.social[0] + self.assertEqual(social.uid, "12345") + self.assertEqual(social.extra_data["permanent_id"], 12345) + + +class QiitaOAuth2TestIdentifiedByPermanentIdAuthException(QiitaOAuth2Test): + user_data_body = json.dumps( + { + "id": "foobar", + "name": "Foo Bar", + } + ) + + def test_login(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_QIITA_IDENTIFIED_BY_PERMANENT_ID": True} + ) + + with self.assertRaises(AuthException): + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_QIITA_IDENTIFIED_BY_PERMANENT_ID": True} + ) + + with self.assertRaises(AuthException): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_quizlet.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_quizlet.py new file mode 100644 index 0000000000000000000000000000000000000000..f932459839763ec8a9a54912bba9358f156d47ba --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_quizlet.py @@ -0,0 +1,24 @@ +import json + +from .oauth import OAuth2Test + + +class QuizletOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.quizlet.QuizletOAuth2" + expected_username = "foo_bar" + + access_token_body = json.dumps( + { + "access_token": "EE1IDxytP04tJ767GbjH7ED9PpGmYvL", + "token_type": "Bearer", + "expires_in": 3600, + "scope": "read", + "user_id": "foo_bar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_readability.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_readability.py new file mode 100644 index 0000000000000000000000000000000000000000..cec83579a0885cf06b0a14b348b3bfc9e2f71304 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_readability.py @@ -0,0 +1,41 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class ReadabilityOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.readability.ReadabilityOAuth" + user_data_url = "https://www.readability.com/api/rest/v1/users/_current" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "username": "foobar", + "first_name": "Foo", + "last_name": "Bar", + "has_active_subscription": False, + "tags": [], + "is_publisher": False, + "email_into_address": "foobar+sharp@inbox.readability.com", + "kindle_email_address": None, + "avatar_url": "https://secure.gravatar.com/avatar/" + "5280f15cedf540b544eecc30fcf3027c?d=" + "https://www.readability.com/media/images/" + "avatar.png&s=36", + "date_joined": "2013-03-18 02:51:02", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_reddit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_reddit.py new file mode 100644 index 0000000000000000000000000000000000000000..e66e49e470ed8dcf1a97418133aa02c0a624beea --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_reddit.py @@ -0,0 +1,65 @@ +import json + +from .oauth import OAuth2Test + + +class RedditOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.reddit.RedditOAuth2" + user_data_url = "https://oauth.reddit.com/api/v1/me.json" + expected_username = "foobar" + access_token_body = json.dumps( + { + "name": "foobar", + "created": 1203420772.0, + "access_token": "foobar-token", + "created_utc": 1203420772.0, + "expires_in": 3600.0, + "link_karma": 34, + "token_type": "bearer", + "comment_karma": 167, + "over_18": True, + "is_gold": False, + "is_mod": True, + "scope": "identity", + "has_verified_email": False, + "id": "33bma", + "refresh_token": "foobar-refresh-token", + } + ) + user_data_body = json.dumps( + { + "name": "foobar", + "created": 1203420772.0, + "created_utc": 1203420772.0, + "link_karma": 34, + "comment_karma": 167, + "over_18": True, + "is_gold": False, + "is_mod": True, + "has_verified_email": False, + "id": "33bma", + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "bearer", + "expires_in": 3600.0, + "refresh_token": "foobar-new-refresh-token", + "scope": "identity", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def refresh_token_arguments(self): + uri = self.strategy.build_absolute_uri("/complete/reddit/") + return {"redirect_uri": uri} + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_saml.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_saml.py new file mode 100644 index 0000000000000000000000000000000000000000..a59fbebaabb3d1faf999002e6ea8f200374c020c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_saml.py @@ -0,0 +1,122 @@ +import json +import os +import re +import sys +import unittest +from os import path +from unittest.mock import patch +from urllib.parse import parse_qs, urlencode, urlparse, urlunparse + +import requests +from httpretty import HTTPretty + +try: + from onelogin.saml2.utils import OneLogin_Saml2_Utils +except ImportError: + # Only available for python 2.7 at the moment, so don't worry if this fails + pass + +from ...exceptions import AuthMissingParameter +from .base import BaseBackendTest + +DATA_DIR = path.join(path.dirname(__file__), "data") + + +@unittest.skipIf( + "TRAVIS" in os.environ, + "Travis-ci segfaults probably due to a bad " "dependencies build", +) +@unittest.skipIf( + "__pypy__" in sys.builtin_module_names, "dm.xmlsec not compatible with pypy" +) +class SAMLTest(BaseBackendTest): + backend_path = "social_core.backends.saml.SAMLAuth" + expected_username = "myself" + + def extra_settings(self): + name = path.join(DATA_DIR, "saml_config.json") + with open(name) as config_file: + config_str = config_file.read() + return json.loads(config_str) + + def setUp(self): + """Patch the time so that we can replay canned + request/response pairs""" + super().setUp() + + @staticmethod + def fixed_time(): + return OneLogin_Saml2_Utils.parse_SAML_to_time("2015-05-09T03:57:22Z") + + now_patch = patch.object(OneLogin_Saml2_Utils, "now", fixed_time) + now_patch.start() + self.addCleanup(now_patch.stop) + + def install_http_intercepts(self, start_url, return_url): + # When we request start_url + # (https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO...) + # we will eventually get a redirect back, with SAML assertion + # data in the query string. A pre-recorded correct response + # is kept in this .txt file: + name = path.join(DATA_DIR, "saml_response.txt") + with open(name) as response_file: + response_url = response_file.read() + HTTPretty.register_uri( + HTTPretty.GET, start_url, status=301, location=response_url + ) + HTTPretty.register_uri(HTTPretty.GET, return_url, status=200, body="foobar") + + def do_start(self): + start_url = self.backend.start().url + # Modify the start URL to make the SAML request consistent + # from test to test: + start_url = self.modify_start_url(start_url) + # If the SAML Identity Provider recognizes the user, we will + # be redirected back to: + return_url = self.backend.redirect_uri + self.install_http_intercepts(start_url, return_url) + response = requests.get(start_url) + self.assertTrue(response.url.startswith(return_url)) + self.assertEqual(response.text, "foobar") + query_values = { + k: v[0] for k, v in parse_qs(urlparse(response.url).query).items() + } + self.assertNotIn(" ", query_values["SAMLResponse"]) + self.strategy.set_request_data(query_values, self.backend) + return self.backend.complete() + + def test_metadata_generation(self): + """Test that we can generate the metadata without error""" + xml, errors = self.backend.generate_metadata_xml() + self.assertEqual(len(errors), 0) + self.assertEqual(xml.decode()[0], "<") + + def test_login(self): + """Test that we can authenticate with a SAML IdP (TestShib)""" + # pretend we've started with a URL like /login/saml/?idp=testshib: + self.strategy.set_request_data({"idp": "testshib"}, self.backend) + self.do_login() + + def test_login_no_idp(self): + """Logging in without an idp param should raise AuthMissingParameter""" + with self.assertRaises(AuthMissingParameter): + self.do_start() + + def modify_start_url(self, start_url): + """ + Given a SAML redirect URL, parse it and change the ID to + a consistent value, so the request is always identical. + """ + # Parse the SAML Request URL to get the XML being sent to TestShib + url_parts = urlparse(start_url) + query = {k: v[0] for (k, v) in parse_qs(url_parts.query).items()} + xml = OneLogin_Saml2_Utils.decode_base64_and_inflate(query["SAMLRequest"]) + # Modify the XML: + xml = xml.decode() + xml, changed = re.subn(r'ID="[^"]+"', 'ID="TEST_ID"', xml) + self.assertEqual(changed, 1) + # Update the URL to use the modified query string: + query["SAMLRequest"] = OneLogin_Saml2_Utils.deflate_and_base64_encode(xml) + url_parts = list(url_parts) + url_parts[4] = urlencode(query) + return urlunparse(url_parts) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_scistarter.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_scistarter.py new file mode 100644 index 0000000000000000000000000000000000000000..dcafe8716d8225491161890cef33fdaec87ac759 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_scistarter.py @@ -0,0 +1,28 @@ +import json + +from .oauth import OAuth2Test + + +class ScistarterOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.scistarter.SciStarterOAuth2" + user_data_url = "https://scistarter.com/api/user_info" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "profile_id": 42006, + "user_id": 5, + "url": "https://scistarter.com/user/foobar", + "result": "success", + "handle": "foobar", + "email": "foo@bar.com", + "first_name": "foo", + "last_name": "bar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_seznam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_seznam.py new file mode 100644 index 0000000000000000000000000000000000000000..d71f1e2f5fc95f057982d20e5dfe9a64fd4ee215 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_seznam.py @@ -0,0 +1,35 @@ +import json + +from .oauth import OAuth2Test + + +class SeznamOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.seznam.SeznamOAuth2" + user_data_url = "https://login.szn.cz/api/v1/user" + expected_username = "krasty" + access_token_body = json.dumps( + { + "access_token": "foo", + "account_name": "krasty@seznam.cz", + "expires_in": 31536000, + "oauth_user_id": "0123abcd", + "refresh_token": "bar", + "scopes": ["identity"], + "token_type": "bearer", + } + ) + user_data_body = json.dumps( + { + "email": "krasty@seznam.cz", + "firstname": "Krasty", + "lastname": "Dog", + "oauth_user_id": "0123abcd", + "username": "krasty", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_simplelogin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_simplelogin.py new file mode 100644 index 0000000000000000000000000000000000000000..ba2b9cb02959ef7bd5c8fb8459295c7d4609e7dc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_simplelogin.py @@ -0,0 +1,26 @@ +import json + +from .oauth import OAuth2Test + + +class SimpleLoginOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.simplelogin.SimpleLoginOAuth2" + user_data_url = "https://app.simplelogin.io/oauth2/userinfo" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "client": "Continental", + "email": "john@wick.com", + "email_verified": True, + "id": 1, + "name": "John Wick", + "avatar_url": "http://wick.com/john.png", + } + ) + expected_username = "john@wick.com" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_sketchfab.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_sketchfab.py new file mode 100644 index 0000000000000000000000000000000000000000..973794596c89c947d7a825680f3c56fea0101ecc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_sketchfab.py @@ -0,0 +1,25 @@ +import json + +from .oauth import OAuth2Test + + +class SketchfabOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.sketchfab.SketchfabOAuth2" + user_data_url = "https://sketchfab.com/v2/users/me" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "uid": "42", + "email": "foo@bar.com", + "displayName": "foo bar", + "username": "foobar", + "apiToken": "XXX", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_skyrock.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_skyrock.py new file mode 100644 index 0000000000000000000000000000000000000000..bdeca0c574adaa3b48ee3adcc0ad11e19f5e892e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_skyrock.py @@ -0,0 +1,49 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class SkyrockOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.skyrock.SkyrockOAuth" + user_data_url = "https://api.skyrock.com/v2/user/get.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + } + ) + user_data_body = json.dumps( + { + "locale": "en_US", + "city": "", + "has_blog": False, + "web_messager_enabled": True, + "email": "foo@bar.com", + "username": "foobar", + "firstname": "Foo", + "user_url": "", + "address1": "", + "address2": "", + "has_profile": False, + "allow_messages_from": "everybody", + "is_online": False, + "postalcode": "", + "lang": "en", + "id_user": 10101010, + "name": "Bar", + "gender": 0, + "avatar_url": "http://www.skyrock.com/img/avatars/default-0.jpg", + "nb_friends": 0, + "country": "US", + "birth_date": "1980-06-10", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_slack.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_slack.py new file mode 100644 index 0000000000000000000000000000000000000000..24b377ff8fa1fdc9531d2bb671b82bc13b4b866d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_slack.py @@ -0,0 +1,61 @@ +import json + +from .oauth import OAuth2Test + + +class SlackOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.slack.SlackOAuth2" + user_data_url = "https://slack.com/api/users.identity" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "ok": True, + "user": {"email": "foobar@example.com", "name": "Foo Bar", "id": "123456"}, + "team": {"id": "456789"}, + "scope": "identity.basic,identity.email", + } + ) + expected_username = "foobar" + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class SlackOAuth2TestTeamName(SlackOAuth2Test): + expected_username = "foobar@Square" + user_data_body = json.dumps( + { + "ok": True, + "user": {"email": "foobar@example.com", "name": "Foo Bar", "id": "123456"}, + "team": { + "id": "456789", + "name": "Square", + }, + "scope": "identity.basic,identity.email,identity.team", + } + ) + + +class SlackOAuth2TestUnicodeTeamName(SlackOAuth2Test): + user_data_body = json.dumps( + { + "ok": True, + "user": {"email": "foobar@example.com", "name": "Foo Bar", "id": "123456"}, + "team": { + "id": "456789", + "name": "Square \u221a team", + }, + "scope": "identity.basic,identity.email,identity.team", + } + ) + + def test_login(self): + self.strategy.set_settings({"SOCIAL_AUTH_SLACK_USERNAME_WITH_TEAM": False}) + self.do_login() + + def test_partial_pipeline(self): + self.strategy.set_settings({"SOCIAL_AUTH_SLACK_USERNAME_WITH_TEAM": False}) + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_soundcloud.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_soundcloud.py new file mode 100644 index 0000000000000000000000000000000000000000..974bbc9beec0d78636ca9c142e4b3dd081395b24 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_soundcloud.py @@ -0,0 +1,53 @@ +import json + +from .oauth import OAuth2Test + + +class SoundcloudOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.soundcloud.SoundcloudOAuth2" + user_data_url = "https://api.soundcloud.com/me.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "website": None, + "myspace_name": None, + "public_favorites_count": 0, + "followings_count": 0, + "full_name": "Foo Bar", + "id": 10101010, + "city": None, + "track_count": 0, + "playlist_count": 0, + "discogs_name": None, + "private_tracks_count": 0, + "followers_count": 0, + "online": True, + "username": "foobar", + "description": None, + "subscriptions": [], + "kind": "user", + "quota": { + "unlimited_upload_quota": False, + "upload_seconds_left": 7200, + "upload_seconds_used": 0, + }, + "website_title": None, + "primary_email_confirmed": False, + "permalink_url": "http://soundcloud.com/foobar", + "private_playlists_count": 0, + "permalink": "foobar", + "upload_seconds_left": 7200, + "country": None, + "uri": "https://api.soundcloud.com/users/10101010", + "avatar_url": "https://a1.sndcdn.com/images/" + "default_avatar_large.png?ca77017", + "plan": "Free", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_spotify.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_spotify.py new file mode 100644 index 0000000000000000000000000000000000000000..ebdf969ac9578110b95df49be1c31ccac8914ae9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_spotify.py @@ -0,0 +1,28 @@ +import json + +from .oauth import OAuth2Test + + +class SpotifyOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.spotify.SpotifyOAuth2" + user_data_url = "https://api.spotify.com/v1/me" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "display_name": None, + "external_urls": {"spotify": "https://open.spotify.com/user/foobar"}, + "followers": {"href": None, "total": 0}, + "href": "https://api.spotify.com/v1/users/foobar", + "id": "foobar", + "images": [], + "type": "user", + "uri": "spotify:user:foobar", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stackoverflow.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stackoverflow.py new file mode 100644 index 0000000000000000000000000000000000000000..5cbbc29b5882125d3ebe196944b1dacaefc1a150 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stackoverflow.py @@ -0,0 +1,49 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth2Test + + +class StackoverflowOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.stackoverflow.StackoverflowOAuth2" + user_data_url = "https://api.stackexchange.com/2.1/me" + expected_username = "foobar" + access_token_body = urlencode({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "items": [ + { + "user_id": 101010, + "user_type": "registered", + "creation_date": 1278525551, + "display_name": "foobar", + "profile_image": "http: //www.gravatar.com/avatar/" + "5280f15cedf540b544eecc30fcf3027c?" + "d=identicon&r=PG", + "reputation": 547, + "reputation_change_day": 0, + "reputation_change_week": 0, + "reputation_change_month": 0, + "reputation_change_quarter": 65, + "reputation_change_year": 65, + "age": 22, + "last_access_date": 1363544705, + "last_modified_date": 1354035327, + "is_employee": False, + "link": "http: //stackoverflow.com/users/101010/foobar", + "location": "Fooland", + "account_id": 101010, + "badge_counts": {"gold": 0, "silver": 3, "bronze": 6}, + } + ], + "quota_remaining": 9997, + "quota_max": 10000, + "has_more": False, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_steam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_steam.py new file mode 100644 index 0000000000000000000000000000000000000000..d0e31cbd70d4b3df3f2b0aeb0317d3eaa63ff476 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_steam.py @@ -0,0 +1,142 @@ +import datetime +import json +from urllib.parse import urlencode + +from httpretty import HTTPretty + +from ...exceptions import AuthFailed +from .open_id import OpenIdTest + +INFO_URL = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?" +JANRAIN_NONCE = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") + + +class SteamOpenIdTest(OpenIdTest): + backend_path = "social_core.backends.steam.SteamOpenId" + expected_username = "foobar" + discovery_body = "".join( + [ + '<?xml version="1.0" encoding="UTF-8"?>', + '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">', + "<XRD>", + '<Service priority="0">', + "<Type>http://specs.openid.net/auth/2.0/server</Type>", + "<URI>https://steamcommunity.com/openid/login</URI>", + "</Service>", + "</XRD>", + "</xrds:XRDS>", + ] + ) + user_discovery_body = "".join( + [ + '<?xml version="1.0" encoding="UTF-8"?>', + '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">', + "<XRD>", + '<Service priority="0">', + "<Type>http://specs.openid.net/auth/2.0/signon</Type> ", + "<URI>https://steamcommunity.com/openid/login</URI>", + "</Service>", + "</XRD>", + "</xrds:XRDS>", + ] + ) + server_response = urlencode( + { + "janrain_nonce": JANRAIN_NONCE, + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.mode": "id_res", + "openid.op_endpoint": "https://steamcommunity.com/openid/login", + "openid.claimed_id": "https://steamcommunity.com/openid/id/123", + "openid.identity": "https://steamcommunity.com/openid/id/123", + "openid.return_to": "http://myapp.com/complete/steam/?" + "janrain_nonce=" + JANRAIN_NONCE, + "openid.response_nonce": JANRAIN_NONCE + "oD4UZ3w9chOAiQXk0AqDipqFYRA=", + "openid.assoc_handle": "1234567890", + "openid.signed": "signed,op_endpoint,claimed_id,identity,return_to," + "response_nonce,assoc_handle", + "openid.sig": "1az53vj9SVdiBwhk8%2BFQ68R2plo=", + } + ) + player_details = json.dumps( + { + "response": { + "players": [ + { + "steamid": "123", + "primaryclanid": "1234", + "timecreated": 1360768416, + "personaname": "foobar", + "personastate": 0, + "communityvisibilitystate": 3, + "profileurl": "http://steamcommunity.com/profiles/123/", + "avatar": "http://media.steampowered.com/steamcommunity/" + "public/images/avatars/fe/fef49e7fa7e1997310d7" + "05b2a6158ff8dc1cdfeb.jpg", + "avatarfull": "http://media.steampowered.com/steamcommunity/" + "public/images/avatars/fe/fef49e7fa7e1997310d7" + "05b2a6158ff8dc1cdfeb_full.jpg", + "avatarmedium": "http://media.steampowered.com/steamcommunity/" + "public/images/avatars/fe/fef49e7fa7e1997310d7" + "05b2a6158ff8dc1cdfeb_medium.jpg", + "lastlogoff": 1360790014, + } + ] + } + } + ) + + def _login_setup(self, user_url=None): + self.strategy.set_settings({"SOCIAL_AUTH_STEAM_API_KEY": "123abc"}) + HTTPretty.register_uri( + HTTPretty.POST, + "https://steamcommunity.com/openid/login", + status=200, + body=self.server_response, + ) + HTTPretty.register_uri( + HTTPretty.GET, + user_url or "https://steamcommunity.com/openid/id/123", + status=200, + body=self.user_discovery_body, + ) + HTTPretty.register_uri( + HTTPretty.GET, INFO_URL, status=200, body=self.player_details + ) + + def test_login(self): + self._login_setup() + self.do_login() + + def test_partial_pipeline(self): + self._login_setup() + self.do_partial_pipeline() + + +class SteamOpenIdMissingSteamIdTest(SteamOpenIdTest): + server_response = urlencode( + { + "janrain_nonce": JANRAIN_NONCE, + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.mode": "id_res", + "openid.op_endpoint": "https://steamcommunity.com/openid/login", + "openid.claimed_id": "https://steamcommunity.com/openid/BROKEN", + "openid.identity": "https://steamcommunity.com/openid/BROKEN", + "openid.return_to": "http://myapp.com/complete/steam/?" + "janrain_nonce=" + JANRAIN_NONCE, + "openid.response_nonce": JANRAIN_NONCE + "oD4UZ3w9chOAiQXk0AqDipqFYRA=", + "openid.assoc_handle": "1234567890", + "openid.signed": "signed,op_endpoint,claimed_id,identity,return_to," + "response_nonce,assoc_handle", + "openid.sig": "1az53vj9SVdiBwhk8%2BFQ68R2plo=", + } + ) + + def test_login(self): + self._login_setup(user_url="https://steamcommunity.com/openid/BROKEN") + with self.assertRaises(AuthFailed): + self.do_login() + + def test_partial_pipeline(self): + self._login_setup(user_url="https://steamcommunity.com/openid/BROKEN") + with self.assertRaises(AuthFailed): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stocktwits.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stocktwits.py new file mode 100644 index 0000000000000000000000000000000000000000..c6404d9203db48df65e52e01a8d29893cc26d151 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stocktwits.py @@ -0,0 +1,51 @@ +import json + +from .oauth import OAuth2Test + + +class StocktwitsOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.stocktwits.StocktwitsOAuth2" + user_data_url = "https://api.stocktwits.com/api/2/account/verify.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "response": {"status": 200}, + "user": { + "username": "foobar", + "name": "Foo Bar", + "classification": [], + "avatar_url": "http://avatars.stocktwits.net/images/" + "default_avatar_thumb.jpg", + "avatar_url_ssl": "https://s3.amazonaws.com/st-avatars/images/" + "default_avatar_thumb.jpg", + "id": 101010, + "identity": "User", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class StocktwitsOAuth2UsernameAlternativeTest(StocktwitsOAuth2Test): + user_data_body = json.dumps( + { + "response": {"status": 200}, + "user": { + "username": "foobar", + "name": "Foobar", + "classification": [], + "avatar_url": "http://avatars.stocktwits.net/images/" + "default_avatar_thumb.jpg", + "avatar_url_ssl": "https://s3.amazonaws.com/st-avatars/images/" + "default_avatar_thumb.jpg", + "id": 101010, + "identity": "User", + }, + } + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_strava.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_strava.py new file mode 100644 index 0000000000000000000000000000000000000000..a7a962d5bb8a0d96e4fa768e4e756655c0c07285 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_strava.py @@ -0,0 +1,76 @@ +import json + +from .oauth import OAuth2Test + + +class StravaOAuthTest(OAuth2Test): + backend_path = "social_core.backends.strava.StravaOAuth" + user_data_url = "https://www.strava.com/api/v3/athlete" + expected_username = "marianne_v" + access_token_body = json.dumps( + { + "token_type": "Bearer", + "expires_at": 1572805000, + "expires_in": 227615, + "refresh_token": "f51defab4632d27255dd0d106504dfd7568fd1df6", + "access_token": "83ebeabdec09f6670863766f792ead24d61fe3f9", + "athlete": { + "id": 1234567890987654321, + "username": "marianne_v", + "resource_state": 2, + "firstname": "Marianne", + "lastname": "V.", + "city": "Francisco", + "state": "California", + "country": "United States", + "sex": "F", + "premium": "true", + "summit": "true", + "created_at": "2017-11-14T02:30:05Z", + "updated_at": "2018-02-06T19:32:20Z", + "badge_type_id": 4, + "profile_medium": "https://xxxxxx.cloudfront.net/pictures/athletes/123456789/123456789/2/medium.jpg", + "profile": "https://xxxxx.cloudfront.net/pictures/athletes/123456789/123456789/2/large.jpg", + "friend": "null", + "follower": "null", + }, + } + ) + user_data_body = json.dumps( + { + "id": 1234567890987654321, + "username": "marianne_v", + "resource_state": 3, + "firstname": "Marianne", + "lastname": "V.", + "city": "San Francisco", + "state": "CA", + "country": "US", + "sex": "F", + "premium": "true", + "created_at": "2017-11-14T02:30:05Z", + "updated_at": "2018-02-06T19:32:20Z", + "badge_type_id": 4, + "profile_medium": "https://xxxxxx.cloudfront.net/pictures/athletes/123456789/123456789/2/medium.jpg", + "profile": "https://xxxxx.cloudfront.net/pictures/athletes/123456789/123456789/2/large.jpg", + "friend": "null", + "follower": "null", + "follower_count": 5, + "friend_count": 5, + "mutual_friend_count": 0, + "athlete_type": 1, + "date_preference": "%m/%d/%Y", + "measurement_preference": "feet", + "clubs": [], + "ftp": "null", + "weight": 0, + "bikes": [], + "shoes": [], + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stripe.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stripe.py new file mode 100644 index 0000000000000000000000000000000000000000..0a36846db232329c537156b81a074a86052ef6b8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_stripe.py @@ -0,0 +1,52 @@ +import json + +import requests +from httpretty import HTTPretty + +from .oauth import OAuth2Test + + +class StripeOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.stripe.StripeOAuth2" + account_data_url = "https://api.stripe.com/v1/account" + access_token_body = json.dumps( + { + "stripe_publishable_key": "pk_test_foobar", + "access_token": "foobar", + "livemode": False, + "token_type": "bearer", + "scope": "read_only", + "refresh_token": "rt_foobar", + "stripe_user_id": "acct_foobar", + } + ) + expected_username = "acct_foobar" + user_data_body = json.dumps( + { + "id": "acct_1LUYJiECsxMRIeT8", + "object": "account", + "country": "FR", + "created": 1659974194, + "default_currency": "eur", + "details_submitted": True, + "email": "foobar@yahoo.com", + "type": "express", + } + ) + + def setUp(self): + super().setUp() + HTTPretty.register_uri( + HTTPretty.GET, self.account_data_url, status=200, body=self.user_data_body + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_get_user_details(self): + response = requests.get(self.account_data_url) + user_details = self.backend.get_user_details(response.json()) + self.assertEqual(user_details["email"], "foobar@yahoo.com") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_taobao.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_taobao.py new file mode 100644 index 0000000000000000000000000000000000000000..9216b340eabd0957dfcb35e0cb439f020af50640 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_taobao.py @@ -0,0 +1,28 @@ +import json + +from .oauth import OAuth2Test + + +class TaobaoOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.taobao.TAOBAOAuth" + user_data_url = "https://eco.taobao.com/router/rest" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "w2_expires_in": 0, + "taobao_user_id": "1", + "taobao_user_nick": "foobar", + "w1_expires_in": 1800, + "re_expires_in": 0, + "r2_expires_in": 0, + "expires_in": 86400, + "r1_expires_in": 1800, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_thisismyjam.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_thisismyjam.py new file mode 100644 index 0000000000000000000000000000000000000000..453a8b78d8e978cfc376f9b6f972faaee642132d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_thisismyjam.py @@ -0,0 +1,27 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class ThisIsMyJameOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.thisismyjam.ThisIsMyJamOAuth1" + user_data_url = "http://api.thisismyjam.com/1/verify.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + {"id": 10101010, "person": {"name": "foobar", "fullname": "Foo Bar"}} + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tripit.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tripit.py new file mode 100644 index 0000000000000000000000000000000000000000..52ed159c1e1c02dbebb397383fdfe30e8229853e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tripit.py @@ -0,0 +1,102 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class TripitOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.tripit.TripItOAuth" + user_data_url = "https://api.tripit.com/v1/get/profile" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_content_type = "text/xml" + user_data_body = ( + "<Response>" + "<timestamp>1363590451</timestamp>" + "<num_bytes>1040</num_bytes>" + '<Profile ref="ignore-me">' + "<ProfileEmailAddresses>" + "<ProfileEmailAddress>" + "<address>foobar@gmail.com</address>" + "<is_auto_import>false</is_auto_import>" + "<is_confirmed>true</is_confirmed>" + "<is_primary>true</is_primary>" + "<is_auto_inbox_eligible>" + "true" + "</is_auto_inbox_eligible>" + "</ProfileEmailAddress>" + "</ProfileEmailAddresses>" + "<is_client>true</is_client>" + "<is_pro>false</is_pro>" + "<screen_name>foobar</screen_name>" + "<public_display_name>Foo Bar</public_display_name>" + "<profile_url>people/foobar</profile_url>" + "<home_city>Foo, Barland</home_city>" + "<activity_feed_url>" + "https://www.tripit.com/feed/activities/private/" + "ignore-this/activities.atom" + "</activity_feed_url>" + "<alerts_feed_url>" + "https://www.tripit.com/feed/alerts/private/" + "ignore-this/alerts.atom" + "</alerts_feed_url>" + "<ical_url>" + "webcal://www.tripit.com/feed/ical/private/" + "ignore-this/tripit.ics" + "</ical_url>" + "</Profile>" + "</Response>" + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class TripitOAuth1UsernameAlternativesTest(TripitOAuth1Test): + user_data_body = ( + "<Response>" + "<timestamp>1363590451</timestamp>" + "<num_bytes>1040</num_bytes>" + '<Profile ref="ignore-me">' + "<ProfileEmailAddresses>" + "<ProfileEmailAddress>" + "<address>foobar@gmail.com</address>" + "<is_auto_import>false</is_auto_import>" + "<is_confirmed>true</is_confirmed>" + "<is_primary>true</is_primary>" + "<is_auto_inbox_eligible>" + "true" + "</is_auto_inbox_eligible>" + "</ProfileEmailAddress>" + "</ProfileEmailAddresses>" + "<is_client>true</is_client>" + "<is_pro>false</is_pro>" + "<screen_name>foobar</screen_name>" + "<public_display_name>Foobar</public_display_name>" + "<profile_url>people/foobar</profile_url>" + "<home_city>Foo, Barland</home_city>" + "<activity_feed_url>" + "https://www.tripit.com/feed/activities/private/" + "ignore-this/activities.atom" + "</activity_feed_url>" + "<alerts_feed_url>" + "https://www.tripit.com/feed/alerts/private/" + "ignore-this/alerts.atom" + "</alerts_feed_url>" + "<ical_url>" + "webcal://www.tripit.com/feed/ical/private/" + "ignore-this/tripit.ics" + "</ical_url>" + "</Profile>" + "</Response>" + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tumblr.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tumblr.py new file mode 100644 index 0000000000000000000000000000000000000000..69dcd6c7d3c5d47422102ed4de8a8aa86462892c --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_tumblr.py @@ -0,0 +1,59 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class TumblrOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.tumblr.TumblrOAuth" + user_data_url = "http://api.tumblr.com/v2/user/info" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "meta": {"status": 200, "msg": "OK"}, + "response": { + "user": { + "following": 1, + "blogs": [ + { + "updated": 0, + "description": "", + "drafts": 0, + "title": "Untitled", + "url": "http://foobar.tumblr.com/", + "messages": 0, + "tweet": "N", + "share_likes": True, + "posts": 0, + "primary": True, + "queue": 0, + "admin": True, + "followers": 0, + "ask": False, + "facebook": "N", + "type": "public", + "facebook_opengraph_enabled": "N", + "name": "foobar", + } + ], + "default_post_format": "html", + "name": "foobar", + "likes": 0, + } + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitch.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitch.py new file mode 100644 index 0000000000000000000000000000000000000000..b36e8e1c7ee8f81c22c85a977d0ebc4ad6f0aa13 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitch.py @@ -0,0 +1,91 @@ +import json + +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + + +class TwitchOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.twitch.TwitchOpenIdConnect" + user_data_url = "https://id.twitch.tv/oauth2/userinfo" + issuer = "https://id.twitch.tv/oauth2" + expected_username = "test_user1" + openid_config_body = json.dumps( + { + "authorization_endpoint": "https://id.twitch.tv/oauth2/authorize", + "claims_parameter_supported": True, + "claims_supported": [ + "iss", + "azp", + "preferred_username", + "updated_at", + "aud", + "exp", + "iat", + "picture", + "sub", + "email", + "email_verified", + ], + "id_token_signing_alg_values_supported": [ + "RS256", + ], + "issuer": "https://id.twitch.tv/oauth2", + "jwks_uri": "https://id.twitch.tv/oauth2/keys", + "response_types_supported": [ + "id_token", + "code", + "token", + "code id_token", + "token id_token", + ], + "scopes_supported": [ + "openid", + ], + "subject_types_supported": [ + "public", + ], + "token_endpoint": "https://id.twitch.tv/oauth2/token", + "token_endpoint_auth_methods_supported": [ + "client_secret_post", + ], + "userinfo_endpoint": "https://id.twitch.tv/oauth2/userinfo", + } + ) + + +class TwitchOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.twitch.TwitchOAuth2" + user_data_url = "https://api.twitch.tv/helix/users" + expected_username = "test_user1" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + } + ) + user_data_body = json.dumps( + { + "data": [ + { + "id": "689563726", + "login": "test_user1", + "display_name": "test_user1", + "type": "", + "broadcaster_type": "", + "description": "", + "profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/foo.png", + "offline_image_url": "", + "view_count": 0, + "email": "example@reply.com", + "created_at": "2021-05-21T18:59:25Z", + "access_token": "hmkgz15x7j54jm63rpwfwhcnue6t4fxwv", + } + ] + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitter.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitter.py new file mode 100644 index 0000000000000000000000000000000000000000..5911ef5aa326489ec880131c59a6e42c7b2ddc40 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_twitter.py @@ -0,0 +1,251 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class TwitterOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.twitter.TwitterOAuth" + user_data_url = "https://api.twitter.com/1.1/account/" "verify_credentials.json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "follow_request_sent": False, + "profile_use_background_image": True, + "id": 10101010, + "description": "Foo bar baz qux", + "verified": False, + "entities": {"description": {"urls": []}}, + "profile_image_url_https": "https://twimg0-a.akamaihd.net/" + "profile_images/532018826/" + "n587119531_1939735_9305_normal.jpg", + "profile_sidebar_fill_color": "252429", + "profile_text_color": "666666", + "followers_count": 77, + "profile_sidebar_border_color": "181A1E", + "location": "Fooland", + "default_profile_image": False, + "listed_count": 4, + "status": { + "favorited": False, + "contributors": None, + "retweeted_status": { + "favorited": False, + "contributors": None, + "truncated": False, + "source": "web", + "text": '"Foo foo foo foo', + "created_at": "Fri Dec 21 18:12:00 +0000 2012", + "retweeted": True, + "in_reply_to_status_id": None, + "coordinates": None, + "id": 101010101010101010, + "entities": {"user_mentions": [], "hashtags": [], "urls": []}, + "in_reply_to_status_id_str": None, + "place": None, + "id_str": "101010101010101010", + "in_reply_to_screen_name": None, + "retweet_count": 8, + "geo": None, + "in_reply_to_user_id_str": None, + "in_reply_to_user_id": None, + }, + "truncated": False, + "source": "web", + "text": 'RT @foo: "Foo foo foo foo', + "created_at": "Fri Dec 21 18:24:10 +0000 2012", + "retweeted": True, + "in_reply_to_status_id": None, + "coordinates": None, + "id": 101010101010101010, + "entities": { + "user_mentions": [ + { + "indices": [3, 10], + "id": 10101010, + "screen_name": "foo", + "id_str": "10101010", + "name": "Foo", + } + ], + "hashtags": [], + "urls": [], + }, + "in_reply_to_status_id_str": None, + "place": None, + "id_str": "101010101010101010", + "in_reply_to_screen_name": None, + "retweet_count": 8, + "geo": None, + "in_reply_to_user_id_str": None, + "in_reply_to_user_id": None, + }, + "utc_offset": -10800, + "statuses_count": 191, + "profile_background_color": "1A1B1F", + "friends_count": 151, + "profile_background_image_url_https": "https://twimg0-a.akamaihd.net/" + "images/themes/theme9/bg.gif", + "profile_link_color": "2FC2EF", + "profile_image_url": "http://a0.twimg.com/profile_images/532018826/" + "n587119531_1939735_9305_normal.jpg", + "is_translator": False, + "geo_enabled": False, + "id_str": "74313638", + "profile_background_image_url": "http://a0.twimg.com/images/themes/" + "theme9/bg.gif", + "screen_name": "foobar", + "lang": "en", + "profile_background_tile": False, + "favourites_count": 2, + "name": "Foo", + "notifications": False, + "url": None, + "created_at": "Tue Sep 15 00:26:17 +0000 2009", + "contributors_enabled": False, + "time_zone": "Buenos Aires", + "protected": False, + "default_profile": False, + "following": False, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class TwitterOAuth1IncludeEmailTest(OAuth1Test): + backend_path = "social_core.backends.twitter.TwitterOAuth" + user_data_url = ( + "https://api.twitter.com/1.1/account/" + "verify_credentials.json?include_email=true" + ) + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "follow_request_sent": False, + "profile_use_background_image": True, + "id": 10101010, + "description": "Foo bar baz qux", + "verified": False, + "entities": {"description": {"urls": []}}, + "profile_image_url_https": "https://twimg0-a.akamaihd.net/" + "profile_images/532018826/" + "n587119531_1939735_9305_normal.jpg", + "profile_sidebar_fill_color": "252429", + "profile_text_color": "666666", + "followers_count": 77, + "profile_sidebar_border_color": "181A1E", + "location": "Fooland", + "default_profile_image": False, + "listed_count": 4, + "status": { + "favorited": False, + "contributors": None, + "retweeted_status": { + "favorited": False, + "contributors": None, + "truncated": False, + "source": "web", + "text": '"Foo foo foo foo', + "created_at": "Fri Dec 21 18:12:00 +0000 2012", + "retweeted": True, + "in_reply_to_status_id": None, + "coordinates": None, + "id": 101010101010101010, + "entities": {"user_mentions": [], "hashtags": [], "urls": []}, + "in_reply_to_status_id_str": None, + "place": None, + "id_str": "101010101010101010", + "in_reply_to_screen_name": None, + "retweet_count": 8, + "geo": None, + "in_reply_to_user_id_str": None, + "in_reply_to_user_id": None, + }, + "truncated": False, + "source": "web", + "text": 'RT @foo: "Foo foo foo foo', + "created_at": "Fri Dec 21 18:24:10 +0000 2012", + "retweeted": True, + "in_reply_to_status_id": None, + "coordinates": None, + "id": 101010101010101010, + "entities": { + "user_mentions": [ + { + "indices": [3, 10], + "id": 10101010, + "screen_name": "foo", + "id_str": "10101010", + "name": "Foo", + } + ], + "hashtags": [], + "urls": [], + }, + "in_reply_to_status_id_str": None, + "place": None, + "id_str": "101010101010101010", + "in_reply_to_screen_name": None, + "retweet_count": 8, + "geo": None, + "in_reply_to_user_id_str": None, + "in_reply_to_user_id": None, + }, + "utc_offset": -10800, + "statuses_count": 191, + "profile_background_color": "1A1B1F", + "friends_count": 151, + "profile_background_image_url_https": "https://twimg0-a.akamaihd.net/" + "images/themes/theme9/bg.gif", + "profile_link_color": "2FC2EF", + "profile_image_url": "http://a0.twimg.com/profile_images/532018826/" + "n587119531_1939735_9305_normal.jpg", + "is_translator": False, + "geo_enabled": False, + "id_str": "74313638", + "profile_background_image_url": "http://a0.twimg.com/images/themes/" + "theme9/bg.gif", + "screen_name": "foobar", + "lang": "en", + "profile_background_tile": False, + "favourites_count": 2, + "name": "Foo", + "notifications": False, + "url": None, + "created_at": "Tue Sep 15 00:26:17 +0000 2009", + "contributors_enabled": False, + "time_zone": "Buenos Aires", + "protected": False, + "default_profile": False, + "following": False, + "email": "foo@bar.bas", + } + ) + + def test_login(self): + user = self.do_login() + self.assertEqual(user.email, "foo@bar.bas") + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_uber.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_uber.py new file mode 100644 index 0000000000000000000000000000000000000000..524cfdc3b1689383a79cc3a1078b84211ed0e46f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_uber.py @@ -0,0 +1,36 @@ +import json + +from .oauth import OAuth2Test + + +class UberOAuth2Test(OAuth2Test): + user_data_url = "https://api.uber.com/v1/me" + backend_path = "social_core.backends.uber.UberOAuth2" + expected_username = "foo@bar.com" + + user_data_body = json.dumps( + { + "first_name": "Foo", + "last_name": "Bar", + "email": "foo@bar.com", + "picture": "https://", + "promo_code": "barfoo", + "uuid": "91d81273-45c2-4b57-8124-d0165f8240c0", + } + ) + + access_token_body = json.dumps( + { + "access_token": "EE1IDxytP04tJ767GbjH7ED9PpGmYvL", + "token_type": "Bearer", + "expires_in": 2592000, + "refresh_token": "Zx8fJ8qdSRRseIVlsGgtgQ4wnZBehr", + "scope": "profile history request", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_udata.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_udata.py new file mode 100644 index 0000000000000000000000000000000000000000..001750a291344fc1ea20ba436b925e16cb220434 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_udata.py @@ -0,0 +1,32 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth2Test + + +class DatagouvfrOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.udata.DatagouvfrOAuth2" + user_data_url = "https://www.data.gouv.fr/api/1/me/" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar", + "token_type": "bearer", + "first_name": "foobar", + "email": "foobar@example.com", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps({}) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_universe.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_universe.py new file mode 100644 index 0000000000000000000000000000000000000000..639775064418158ac14a33e80ec61e1d2c0d04bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_universe.py @@ -0,0 +1,29 @@ +import json + +from .oauth import OAuth2Test + + +class UniverseAuth2Test(OAuth2Test): + backend_path = "social_core.backends.universe.UniverseOAuth2" + user_data_url = "https://www.universe.com/api/v2/current_user" + expected_username = "scott+awesome@universe.com" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "current_user": { + "id": "123456", + "slug": "foo-bar", + "first_name": "Scott", + "last_name": "Vitale", + "created_at": "2019-01-08T15:49:42.514Z", + "updated_at": "2019-01-17T19:41:39.711Z", + "email": "scott+awesome@universe.com", + } + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_upwork.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_upwork.py new file mode 100644 index 0000000000000000000000000000000000000000..1e85514d7a4611eb0ba19854358102fc15010117 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_upwork.py @@ -0,0 +1,50 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class UpworkOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.upwork.UpworkOAuth" + user_data_url = "https://www.upwork.com/api/auth/v1/info.json" + expected_username = "10101010" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "info": { + "portrait_32_img": "", + "capacity": { + "buyer": "no", + "affiliate_manager": "no", + "provider": "yes", + }, + "company_url": "", + "has_agency": "1", + "portrait_50_img": "", + "portrait_100_img": "", + "location": {"city": "New York", "state": "", "country": "USA"}, + "ref": "9755314", + "profile_url": "https://www.upwork.com/users/~10101010", + }, + "auth_user": { + "timezone": "USA/New York", + "first_name": "Foo", + "last_name": "Bar", + "timezone_offset": "10000", + }, + "server_time": "1111111111", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_username.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_username.py new file mode 100644 index 0000000000000000000000000000000000000000..57194cbe4be7bab0e2edbd8b68a4ffd3b854c686 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_username.py @@ -0,0 +1,19 @@ +from .legacy import BaseLegacyTest + + +class UsernameTest(BaseLegacyTest): + backend_path = "social_core.backends.username.UsernameAuth" + expected_username = "foobar" + response_body = "username=foobar" + form = """ + <form method="post" action="{0}"> + <input name="username" type="text"> + <button>Submit</button> + </form> + """ + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..d03fbe3bf81024d0775d8872b269b2080ff36696 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_utils.py @@ -0,0 +1,57 @@ +import unittest as unittest + +from ...backends.github import GithubOAuth2 +from ...backends.utils import get_backend, load_backends +from ...exceptions import MissingBackend +from ..models import TestStorage +from ..strategy import TestStrategy + + +class BaseBackendUtilsTest(unittest.TestCase): + def setUp(self): + self.strategy = TestStrategy(storage=TestStorage) + + def tearDown(self): + self.strategy = None + + +class LoadBackendsTest(BaseBackendUtilsTest): + def test_load_backends(self): + loaded_backends = load_backends( + ( + "social_core.backends.github.GithubOAuth2", + "social_core.backends.facebook.FacebookOAuth2", + "social_core.backends.flickr.FlickrOAuth", + ), + force_load=True, + ) + keys = list(loaded_backends.keys()) + self.assertEqual(keys, ["github", "facebook", "flickr"]) + + backends = () + loaded_backends = load_backends(backends, force_load=True) + self.assertEqual(len(list(loaded_backends.keys())), 0) + + +class GetBackendTest(BaseBackendUtilsTest): + def test_get_backend(self): + backend = get_backend( + ( + "social_core.backends.github.GithubOAuth2", + "social_core.backends.facebook.FacebookOAuth2", + "social_core.backends.flickr.FlickrOAuth", + ), + "github", + ) + self.assertEqual(backend, GithubOAuth2) + + def test_get_missing_backend(self): + with self.assertRaisesRegex(MissingBackend, 'Missing backend "foobar" entry'): + get_backend( + ( + "social_core.backends.github.GithubOAuth2", + "social_core.backends.facebook.FacebookOAuth2", + "social_core.backends.flickr.FlickrOAuth", + ), + "foobar", + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vault.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vault.py new file mode 100644 index 0000000000000000000000000000000000000000..9c3c3e3851da40ada81e29819b6099cd7a50e2c1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vault.py @@ -0,0 +1,49 @@ +import json + +from httpretty import HTTPretty + +from .oauth import OAuth2Test +from .test_open_id_connect import OpenIdConnectTestMixin + +ROOT_URL = "https://vault.example.net:8200/" + + +class VaultOpenIdConnectTest(OpenIdConnectTestMixin, OAuth2Test): + backend_path = "social_core.backends.vault.VaultOpenIdConnect" + issuer = f"{ROOT_URL}v1/identity/oidc/provider/default" + openid_config_body = json.dumps( + { + "issuer": f"{ROOT_URL}v1/identity/oidc/provider/default", + "jwks_uri": f"{ROOT_URL}v1/identity/oidc/provider/default/.well-known/keys", + "authorization_endpoint": f"{ROOT_URL}ui/vault/identity/oidc/provider/default/authorize", + "token_endpoint": f"{ROOT_URL}v1/identity/oidc/provider/default/token", + "userinfo_endpoint": f"{ROOT_URL}v1/identity/oidc/provider/default/userinfo", + "request_uri_parameter_supported": False, + "grant_types_supported": ["authorization_code"], + "token_endpoint_auth_methods_supported": ["client_secret_basic"], + } + ) + + expected_username = "cartman" + + def extra_settings(self): + settings = super().extra_settings() + settings.update( + { + f"SOCIAL_AUTH_{self.name}_OIDC_ENDPOINT": f"{ROOT_URL}v1/identity/oidc/provider/default", + } + ) + return settings + + def pre_complete_callback(self, start_url): + super().pre_complete_callback(start_url) + HTTPretty.register_uri( + "GET", + uri=self.backend.userinfo_url(), + status=200, + body=json.dumps({"preferred_username": self.expected_username}), + content_type="text/json", + ) + + def test_everything_works(self): + self.do_login() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vk.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vk.py new file mode 100644 index 0000000000000000000000000000000000000000..f7bd9b7dccf988895ad905eeeb3811e0bcfc7640 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_vk.py @@ -0,0 +1,30 @@ +import json + +from .oauth import OAuth2Test + + +class VKOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.vk.VKOAuth2" + user_data_url = "https://api.vk.com/method/users.get" + expected_username = "durov" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "response": [ + { + "uid": "1", + "first_name": "Павел", + "last_name": "Дуров", + "screen_name": "durov", + "nickname": "", + "photo": r"http:\/\/cs7003.vk.me\/v7003815\/22a1\/xgG9fb-IJ3Y.jpg", + } + ] + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_wunderlist.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_wunderlist.py new file mode 100644 index 0000000000000000000000000000000000000000..c10216112b4008b7bd76ada8c986843699363713 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_wunderlist.py @@ -0,0 +1,29 @@ +import json + +from .oauth import OAuth2Test + + +class WunderlistOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.wunderlist.WunderlistOAuth2" + user_data_url = "https://a.wunderlist.com/api/v1/user" + expected_username = "12345" + access_token_body = json.dumps( + {"access_token": "foobar-token", "token_type": "foobar"} + ) + user_data_body = json.dumps( + { + "created_at": "2015-01-21T00:56:51.442Z", + "email": "foo@bar.com", + "id": 12345, + "name": "foobar", + "revision": 1, + "type": "user", + "updated_at": "2015-01-21T00:56:51.442Z", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_xing.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_xing.py new file mode 100644 index 0000000000000000000000000000000000000000..bb7dbee77c385c5ecd65f8cd320b8ba604c6b48a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_xing.py @@ -0,0 +1,178 @@ +import json +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class XingOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.xing.XingOAuth" + user_data_url = "https://api.xing.com/v1/users/me.json" + expected_username = "FooBar" + access_token_body = urlencode( + { + "access_token": "foobar", + "token_type": "bearer", + "user_id": "123456_abcdef", + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + user_data_body = json.dumps( + { + "users": [ + { + "id": "123456_abcdef", + "first_name": "Foo", + "last_name": "Bar", + "display_name": "Foo Bar", + "page_name": "Foo_Bar", + "permalink": "https://www.xing.com/profile/Foo_Bar", + "gender": "m", + "birth_date": {"day": 12, "month": 8, "year": 1963}, + "active_email": "foo@bar.com", + "time_zone": {"name": "Europe/Copenhagen", "utc_offset": 2.0}, + "premium_services": ["SEARCH", "PRIVATEMESSAGES"], + "badges": ["PREMIUM", "MODERATOR"], + "wants": "Nothing", + "haves": "Skills", + "interests": "Foo Foo", + "organisation_member": "ACM, GI", + "languages": { + "de": "NATIVE", + "en": "FLUENT", + "fr": None, + "zh": "BASIC", + }, + "private_address": { + "city": "Foo", + "country": "DE", + "zip_code": "20357", + "street": "Bar", + "phone": "12|34|1234560", + "fax": "||", + "province": "Foo", + "email": "foo@bar.com", + "mobile_phone": "12|3456|1234567", + }, + "business_address": { + "city": "Foo", + "country": "DE", + "zip_code": "20357", + "street": "Bar", + "phone": "12|34|1234569", + "fax": "12|34|1234561", + "province": "Foo", + "email": "foo@bar.com", + "mobile_phone": "12|345|12345678", + }, + "web_profiles": { + "qype": ["http://qype.de/users/foo"], + "google_plus": ["http://plus.google.com/foo"], + "blog": ["http://blog.example.org"], + "homepage": ["http://example.org", "http://other-example.org"], + }, + "instant_messaging_accounts": { + "skype": "foobar", + "googletalk": "foobar", + }, + "professional_experience": { + "primary_company": { + "name": "XING AG", + "title": "Softwareentwickler", + "company_size": "201-500", + "tag": None, + "url": "http://www.xing.com", + "career_level": "PROFESSIONAL_EXPERIENCED", + "begin_date": "2010-01", + "description": None, + "end_date": None, + "industry": "AEROSPACE", + }, + "non_primary_companies": [ + { + "name": "Ninja Ltd.", + "title": "DevOps", + "company_size": None, + "tag": "NINJA", + "url": "http://www.ninja-ltd.co.uk", + "career_level": None, + "begin_date": "2009-04", + "description": None, + "end_date": "2010-07", + "industry": "ALTERNATIVE_MEDICINE", + }, + { + "name": None, + "title": "Wiss. Mitarbeiter", + "company_size": None, + "tag": "OFFIS", + "url": "http://www.uni.de", + "career_level": None, + "begin_date": "2007", + "description": None, + "end_date": "2008", + "industry": "APPAREL_AND_FASHION", + }, + { + "name": None, + "title": "TEST NINJA", + "company_size": "201-500", + "tag": "TESTCOMPANY", + "url": None, + "career_level": "ENTRY_LEVEL", + "begin_date": "1998-12", + "description": None, + "end_date": "1999-05", + "industry": "ARTS_AND_CRAFTS", + }, + ], + "awards": [ + { + "name": "Awesome Dude Of The Year", + "date_awarded": 2007, + "url": None, + } + ], + }, + "educational_background": { + "schools": [ + { + "name": "Foo University", + "degree": "MSc CE/CS", + "notes": None, + "subject": None, + "begin_date": "1998-08", + "end_date": "2005-02", + } + ], + "qualifications": ["TOEFLS", "PADI AOWD"], + }, + "photo_urls": { + "large": "http://www.xing.com/img/users/e/3/d/" + "f94ef165a.123456,1.140x185.jpg", + "mini_thumb": "http://www.xing.com/img/users/e/3/d/" + "f94ef165a.123456,1.18x24.jpg", + "thumb": "http://www.xing.com/img/users/e/3/d/" + "f94ef165a.123456,1.30x40.jpg", + "medium_thumb": "http://www.xing.com/img/users/e/3/d/" + "f94ef165a.123456,1.57x75.jpg", + "maxi_thumb": "http://www.xing.com/img/users/e/3/d/" + "f94ef165a.123456,1.70x93.jpg", + }, + } + ] + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yahoo.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yahoo.py new file mode 100644 index 0000000000000000000000000000000000000000..185a727f33f2ec9c9d17bf4047eae4269c0ea569 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yahoo.py @@ -0,0 +1,84 @@ +import json +from urllib.parse import urlencode + +import requests +from httpretty import HTTPretty + +from .oauth import OAuth1Test + + +class YahooOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.yahoo.YahooOAuth" + user_data_url = "https://social.yahooapis.com/v1/user/a-guid/profile?" "format=json" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + guid_body = json.dumps( + {"guid": {"uri": "https://social.yahooapis.com/v1/me/guid", "value": "a-guid"}} + ) + user_data_body = json.dumps( + { + "profile": { + "bdRestricted": True, + "memberSince": "2007-12-11T14:40:30Z", + "image": { + "width": 192, + "imageUrl": "http://l.yimg.com/dh/ap/social/profile/" + "profile_b192.png", + "size": "192x192", + "height": 192, + }, + "created": "2013-03-18T04:15:08Z", + "uri": "https://social.yahooapis.com/v1/user/a-guid/profile", + "isConnected": False, + "profileUrl": "http://profile.yahoo.com/a-guid", + "guid": "a-guid", + "nickname": "foobar", + "emails": [ + { + "handle": "foobar@yahoo.com", + "id": 1, + "primary": True, + "type": "HOME", + }, + { + "handle": "foobar@email.com", + "id": 2, + "type": "HOME", + }, + ], + } + } + ) + + def test_login(self): + HTTPretty.register_uri( + HTTPretty.GET, + "https://social.yahooapis.com/v1/me/guid?format=json", + status=200, + body=self.guid_body, + ) + self.do_login() + + def test_partial_pipeline(self): + HTTPretty.register_uri( + HTTPretty.GET, + "https://social.yahooapis.com/v1/me/guid?format=json", + status=200, + body=self.guid_body, + ) + self.do_partial_pipeline() + + def test_get_user_details(self): + HTTPretty.register_uri( + HTTPretty.GET, self.user_data_url, status=200, body=self.user_data_body + ) + response = requests.get(self.user_data_url) + user_details = self.backend.get_user_details(response.json()["profile"]) + self.assertEqual(user_details["email"], "foobar@yahoo.com") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yammer.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yammer.py new file mode 100644 index 0000000000000000000000000000000000000000..481b133be81928b9770a7acb5ca8c1cb4eb8afc1 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yammer.py @@ -0,0 +1,105 @@ +import json + +from .oauth import OAuth2Test + + +class YammerOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.yammer.YammerOAuth2" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": { + "user_id": 1010101010, + "view_groups": True, + "modify_messages": True, + "network_id": 101010, + "created_at": "2013/03/17 16:39:56 +0000", + "view_members": True, + "authorized_at": "2013/03/17 16:39:56 +0000", + "view_subscriptions": True, + "view_messages": True, + "modify_subscriptions": True, + "token": "foobar", + "expires_at": None, + "network_permalink": "foobar.com", + "view_tags": True, + "network_name": "foobar.com", + }, + "user": { + "last_name": "Bar", + "web_url": "https://www.yammer.com/foobar/users/foobar", + "expertise": None, + "full_name": "Foo Bar", + "timezone": "Pacific Time (US & Canada)", + "mugshot_url": "https://mug0.assets-yammer.com/mugshot/images/" + "48x48/no_photo.png", + "guid": None, + "network_name": "foobar", + "id": 1010101010, + "previous_companies": [], + "first_name": "Foo", + "stats": {"following": 0, "followers": 0, "updates": 1}, + "hire_date": None, + "state": "active", + "location": None, + "department": "Software Development", + "type": "user", + "show_ask_for_photo": True, + "job_title": "Software Developer", + "interests": None, + "kids_names": None, + "activated_at": "2013/03/17 16:27:50 +0000", + "verified_admin": "false", + "can_broadcast": "false", + "schools": [], + "admin": "false", + "network_domains": ["foobar.com"], + "name": "foobar", + "external_urls": [], + "url": "https://www.yammer.com/api/v1/users/1010101010", + "settings": {"xdr_proxy": "https://xdrproxy.yammer.com"}, + "summary": None, + "network_id": 101010, + "contact": { + "phone_numbers": [], + "im": {"username": "", "provider": ""}, + "email_addresses": [{"type": "primary", "address": "foo@bar.com"}], + "has_fake_email": False, + }, + "birth_date": "", + "mugshot_url_template": "https://mug0.assets-yammer.com/mugshot/" + "images/{width}x{height}/no_photo.png", + "significant_other": None, + }, + "network": { + "show_upgrade_banner": False, + "header_text_color": "#FFFFFF", + "is_org_chart_enabled": True, + "name": "foobar.com", + "is_group_enabled": True, + "header_background_color": "#396B9A", + "created_at": "2012/12/26 16:52:35 +0000", + "profile_fields_config": { + "enable_work_phone": True, + "enable_mobile_phone": True, + "enable_job_title": True, + }, + "permalink": "foobar.com", + "paid": False, + "id": 101010, + "is_chat_enabled": True, + "web_url": "https://www.yammer.com/foobar.com", + "moderated": False, + "community": False, + "type": "network", + "navigation_background_color": "#38699F", + "navigation_text_color": "#FFFFFF", + }, + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yandex.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yandex.py new file mode 100644 index 0000000000000000000000000000000000000000..5a879916b8d6cd70200fd15bf1cf533b35cad57b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_yandex.py @@ -0,0 +1,54 @@ +import json + +from .oauth import OAuth2Test + + +class YandexOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.yandex.YandexOAuth2" + user_data_url = "https://login.yandex.ru/info" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "display_name": "foobar", + "real_name": "Foo Bar", + "sex": None, + "id": "101010101", + "default_email": "foobar@yandex.com", + "emails": ["foobar@yandex.com"], + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + +class YandexOAuth2TestEmptyEmail(OAuth2Test): + """ + When user log in to yandex service with social network account (e.g. + vk.com), they `default_email` could be empty. + """ + + backend_path = "social_core.backends.yandex.YandexOAuth2" + user_data_url = "https://login.yandex.ru/info" + expected_username = "foobar" + access_token_body = json.dumps({"access_token": "foobar", "token_type": "bearer"}) + user_data_body = json.dumps( + { + "display_name": "foobar", + "real_name": "Foo Bar", + "sex": None, + "id": "101010101", + "default_email": "", + "emails": [], + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zoom.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zoom.py new file mode 100644 index 0000000000000000000000000000000000000000..ece905337a517e59eebe0a07474bbc1fa251b55f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zoom.py @@ -0,0 +1,68 @@ +import json + +from .oauth import OAuth2Test + + +class ZoomOAuth2Test(OAuth2Test): + backend_path = "social_core.backends.zoom.ZoomOAuth2" + user_data_url = "https://api.zoom.us/v2/users/me" + expected_username = "foobar" + access_token_body = json.dumps( + { + "access_token": "foobar-token", + "token_type": "bearer", + "refresh_token": "foobar-refresh-token", + "expires_in": 3599, + "scope": "identity", + } + ) + user_data_body = json.dumps( + { + "id": "foobar", + "first_name": "Foo", + "last_name": "Bar", + "email": "foobar@email.com", + "type": 2, + "role_name": "Foobar", + "pmi": 1234567890, + "use_pmi": False, + "vanity_url": "https://foobar.zoom.us/my/foobar", + "personal_meeting_url": "https://foobar.zoom.us/j/1234567890", + "timezone": "America/Denver", + "verified": 1, + "dept": "", + "created_at": "2019-04-05T15:24:32Z", + "last_login_time": "2019-12-16T18:02:48Z", + "last_client_version": "version", + "pic_url": "https://foobar.zoom.us/p/123456789", + "host_key": "123456", + "jid": "foobar@xmpp.zoom.us", + "group_ids": [], + "im_group_ids": ["foobar-group-id"], + "account_id": "foobar-account-id", + "language": "en-US", + "phone_country": "US", + "phone_number": "+1 1234567891", + "status": "active", + } + ) + refresh_token_body = json.dumps( + { + "access_token": "foobar-new-token", + "token_type": "bearer", + "refresh_token": "foobar-new-refresh-token", + "expires_in": 3599, + "scope": "identity", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() + + def test_refresh_token(self): + user, social = self.do_refresh_token() + self.assertEqual(user.username, self.expected_username) + self.assertEqual(social.extra_data["access_token"], "foobar-new-token") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zotero.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zotero.py new file mode 100644 index 0000000000000000000000000000000000000000..e6b5cd0e71238c94b9aca86ee7ff40b0cf12cbc4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/backends/test_zotero.py @@ -0,0 +1,29 @@ +from urllib.parse import urlencode + +from .oauth import OAuth1Test + + +class ZoteroOAuth1Test(OAuth1Test): + backend_path = "social_core.backends.zotero.ZoteroOAuth" + expected_username = "FooBar" + access_token_body = urlencode( + { + "oauth_token": "foobar", + "oauth_token_secret": "rodgsNDK4hLJU1504Atk131G", + "userID": "123456_abcdef", + "username": "FooBar", + } + ) + request_token_body = urlencode( + { + "oauth_token_secret": "foobar-secret", + "oauth_token": "foobar", + "oauth_callback_confirmed": "true", + } + ) + + def test_login(self): + self.do_login() + + def test_partial_pipeline(self): + self.do_partial_pipeline() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/models.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/models.py new file mode 100644 index 0000000000000000000000000000000000000000..bf6111fceb5cd11071f6f197d994dc1d494d7369 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/models.py @@ -0,0 +1,246 @@ +import base64 + +from ..storage import ( + AssociationMixin, + BaseStorage, + CodeMixin, + NonceMixin, + PartialMixin, + UserMixin, +) + + +class BaseModel: + @classmethod + def next_id(cls): + cls.NEXT_ID += 1 + return cls.NEXT_ID - 1 + + @classmethod + def get(cls, key): + return cls.cache.get(key) + + @classmethod + def reset_cache(cls): + cls.cache = {} + + +class User(BaseModel): + NEXT_ID = 1 + cache = {} + _is_active = True + + def __init__(self, username, email=None, **extra_user_fields): + self.id = User.next_id() + self.username = username + self.email = email + self.first_name = None + self.password = None + self.slug = None + self.social = [] + self.extra_data = {} + self.extra_user_fields = extra_user_fields + self.save() + + def is_active(self): + return self._is_active + + @classmethod + def set_active(cls, is_active=True): + cls._is_active = is_active + + def set_password(self, password): + self.password = password + + def save(self): + User.cache[self.username] = self + + +class TestUserSocialAuth(UserMixin, BaseModel): + NEXT_ID = 1 + cache = {} + cache_by_uid = {} + + def __init__(self, user, provider, uid, extra_data=None): + self.id = TestUserSocialAuth.next_id() + self.user = user + self.provider = provider + self.uid = uid + self.extra_data = extra_data or {} + self.user.social.append(self) + TestUserSocialAuth.cache_by_uid[uid] = self + + def save(self): + pass + + @classmethod + def reset_cache(cls): + cls.cache = {} + cls.cache_by_uid = {} + + @classmethod + def changed(cls, user): + pass + + @classmethod + def get_username(cls, user): + return user.username + + @classmethod + def user_model(cls): + return User + + @classmethod + def username_max_length(cls): + return 1024 + + @classmethod + def allowed_to_disconnect(cls, user, backend_name, association_id=None): + return user.password or len(user.social) > 1 + + @classmethod + def disconnect(cls, entry): + cls.cache.pop(entry.id, None) + entry.user.social = [s for s in entry.user.social if entry != s] + + @classmethod + def user_exists(cls, username): + return User.cache.get(username) is not None + + @classmethod + def create_user(cls, username, email=None, **extra_user_fields): + return User(username=username, email=email, **extra_user_fields) + + @classmethod + def get_user(cls, pk): + for username, user in User.cache.items(): + if user.id == pk: + return user + + @classmethod + def get_social_auth(cls, provider, uid): + social_user = cls.cache_by_uid.get(uid) + if social_user and social_user.provider == provider: + return social_user + + @classmethod + def get_social_auth_for_user(cls, user, provider=None, id=None): + return [ + usa + for usa in user.social + if provider in (None, usa.provider) and id in (None, usa.id) + ] + + @classmethod + def create_social_auth(cls, user, uid, provider): + return cls(user=user, provider=provider, uid=uid) + + @classmethod + def get_users_by_email(cls, email): + return [user for user in User.cache.values() if user.email == email] + + +class TestNonce(NonceMixin, BaseModel): + NEXT_ID = 1 + cache = {} + + def __init__(self, server_url, timestamp, salt): + self.id = TestNonce.next_id() + self.server_url = server_url + self.timestamp = timestamp + self.salt = salt + + @classmethod + def use(cls, server_url, timestamp, salt): + nonce = TestNonce(server_url, timestamp, salt) + TestNonce.cache[server_url] = nonce + return nonce + + @classmethod + def get(cls, server_url, salt): + return TestNonce.cache[server_url] + + @classmethod + def delete(cls, nonce): + server_url = nonce.server_url + del TestNonce.cache[server_url] + + +class TestAssociation(AssociationMixin, BaseModel): + NEXT_ID = 1 + cache = {} + + def __init__(self, server_url, handle): + self.id = TestAssociation.next_id() + self.server_url = server_url + self.handle = handle + + def save(self): + TestAssociation.cache[(self.server_url, self.handle)] = self + + @classmethod + def store(cls, server_url, association): + assoc = TestAssociation.cache.get((server_url, association.handle)) + if assoc is None: + assoc = TestAssociation(server_url=server_url, handle=association.handle) + assoc.secret = base64.encodebytes(association.secret) + assoc.issued = association.issued + assoc.lifetime = association.lifetime + assoc.assoc_type = association.assoc_type + assoc.save() + + @classmethod + def get(cls, server_url=None, handle=None): + result = [] + for assoc in TestAssociation.cache.values(): + if server_url and assoc.server_url != server_url: + continue + if handle and assoc.handle != handle: + continue + result.append(assoc) + return result + + @classmethod + def remove(cls, ids_to_delete): + assoc = filter(lambda a: a.id in ids_to_delete, TestAssociation.cache.values()) + for a in list(assoc): + TestAssociation.cache.pop((a.server_url, a.handle), None) + + +class TestCode(CodeMixin, BaseModel): + NEXT_ID = 1 + cache = {} + + @classmethod + def get_code(cls, code): + for c in cls.cache.values(): + if c.code == code: + return c + + +class TestPartial(PartialMixin, BaseModel): + NEXT_ID = 1 + cache = {} + + def save(self): + TestPartial.cache[self.token] = self + + @classmethod + def load(cls, token): + return cls.cache.get(token) + + @classmethod + def destroy(cls, token): + cls.cache.pop(token) + + +class TestStorage(BaseStorage): + user = TestUserSocialAuth + nonce = TestNonce + association = TestAssociation + code = TestCode + partial = TestPartial + + @classmethod + def is_integrity_error(cls, exception): + pass diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/pipeline.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..7d8d8126ade5f55177be832ac4ad46cc4b431622 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/pipeline.py @@ -0,0 +1,45 @@ +from ..pipeline.partial import partial + + +@partial +def ask_for_password(strategy, *args, **kwargs): + if strategy.session_get("password"): + return {"password": strategy.session_get("password")} + else: + return strategy.redirect(strategy.build_absolute_uri("/password")) + + +@partial +def ask_for_slug(strategy, *args, **kwargs): + if strategy.session_get("slug"): + return {"slug": strategy.session_get("slug")} + else: + return strategy.redirect(strategy.build_absolute_uri("/slug")) + + +def set_password(strategy, user, *args, **kwargs): + user.set_password(kwargs["password"]) + + +def set_slug(strategy, user, *args, **kwargs): + user.slug = kwargs["slug"] + + +def remove_user(strategy, user, *args, **kwargs): + return {"user": None} + + +@partial +def set_user_from_kwargs(strategy, *args, **kwargs): + if strategy.session_get("attribute"): + kwargs["user"].id + else: + return strategy.redirect(strategy.build_absolute_uri("/attribute")) + + +@partial +def set_user_from_args(strategy, user, *args, **kwargs): + if strategy.session_get("attribute"): + user.id + else: + return strategy.redirect(strategy.build_absolute_uri("/attribute")) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/requirements.txt b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c21a1b7e5d3a2b3313510a5c6791c1cc717aaf91 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/requirements.txt @@ -0,0 +1,4 @@ +pytest>=4.5 +httpretty>=0.9.6 +coverage>=3.6 +pytest-cov>=2.7.1 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/strategy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/strategy.py new file mode 100644 index 0000000000000000000000000000000000000000..4ee4543df5ee438653d2d87e083d428384ab4623 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/strategy.py @@ -0,0 +1,123 @@ +from ..strategy import BaseStrategy, BaseTemplateStrategy + +TEST_URI = "http://myapp.com" +TEST_HOST = "myapp.com" + + +class Redirect: + def __init__(self, url): + self.url = url + + +class TestTemplateStrategy(BaseTemplateStrategy): + def render_template(self, tpl, context): + return tpl + + def render_string(self, html, context): + return html + + +class TestStrategy(BaseStrategy): + DEFAULT_TEMPLATE_STRATEGY = TestTemplateStrategy + + def __init__(self, storage, tpl=None): + self._request_data = {} + self._settings = {} + self._session = {} + super().__init__(storage, tpl) + + def redirect(self, url): + return Redirect(url) + + def get_setting(self, name): + """Return value for given setting name""" + return self._settings[name] + + def html(self, content): + """Return HTTP response with given content""" + return content + + def render_html(self, tpl=None, html=None, context=None): + """Render given template or raw html with given context""" + return tpl or html + + def request_data(self, merge=True): + """Return current request data (POST or GET)""" + return self._request_data + + def request_host(self): + """Return current host value""" + return TEST_HOST + + def request_is_secure(self): + """Is the request using HTTPS?""" + return False + + def request_path(self): + """path of the current request""" + return "" + + def request_port(self): + """Port in use for this request""" + return 80 + + def request_get(self): + """Request GET data""" + return self._request_data.copy() + + def request_post(self): + """Request POST data""" + return self._request_data.copy() + + def session_get(self, name, default=None): + """Return session value for given key""" + return self._session.get(name, default) + + def session_set(self, name, value): + """Set session value for given key""" + self._session[name] = value + + def session_pop(self, name): + """Pop session value for given key""" + return self._session.pop(name, None) + + def build_absolute_uri(self, path=None): + """Build absolute URI with given (optional) path""" + path = path or "" + if path.startswith("http://") or path.startswith("https://"): + return path + return TEST_URI + path + + def set_settings(self, values): + self._settings.update(values) + + def set_request_data(self, values, backend): + self._request_data.update(values) + backend.data = self._request_data + + def remove_from_request_data(self, name): + self._request_data.pop(name, None) + + def authenticate(self, *args, **kwargs): + user = super().authenticate(*args, **kwargs) + if isinstance(user, self.storage.user.user_model()): + self.session_set("username", user.username) + return user + + def get_pipeline(self, backend=None): + return self.setting( + "PIPELINE", + ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.auth_allowed", + "social_core.pipeline.social_auth.social_user", + "social_core.pipeline.user.get_username", + "social_core.pipeline.social_auth.associate_by_email", + "social_core.pipeline.user.create_user", + "social_core.pipeline.social_auth.associate_user", + "social_core.pipeline.social_auth.load_extra_data", + "social_core.pipeline.user.user_details", + ), + backend, + ) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_exceptions.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..5ed5811bea31e8319769cbaf8552e205eade2597 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_exceptions.py @@ -0,0 +1,124 @@ +import unittest + +from ..exceptions import ( + AuthAlreadyAssociated, + AuthCanceled, + AuthException, + AuthFailed, + AuthForbidden, + AuthMissingParameter, + AuthStateForbidden, + AuthStateMissing, + AuthTokenError, + AuthTokenRevoked, + AuthUnknownError, + AuthUnreachableProvider, + InvalidEmail, + MissingBackend, + NotAllowedToDisconnect, + SocialAuthBaseException, + WrongBackend, +) + + +class BaseExceptionTestCase(unittest.TestCase): + exception = None + expected_message = "" + + def test_exception_message(self): + if self.exception is None and self.expected_message == "": + return + try: + raise self.exception + except SocialAuthBaseException as err: + self.assertEqual(str(err), self.expected_message) + + +class WrongBackendTest(BaseExceptionTestCase): + exception = WrongBackend("foobar") + expected_message = 'Incorrect authentication service "foobar"' + + +class AuthFailedTest(BaseExceptionTestCase): + exception = AuthFailed("foobar", "wrong_user") + expected_message = "Authentication failed: wrong_user" + + +class AuthFailedDeniedTest(BaseExceptionTestCase): + exception = AuthFailed("foobar", "access_denied") + expected_message = "Authentication process was canceled" + + +class AuthTokenErrorTest(BaseExceptionTestCase): + exception = AuthTokenError("foobar", "Incorrect tokens") + expected_message = "Token error: Incorrect tokens" + + +class AuthMissingParameterTest(BaseExceptionTestCase): + exception = AuthMissingParameter("foobar", "username") + expected_message = "Missing needed parameter username" + + +class AuthStateMissingTest(BaseExceptionTestCase): + exception = AuthStateMissing("foobar") + expected_message = "Session value state missing." + + +class NotAllowedToDisconnectTest(BaseExceptionTestCase): + exception = NotAllowedToDisconnect() + expected_message = "This account is not allowed to be disconnected." + + +class AuthExceptionTest(BaseExceptionTestCase): + exception = AuthException("foobar", "message") + expected_message = "message" + + +class AuthCanceledTest(BaseExceptionTestCase): + exception = AuthCanceled("foobar") + expected_message = "Authentication process canceled" + + +class AuthCanceledWithExtraMessageTest(BaseExceptionTestCase): + exception = AuthCanceled("foobar", "error_message") + expected_message = "Authentication process canceled: error_message" + + +class AuthUnknownErrorTest(BaseExceptionTestCase): + exception = AuthUnknownError("foobar", "some error") + expected_message = "An unknown error happened while " "authenticating some error" + + +class AuthStateForbiddenTest(BaseExceptionTestCase): + exception = AuthStateForbidden("foobar") + expected_message = "Wrong state parameter given." + + +class AuthAlreadyAssociatedTest(BaseExceptionTestCase): + exception = AuthAlreadyAssociated("foobar") + expected_message = "This account is already in use." + + +class AuthTokenRevokedTest(BaseExceptionTestCase): + exception = AuthTokenRevoked("foobar") + expected_message = "User revoke access to the token" + + +class AuthForbiddenTest(BaseExceptionTestCase): + exception = AuthForbidden("foobar") + expected_message = "Your credentials aren't allowed" + + +class AuthUnreachableProviderTest(BaseExceptionTestCase): + exception = AuthUnreachableProvider("foobar") + expected_message = "The authentication provider could not be reached" + + +class InvalidEmailTest(BaseExceptionTestCase): + exception = InvalidEmail("foobar") + expected_message = "Email couldn't be validated" + + +class MissingBackendTest(BaseExceptionTestCase): + exception = MissingBackend("backend") + expected_message = 'Missing backend "backend" entry' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_partial.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_partial.py new file mode 100644 index 0000000000000000000000000000000000000000..1c4891c09eb83aa72c19d3cdb82726148f8325b6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_partial.py @@ -0,0 +1,128 @@ +import unittest +from unittest.mock import Mock, patch + +from ..pipeline.partial import partial, partial_step +from ..utils import PARTIAL_TOKEN_SESSION_NAME + + +class PartialDecoratorTestCase(unittest.TestCase): + def setUp(self): + super().setUp() + self.mock_current_partial_token = Mock() + self.mock_current_partial = Mock(token=self.mock_current_partial_token) + + self.mock_strategy = Mock() + self.mock_backend = Mock() + self.mock_pipeline_index = Mock() + self.mock_partial_store = Mock() + self.mock_strategy.storage.partial.store = self.mock_partial_store + + self.mock_session_set = Mock() + self.mock_strategy.session_set = self.mock_session_set + + def test_save_to_session(self): + # GIVEN + expected_response = Mock() + + @partial_step(save_to_session=True) + def decorated_func(*args, **kwargs): + return expected_response + + # WHEN + with patch( + "social_core.pipeline.partial.partial_prepare", + return_value=self.mock_current_partial, + ): + response = decorated_func( + self.mock_strategy, self.mock_backend, self.mock_pipeline_index + ) + + # THEN + self.assertEqual(expected_response, response) + + self.assertEqual(1, self.mock_partial_store.call_count) + self.assertEqual( + (self.mock_current_partial,), self.mock_partial_store.call_args[0] + ) + + self.assertEqual(1, self.mock_session_set.call_count) + self.assertEqual( + (PARTIAL_TOKEN_SESSION_NAME, self.mock_current_partial_token), + self.mock_session_set.call_args[0], + ) + + def test_not_to_save_to_session(self): + # GIVEN + expected_response = Mock() + + @partial_step(save_to_session=False) + def decorated_func(*args, **kwargs): + return expected_response + + # WHEN + with patch( + "social_core.pipeline.partial.partial_prepare", + return_value=self.mock_current_partial, + ): + response = decorated_func( + self.mock_strategy, self.mock_backend, self.mock_pipeline_index + ) + + # THEN + self.assertEqual(expected_response, response) + + self.assertEqual(1, self.mock_partial_store.call_count) + self.assertEqual( + (self.mock_current_partial,), self.mock_partial_store.call_args[0] + ) + + self.assertEqual(0, self.mock_session_set.call_count) + + def test_save_to_session_by_backward_compatible_decorator(self): + # GIVEN + expected_response = Mock() + + @partial + def decorated_func(*args, **kwargs): + return expected_response + + # WHEN + with patch( + "social_core.pipeline.partial.partial_prepare", + return_value=self.mock_current_partial, + ): + response = decorated_func( + self.mock_strategy, self.mock_backend, self.mock_pipeline_index + ) + + # THEN + self.assertEqual(expected_response, response) + + self.assertEqual(1, self.mock_partial_store.call_count) + self.assertEqual( + (self.mock_current_partial,), self.mock_partial_store.call_args[0] + ) + + self.assertEqual(1, self.mock_session_set.call_count) + self.assertEqual( + (PARTIAL_TOKEN_SESSION_NAME, self.mock_current_partial_token), + self.mock_session_set.call_args[0], + ) + + def test_not_to_save_to_session_when_the_response_is_a_dict(self): + # GIVEN + expected_response = {"test_key": "test_value"} + + @partial_step(save_to_session=True) + def decorated_func(*args, **kwargs): + return expected_response + + # WHEN + response = decorated_func( + self.mock_strategy, self.mock_backend, self.mock_pipeline_index + ) + + # THEN + self.assertEqual(expected_response, response) + self.assertEqual(0, self.mock_partial_store.call_count) + self.assertEqual(0, self.mock_session_set.call_count) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_pipeline.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..f36b2d36254e784ee9bcb7b94893cbb48b750f29 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_pipeline.py @@ -0,0 +1,268 @@ +import json + +from ..exceptions import AuthException +from ..pipeline.user import user_details +from ..utils import PARTIAL_TOKEN_SESSION_NAME +from .actions.actions import BaseActionTest +from .models import TestStorage, TestUserSocialAuth, User +from .strategy import TestStrategy + + +class IntegrityError(Exception): + pass + + +class UnknownError(Exception): + pass + + +class IntegrityErrorUserSocialAuth(TestUserSocialAuth): + @classmethod + def create_social_auth(cls, user, uid, provider): + raise IntegrityError() + + @classmethod + def get_social_auth(cls, provider, uid): + if not hasattr(cls, "_called_times"): + cls._called_times = 0 + cls._called_times += 1 + if cls._called_times == 2: + user = list(User.cache.values())[0] + return IntegrityErrorUserSocialAuth(user, provider, uid) + else: + return super().get_social_auth(provider, uid) + + +class IntegrityErrorStorage(TestStorage): + user = IntegrityErrorUserSocialAuth + + @classmethod + def is_integrity_error(cls, exception): + """Check if given exception flags an integrity error in the DB""" + return isinstance(exception, IntegrityError) + + +class UnknownErrorUserSocialAuth(TestUserSocialAuth): + @classmethod + def create_social_auth(cls, user, uid, provider): + raise UnknownError() + + +class UnknownErrorStorage(IntegrityErrorStorage): + user = UnknownErrorUserSocialAuth + + +class IntegrityErrorOnLoginTest(BaseActionTest): + def setUp(self): + self.strategy = TestStrategy(IntegrityErrorStorage) + super().setUp() + + def test_integrity_error(self): + self.do_login() + + +class UnknownErrorOnLoginTest(BaseActionTest): + def setUp(self): + self.strategy = TestStrategy(UnknownErrorStorage) + super().setUp() + + def test_unknown_error(self): + with self.assertRaises(UnknownError): + self.do_login() + + +class EmailAsUsernameTest(BaseActionTest): + expected_username = "foo@bar.com" + + def test_email_as_username(self): + self.strategy.set_settings({"SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL": True}) + self.do_login() + + +class RandomUsernameTest(BaseActionTest): + user_data_body = json.dumps( + { + "id": 1, + "avatar_url": "https://github.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_random_username(self): + self.do_login(after_complete_checks=False) + + +class SluggedUsernameTest(BaseActionTest): + expected_username = "foo-bar" + user_data_body = json.dumps( + { + "login": "Foo Bar", + "id": 1, + "avatar_url": "https://github.com/images/error/foobar_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/foobar", + "name": "monalisa foobar", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "foo@bar.com", + "hireable": False, + "bio": "There once was...", + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/foobar", + "created_at": "2008-01-14T04:33:35Z", + "type": "User", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "plan": { + "name": "Medium", + "space": 400, + "collaborators": 10, + "private_repos": 20, + }, + } + ) + + def test_random_username(self): + self.strategy.set_settings( + { + "SOCIAL_AUTH_CLEAN_USERNAMES": False, + "SOCIAL_AUTH_SLUGIFY_USERNAMES": True, + } + ) + self.do_login() + + +class RepeatedUsernameTest(BaseActionTest): + def test_random_username(self): + User(username="foobar") + self.do_login(after_complete_checks=False) + self.assertTrue(self.strategy.session_get("username").startswith("foobar")) + + +class AssociateByEmailTest(BaseActionTest): + def test_multiple_accounts_with_same_email(self): + user = User(username="foobar1") + user.email = "foo@bar.com" + self.do_login(after_complete_checks=False) + self.assertTrue(self.strategy.session_get("username").startswith("foobar")) + + +class MultipleAccountsWithSameEmailTest(BaseActionTest): + def test_multiple_accounts_with_same_email(self): + user1 = User(username="foobar1") + user2 = User(username="foobar2") + user1.email = "foo@bar.com" + user2.email = "foo@bar.com" + with self.assertRaises(AuthException): + self.do_login(after_complete_checks=False) + + +class UserPersistsInPartialPipeline(BaseActionTest): + def test_user_persists_in_partial_pipeline_kwargs(self): + user = User(username="foobar1") + user.email = "foo@bar.com" + + self.strategy.set_settings( + { + "SOCIAL_AUTH_PIPELINE": ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.associate_by_email", + "social_core.tests.pipeline.set_user_from_kwargs", + ) + } + ) + + self.do_login(after_complete_checks=False) + + # Handle the partial pipeline + self.strategy.session_set("attribute", "testing") + token = self.strategy.session_pop(PARTIAL_TOKEN_SESSION_NAME) + partial = self.strategy.partial_load(token) + self.backend.continue_pipeline(partial) + + def test_user_persists_in_partial_pipeline(self): + user = User(username="foobar1") + user.email = "foo@bar.com" + + self.strategy.set_settings( + { + "SOCIAL_AUTH_PIPELINE": ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.associate_by_email", + "social_core.tests.pipeline.set_user_from_args", + ) + } + ) + + self.do_login(after_complete_checks=False) + + # Handle the partial pipeline + self.strategy.session_set("attribute", "testing") + token = self.strategy.session_pop(PARTIAL_TOKEN_SESSION_NAME) + partial = self.strategy.partial_load(token) + self.backend.continue_pipeline(partial) + + +class TestUserDetails(BaseActionTest): + def test_user_details(self): + self.strategy.set_settings({}) + details = {"first_name": "Test"} + user = User(username="foobar") + backend = None + user_details(self.strategy, details, backend, user) + self.assertEqual(user.first_name, "Test") + + # Also test mutation + details = {"first_name": "Test2"} + user_details(self.strategy, details, backend, user) + self.assertEqual(user.first_name, "Test2") + + def test_user_details_(self): + self.strategy.set_settings( + {"SOCIAL_AUTH_IMMUTABLE_USER_FIELDS": ("first_name",)} + ) + details = {"first_name": "Test"} + user = User(username="foobar") + backend = None + user_details(self.strategy, details, backend, user) + self.assertEqual(user.first_name, "Test") + + # Also test mutation does not change field + details = {"first_name": "Test2"} + user_details(self.strategy, details, backend, user) + self.assertEqual(user.first_name, "Test") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_storage.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_storage.py new file mode 100644 index 0000000000000000000000000000000000000000..8719979b7a82de5f81c89caf0481a841a8fc4f27 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_storage.py @@ -0,0 +1,195 @@ +import random +import unittest + +from ..storage import AssociationMixin, BaseStorage, CodeMixin, NonceMixin, UserMixin +from ..strategy import BaseStrategy +from .models import User + +NOT_IMPLEMENTED_MSG = "Implement in subclass" + + +class BrokenUser(UserMixin): + pass + + +class BrokenAssociation(AssociationMixin): + pass + + +class BrokenNonce(NonceMixin): + pass + + +class BrokenCode(CodeMixin): + pass + + +class BrokenStrategy(BaseStrategy): + pass + + +class BrokenStrategyWithSettings(BrokenStrategy): + def get_setting(self, name): + raise AttributeError() + + +class BrokenStorage(BaseStorage): + pass + + +class BrokenUserTests(unittest.TestCase): + def setUp(self): + self.user = BrokenUser + + def tearDown(self): + self.user = None + + def test_get_username(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.get_username(User("foobar")) + + def test_user_model(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.user_model() + + def test_username_max_length(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.username_max_length() + + def test_get_user(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.get_user(1) + + def test_get_social_auth(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.get_social_auth("foo", 1) + + def test_get_social_auth_for_user(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.get_social_auth_for_user(User("foobar")) + + def test_create_social_auth(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.create_social_auth(User("foobar"), 1, "foo") + + def test_disconnect(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.user.disconnect(BrokenUser()) + + +class BrokenAssociationTests(unittest.TestCase): + def setUp(self): + self.association = BrokenAssociation + + def tearDown(self): + self.association = None + + def test_store(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.association.store("http://foobar.com", BrokenAssociation()) + + def test_get(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.association.get() + + def test_remove(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.association.remove([1, 2, 3]) + + +class BrokenNonceTests(unittest.TestCase): + def setUp(self): + self.nonce = BrokenNonce + + def tearDown(self): + self.nonce = None + + def test_use(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.nonce.use("http://foobar.com", 1364951922, "foobar123") + + +class BrokenCodeTest(unittest.TestCase): + def setUp(self): + self.code = BrokenCode + + def tearDown(self): + self.code = None + + def test_get_code(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.code.get_code("foobar") + + +class BrokenStrategyTests(unittest.TestCase): + def setUp(self): + self.strategy = BrokenStrategy(storage=BrokenStorage) + + def tearDown(self): + self.strategy = None + + def test_redirect(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.redirect("http://foobar.com") + + def test_get_setting(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.get_setting("foobar") + + def test_html(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.html("<p>foobar</p>") + + def test_request_data(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.request_data() + + def test_request_host(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.request_host() + + def test_session_get(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.session_get("foobar") + + def test_session_set(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.session_set("foobar", 123) + + def test_session_pop(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.session_pop("foobar") + + def test_build_absolute_uri(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.build_absolute_uri("/foobar") + + def test_render_html_with_tpl(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.render_html("foobar.html", context={}) + + def test_render_html_with_html(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.render_html(html="<p>foobar</p>", context={}) + + def test_render_html_with_none(self): + with self.assertRaisesRegex(ValueError, "Missing template or html parameters"): + self.strategy.render_html() + + def test_is_integrity_error(self): + with self.assertRaisesRegex(NotImplementedError, NOT_IMPLEMENTED_MSG): + self.strategy.storage.is_integrity_error(None) + + def test_random_string(self): + self.assertTrue(isinstance(self.strategy.random_string(), str)) + + def test_random_string_without_systemrandom(self): + def SystemRandom(): + raise NotImplementedError() + + orig_random = getattr(random, "SystemRandom", None) + random.SystemRandom = SystemRandom + + strategy = BrokenStrategyWithSettings(storage=BrokenStorage) + self.assertTrue(isinstance(strategy.random_string(), str)) + random.SystemRandom = orig_random diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1b818b3ce8d4b339dc2c986b21502b2072cb7989 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/test_utils.py @@ -0,0 +1,200 @@ +import sys +import unittest +from unittest.mock import Mock + +from ..utils import ( + build_absolute_uri, + partial_pipeline_data, + sanitize_redirect, + slugify, + user_is_active, + user_is_authenticated, +) +from .models import TestPartial + +PY3 = sys.version_info[0] == 3 + + +class SanitizeRedirectTest(unittest.TestCase): + def test_none_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], None), None) + + def test_empty_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], ""), None) + + def test_dict_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], {}), None) + + def test_invalid_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], {"foo": "bar"}), None) + + def test_wrong_path_redirect(self): + self.assertEqual( + sanitize_redirect(["myapp.com"], "http://notmyapp.com/path/"), None + ) + + def test_invalid_evil_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], "///evil.com"), None) + + def test_valid_absolute_redirect(self): + self.assertEqual( + sanitize_redirect(["myapp.com"], "http://myapp.com/path/"), + "http://myapp.com/path/", + ) + + def test_valid_relative_redirect(self): + self.assertEqual(sanitize_redirect(["myapp.com"], "/path/"), "/path/") + + def test_multiple_hosts(self): + allowed_hosts = ["myapp1.com", "myapp2.com"] + for host in allowed_hosts: + url = f"http://{host}/path/" + self.assertEqual(sanitize_redirect(allowed_hosts, url), url) + + def test_multiple_hosts_wrong_host(self): + self.assertEqual( + sanitize_redirect( + ["myapp1.com", "myapp2.com"], "http://notmyapp.com/path/" + ), + None, + ) + + +class UserIsAuthenticatedTest(unittest.TestCase): + def test_user_is_none(self): + self.assertEqual(user_is_authenticated(None), False) + + def test_user_is_not_none(self): + self.assertEqual(user_is_authenticated(object()), True) + + def test_user_has_is_authenticated(self): + class User: + is_authenticated = True + + self.assertEqual(user_is_authenticated(User()), True) + + def test_user_has_is_authenticated_callable(self): + class User: + def is_authenticated(self): + return True + + self.assertEqual(user_is_authenticated(User()), True) + + +class UserIsActiveTest(unittest.TestCase): + def test_user_is_none(self): + self.assertEqual(user_is_active(None), False) + + def test_user_is_not_none(self): + self.assertEqual(user_is_active(object()), True) + + def test_user_has_is_active(self): + class User: + is_active = True + + self.assertEqual(user_is_active(User()), True) + + def test_user_has_is_active_callable(self): + class User: + def is_active(self): + return True + + self.assertEqual(user_is_active(User()), True) + + +class SlugifyTest(unittest.TestCase): + def test_slugify_formats(self): + if PY3: + self.assertEqual(slugify("FooBar"), "foobar") + self.assertEqual(slugify("Foo Bar"), "foo-bar") + self.assertEqual(slugify("Foo (Bar)"), "foo-bar") + else: + self.assertEqual(slugify("FooBar".decode("utf-8")), "foobar") + self.assertEqual(slugify("Foo Bar".decode("utf-8")), "foo-bar") + self.assertEqual(slugify("Foo (Bar)".decode("utf-8")), "foo-bar") + + +class BuildAbsoluteURITest(unittest.TestCase): + def setUp(self): + self.host = "http://foobar.com" + + def tearDown(self): + self.host = None + + def test_path_none(self): + self.assertEqual(build_absolute_uri(self.host), self.host) + + def test_path_empty(self): + self.assertEqual(build_absolute_uri(self.host, ""), self.host) + + def test_path_http(self): + self.assertEqual( + build_absolute_uri(self.host, "http://barfoo.com"), "http://barfoo.com" + ) + + def test_path_https(self): + self.assertEqual( + build_absolute_uri(self.host, "https://barfoo.com"), "https://barfoo.com" + ) + + def test_host_ends_with_slash_and_path_starts_with_slash(self): + self.assertEqual( + build_absolute_uri(self.host + "/", "/foo/bar"), "http://foobar.com/foo/bar" + ) + + def test_absolute_uri(self): + self.assertEqual( + build_absolute_uri(self.host, "/foo/bar"), "http://foobar.com/foo/bar" + ) + + +class PartialPipelineData(unittest.TestCase): + def test_returns_partial_when_uid_and_email_do_match(self): + email = "foo@example.com" + backend = self._backend({"uid": email}) + backend.strategy.request_data.return_value = {backend.ID_KEY: email} + key, val = ("foo", "bar") + partial = partial_pipeline_data(backend, None, *(), **dict([(key, val)])) + self.assertTrue(key in partial.kwargs) + self.assertEqual(partial.kwargs[key], val) + self.assertEqual(backend.strategy.clean_partial_pipeline.call_count, 0) + + def test_clean_pipeline_when_uid_does_not_match(self): + backend = self._backend({"uid": "foo@example.com"}) + backend.strategy.request_data.return_value = {backend.ID_KEY: "bar@example.com"} + key, val = ("foo", "bar") + partial = partial_pipeline_data(backend, None, *(), **dict([(key, val)])) + self.assertIsNone(partial) + self.assertEqual(backend.strategy.clean_partial_pipeline.call_count, 1) + + def test_kwargs_included_in_result(self): + backend = self._backend() + key, val = ("foo", "bar") + partial = partial_pipeline_data(backend, None, *(), **dict([(key, val)])) + self.assertTrue(key in partial.kwargs) + self.assertEqual(partial.kwargs[key], val) + self.assertEqual(backend.strategy.clean_partial_pipeline.call_count, 0) + + def test_update_user(self): + user = object() + backend = self._backend(session_kwargs={"user": None}) + partial = partial_pipeline_data(backend, user) + self.assertTrue("user" in partial.kwargs) + self.assertEqual(partial.kwargs["user"], user) + self.assertEqual(backend.strategy.clean_partial_pipeline.call_count, 0) + + def _backend(self, session_kwargs=None): + backend = Mock() + backend.ID_KEY = "email" + backend.name = "mock-backend" + + strategy = Mock() + strategy.request = None + strategy.request_data.return_value = {} + strategy.session_get.return_value = object() + strategy.partial_load.return_value = TestPartial.prepare( + backend.name, 0, {"args": [], "kwargs": session_kwargs or {}} + ) + + backend.strategy = strategy + return backend diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/testkey.pem b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/testkey.pem new file mode 100644 index 0000000000000000000000000000000000000000..bfc31dc8908f21ef030f10dbf6a40ccfa2294314 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/tests/testkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAtavb41y83n7xY/sIS23Rv+TEwI85xmML57BT9dyb9JeAFPYG +RIaN/kWYW8pR0CZDu2nLwU2lUA0d0wKTOMaHQFs6L/rPN1zOx13HYO+TKybgU+e8 +TaOncKmJeyp3MP/OM6KBYp7Cx6eLlyvw3HJh6nT+Y5vj3rwS4PYjX1hUcr51IOcq +Ls5Sx/UQ4OUVHJLlcUxP6k2n44nGoDYK8zRc5dEBxbTL4yKzCR9unWAlDHVQYXOx +vzxxFtUID7dy38e0MZ+3RnmIY2wl7/PIRCsbIKrsAiONnLkJQitMVkU8jTEPrXNC +Lj5Hzgf0kDD+4ukQdUPCXlv9y668anaxabXFIwIDAQABAoIBAQCUAfT+UiKpnoBp +dS53zXvSO740Jzvpre4YD2cH6njAl+FIsnu+vmTWoLqVJcrrqxEJkhLnZKvnARio +PfPVkKDGRMyuJEdIEnuAn519ExIyWNTwZt7Z3hffSLByQNGkgPPsy1tgDnogERc/ +zRPJdgLh8fkDDBFk+JLk5oNA/YSnibV5MtriNPoDONxaHsguJ7JvikgLdQs5nyuQ +loMx4JhqP+fXsGIU0DFwaLPvEEntKodaRZXvAMLOuGi3O83OGkhevVvEVFSzCeS1 +fYnKwySQgNctztoBpf09zATeL9xt8tipVnyBKOIBJyf/BQV7fESXp0R8d+rW1cs0 +21qakP0pAoGBAOUFPT/pLP3w676dGvggK0kDy8gjgDHl2/x3fhbeua/6yfetVpZE +CuFez/9E24kMS4/GCi3WgPA6DHDYBH5t1S4e0/cgGJ8sjuX8ELLgy4q+WmvgTwDS +FbXKqY929Hlu65hUvl2xVP2MYUGLHiUE8yKk4RKdZO+3GkWXHhq9A+mvAoGBAMsS +rBYyAt9XeI8W8w2dWgZnBp+7WQeMUAZfCpq65urycD9on9R3gJ5zbOfq6CG2FXML +kslY1R4CVYge+HoWITFECvwPdbDYx/QIVvuhRH8omrG5iYY+ljGuF6wlzETgW117 +vYTSf5xXJ4LiuFD6TY4rxZ0UdjKba9bJfsQb45zNAoGBAMm/zM4xVn46LyLS+YAd +rqP6oRklFPhf+mQ0y7HP8Royvprea0milUcmI+tHOHJJj4MPPcZVkW6OZIk/8u2B +SewAIlAwSSBnu1akr/00hHor6DHh/xbE+3UTHD4S15jl+stN1Alrf2iAsuhvalXI +P3uEbfXdC58U2SL21gFOA1VnAoGBAIv93EoUwewrhb3GyVlaXyRIw8U7xv0wGj66 +KDpQnD3dUco0mvJCS5Vv5uTeCJasyo6brN5G8ewVGdeT2iF3vfwTdysakTyPxRAS +67veCbVLTZE1YXv9C1dGN6WCDRZyQCnq0tSMtFIXtvJAz2VrmClpPXqzD2SFxkq0 +b0JMI5YFAoGAL+1E+JUfPHf69K8XDXY+zrZL/KRPuXHcGk4qm7JXCDxr90zMVJYj +RWTQZHgGCEZGGlChJD8JwGiWEtsn0zlhn4H4dPWzeS7D1fsJK30lhYpDp3TuOY0x +lQAatQXzunglAxXwlOOazX4uoVtiFLjY3U4G6gCwKYEtjP1r0GULlk0= +-----END RSA PRIVATE KEY----- diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_core/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_core/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..71ad8186da26377513ae5ef79b8ca4b553606560 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_core/utils.py @@ -0,0 +1,320 @@ +import functools +import hmac +import logging +import re +import sys +import time +import unicodedata +from urllib.parse import parse_qs as battery_parse_qs +from urllib.parse import urlencode, urlparse, urlunparse + +import requests +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.poolmanager import PoolManager + +import social_core + +from .exceptions import AuthCanceled, AuthForbidden, AuthUnreachableProvider + +SETTING_PREFIX = "SOCIAL_AUTH" + +PARTIAL_TOKEN_SESSION_NAME = "partial_pipeline_token" + + +social_logger = logging.getLogger("social") + + +class SSLHttpAdapter(HTTPAdapter): + """ " + Transport adapter that allows to use any SSL protocol. Based on: + http://requests.rtfd.org/latest/user/advanced/#example-specific-ssl-version + """ + + def __init__(self, ssl_protocol): + self.ssl_protocol = ssl_protocol + super().__init__() + + def init_poolmanager(self, connections, maxsize, block=False): + self.poolmanager = PoolManager( + num_pools=connections, + maxsize=maxsize, + block=block, + ssl_version=self.ssl_protocol, + ) + + @classmethod + def ssl_adapter_session(cls, ssl_protocol): + session = requests.Session() + session.mount("https://", SSLHttpAdapter(ssl_protocol)) + return session + + +def import_module(name): + __import__(name) + return sys.modules[name] + + +def module_member(name): + mod, member = name.rsplit(".", 1) + module = import_module(mod) + return getattr(module, member) + + +def user_agent(): + """Builds a simple User-Agent string to send in requests""" + return "social-auth-" + social_core.__version__ + + +def url_add_parameters(url, params): + """Adds parameters to URL, parameter will be repeated if already present""" + if params: + fragments = list(urlparse(url)) + value = parse_qs(fragments[4]) + value.update(params) + fragments[4] = urlencode(value) + url = urlunparse(fragments) + return url + + +def to_setting_name(*names): + return "_".join([name.upper().replace("-", "_") for name in names if name]) + + +def setting_name(*names): + return to_setting_name(*((SETTING_PREFIX,) + names)) + + +def sanitize_redirect(hosts, redirect_to): + """ + Given a list of hostnames and an untrusted URL to redirect to, + this method tests it to make sure it isn't garbage/harmful + and returns it, else returns None, similar as how's it done + on django.contrib.auth.views. + """ + # Avoid redirect on evil URLs like ///evil.com + if ( + not redirect_to + or not hasattr(redirect_to, "startswith") + or redirect_to.startswith("///") + ): + return None + + try: + # Don't redirect to a host that's not in the list + netloc = urlparse(redirect_to)[1] or hosts[0] + except (TypeError, AttributeError): + pass + else: + if netloc in hosts: + return redirect_to + + +def user_is_authenticated(user): + if user and hasattr(user, "is_authenticated"): + if callable(user.is_authenticated): + authenticated = user.is_authenticated() + else: + authenticated = user.is_authenticated + elif user: + authenticated = True + else: + authenticated = False + return authenticated + + +def user_is_active(user): + if user and hasattr(user, "is_active"): + is_active = user.is_active() if callable(user.is_active) else user.is_active + elif user: + is_active = True + else: + is_active = False + return is_active + + +# This slugify version was borrowed from django revision a61dbd6 +def slugify(value): + """Converts to lowercase, removes non-word characters (alphanumerics + and underscores) and converts spaces to hyphens. Also strips leading + and trailing whitespace.""" + value = ( + unicodedata.normalize("NFKD", str(value)) + .encode("ascii", "ignore") + .decode("ascii") + ) + value = re.sub(r"[^\w\s-]", "", value).strip().lower() + return re.sub(r"[-\s]+", "-", value) + + +def first(func, items): + """Return the first item in the list for what func returns True""" + for item in items: + if func(item): + return item + + +def parse_qs(value): + """Like urlparse.parse_qs but transform list values to single items""" + return drop_lists(battery_parse_qs(value)) + + +def drop_lists(value): + out = {} + for key, val in value.items(): + val = val[0] + if isinstance(key, bytes): + key = str(key, "utf-8") + if isinstance(val, bytes): + val = str(val, "utf-8") + out[key] = val + return out + + +def partial_pipeline_data(backend, user=None, partial_token=None, *args, **kwargs): + request_data = backend.strategy.request_data() + + partial_argument_name = backend.setting( + "PARTIAL_PIPELINE_TOKEN_NAME", "partial_token" + ) + partial_token = ( + partial_token + or request_data.get(partial_argument_name) + or backend.strategy.session_get(PARTIAL_TOKEN_SESSION_NAME, None) + ) + + if partial_token: + partial = backend.strategy.partial_load(partial_token) + partial_matches_request = False + + if partial and partial.backend == backend.name: + partial_matches_request = True + + # Normally when resuming a pipeline, request_data will be empty. We + # only need to check for a uid match if new data was provided (i.e. + # if current request specifies the ID_KEY). + if backend.ID_KEY in request_data: + id_from_partial = partial.kwargs.get("uid") + id_from_request = request_data.get(backend.ID_KEY) + + if id_from_partial != id_from_request: + partial_matches_request = False + + if partial_matches_request: + if user: # don't update user if it's None + kwargs.setdefault("user", user) + kwargs.setdefault("request", request_data) + partial.extend_kwargs(kwargs) + return partial + else: + backend.strategy.clean_partial_pipeline(partial_token) + + +def build_absolute_uri(host_url, path=None): + """Build absolute URI with given (optional) path""" + path = path or "" + if path.startswith("http://") or path.startswith("https://"): + return path + if host_url.endswith("/") and path.startswith("/"): + path = path[1:] + return host_url + path + + +def constant_time_compare(val1, val2): + """Compare two values and prevent timing attacks for cryptographic use.""" + if isinstance(val1, str): + val1 = val1.encode("utf-8") + if isinstance(val2, str): + val2 = val2.encode("utf-8") + return hmac.compare_digest(val1, val2) + + +def is_url(value): + return value and ( + value.startswith("http://") + or value.startswith("https://") + or value.startswith("/") + ) + + +def setting_url(backend, *names): + for name in names: + if is_url(name): + return name + else: + value = backend.setting(name) + if is_url(value): + return value + + +def handle_http_errors(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except requests.HTTPError as err: + if err.response.status_code == 400: + raise AuthCanceled(args[0], response=err.response) + elif err.response.status_code == 401: + raise AuthForbidden(args[0]) + elif err.response.status_code == 503: + raise AuthUnreachableProvider(args[0]) + else: + raise + + return wrapper + + +def append_slash(url): + """Make sure we append a slash at the end of the URL otherwise we + have issues with urljoin Example: + >>> urlparse.urljoin('http://www.example.com/api/v3', 'user/1/') + 'http://www.example.com/api/user/1/' + """ + if url and not url.endswith("/"): + url = f"{url}/" + return url + + +def get_strategy(strategy, storage, *args, **kwargs): + Strategy = module_member(strategy) + Storage = module_member(storage) + return Strategy(Storage, *args, **kwargs) + + +class cache: + """ + Cache decorator that caches the return value of a method for a + specified time. + + It maintains a cache per class, so subclasses have a different cache entry + for the same cached method. + + Does not work for methods with arguments. + """ + + def __init__(self, ttl): + self.ttl = ttl + self.cache = {} + + def __call__(self, fn): + def wrapped(this): + now = time.time() + last_updated = None + cached_value = None + if this.__class__ in self.cache: + last_updated, cached_value = self.cache[this.__class__] + if not cached_value or now - last_updated > self.ttl: + try: + cached_value = fn(this) + self.cache[this.__class__] = (now, cached_value) + except Exception: + # Use previously cached value when call fails, if available + if not cached_value: + raise + return cached_value + + wrapped.invalidate = self._invalidate + return wrapped + + def _invalidate(self): + self.cache.clear() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..94b073f533cdeaf9c76b559b61885c77cd95c99f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__init__.py @@ -0,0 +1,23 @@ +__version__ = '4.0.0' + + +from social_core.backends.base import BaseAuth + +# django.contrib.auth.load_backend() will import and instanciate the +# authentication backend ignoring the possibility that it might +# require more arguments. Here we set a monkey patch to +# BaseAuth.__init__ to ignore the mandatory strategy argument and load +# it. + +def baseauth_init_workaround(original_init): + def fake_init(self, strategy=None, *args, **kwargs): + from .utils import load_strategy + original_init(self, strategy or load_strategy(), *args, **kwargs) + return fake_init + + +if not getattr(BaseAuth, '__init_patched', False): + BaseAuth.__init__ = baseauth_init_workaround(BaseAuth.__init__) + BaseAuth.__init_patched = True + +default_app_config = 'social_django.config.PythonSocialAuthConfig' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c80e2e762239624ea3921d5c487fbad5168805ab Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/admin.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc7c73caaad196ac051945701e2a04d65b5a7ae7 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/admin.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/compat.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86e53705d0188525195d8571d0a8a1ee70ccda03 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/compat.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/config.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d9568cb2667a882ef6a56fe8227b379eba7805e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/config.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/context_processors.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/context_processors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f60c9a40d3c5e1fcdbf90bc91415bbb44086bdb6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/context_processors.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/fields.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/fields.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..410491019efb77cfafd92271aa999bfff39c5cc6 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/fields.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/managers.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/managers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d36f525c6236888eb42b9be407b2937be7d07d16 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/managers.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/middleware.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/middleware.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..377d499805a7e807d6a20dc5846fd56c512060b9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/middleware.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f84361d9b798926e089baacfb1991f11ce7b0fea Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/storage.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/storage.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..889531ffc90d68500189165b824f7723055ce292 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/storage.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/strategy.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/strategy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c92abcb307b95038f60fcd4425005497f135d41 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/strategy.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/urls.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac6e8805a29149c3c460591aca5a2e1409e8f4b8 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/urls.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/utils.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..931661cfdcca3f1c69f69749f979ef8fb92c1e7e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/utils.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fa44c4d11464ba1e44cbfceef0ebe8542528511 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/admin.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..635d3d821b7e3806558192536fd75969b399b501 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/admin.py @@ -0,0 +1,62 @@ +"""Admin settings""" +from itertools import chain + +from django.conf import settings +from django.contrib import admin + +from social_core.utils import setting_name +from .models import UserSocialAuth, Nonce, Association + + +class UserSocialAuthOption(admin.ModelAdmin): + """Social Auth user options""" + list_display = ('user', 'id', 'provider', 'uid') + list_filter = ('provider',) + raw_id_fields = ('user',) + list_select_related = True + + def get_search_fields(self, request=None): + search_fields = getattr( + settings, setting_name('ADMIN_USER_SEARCH_FIELDS'), None + ) + if search_fields is None: + _User = UserSocialAuth.user_model() + username = getattr(_User, 'USERNAME_FIELD', None) or \ + hasattr(_User, 'username') and 'username' or \ + None + fieldnames = ('first_name', 'last_name', 'email', username) + all_names = self._get_all_field_names(_User._meta) + search_fields = [name for name in fieldnames + if name and name in all_names] + return ['user__' + name for name in search_fields] + \ + getattr(settings, setting_name('ADMIN_SEARCH_FIELDS'), []) + + @staticmethod + def _get_all_field_names(model): + names = chain.from_iterable( + (field.name, field.attname) + if hasattr(field, 'attname') else (field.name,) + for field in model.get_fields() + # For complete backwards compatibility, you may want to exclude + # GenericForeignKey from the results. + if not (field.many_to_one and field.related_model is None) + ) + return list(set(names)) + + +class NonceOption(admin.ModelAdmin): + """Nonce options""" + list_display = ('id', 'server_url', 'timestamp', 'salt') + search_fields = ('server_url',) + + +class AssociationOption(admin.ModelAdmin): + """Association options""" + list_display = ('id', 'server_url', 'assoc_type') + list_filter = ('assoc_type',) + search_fields = ('server_url',) + + +admin.site.register(UserSocialAuth, UserSocialAuthOption) +admin.site.register(Nonce, NonceOption) +admin.site.register(Association, AssociationOption) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/compat.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/compat.py new file mode 100644 index 0000000000000000000000000000000000000000..eef9ad2e9efe81e44d439a450b67064f034d4dc2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/compat.py @@ -0,0 +1,34 @@ +# coding=utf-8 +import six +import django +from django.db import models + + +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse + +try: + from django.utils.deprecation import MiddlewareMixin +except ImportError: + MiddlewareMixin = object + + +def get_rel_model(field): + if django.VERSION >= (1, 9): + return field.remote_field.model + + user_model = field.rel.to + if isinstance(user_model, six.string_types): + app_label, model_name = user_model.split('.') + user_model = models.get_model(app_label, model_name) + return user_model + + +def get_request_port(request): + if django.VERSION >= (1, 9): + return request.get_port() + + host_parts = request.get_host().partition(':') + return host_parts[2] or request.META['SERVER_PORT'] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/config.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/config.py new file mode 100644 index 0000000000000000000000000000000000000000..c1491bb18430edc0ccbabcc8b794751212a9145b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/config.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig + + +class PythonSocialAuthConfig(AppConfig): + # Full Python path to the application eg. 'django.contrib.admin'. + name = 'social_django' + # Last component of the Python path to the application eg. 'admin'. + label = 'social_django' + # Human-readable name for the application eg. "Admin". + verbose_name = 'Python Social Auth' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/context_processors.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/context_processors.py new file mode 100644 index 0000000000000000000000000000000000000000..07e875c52109d23d098cc44783b31d5b870bdb60 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/context_processors.py @@ -0,0 +1,52 @@ +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.utils.functional import SimpleLazyObject +from django.utils.http import urlquote + +try: + from django.utils.functional import empty as _empty + empty = _empty +except ImportError: # django < 1.4 + empty = None + + +from social_core.backends.utils import user_backends_data +from .utils import Storage, BACKENDS + + +class LazyDict(SimpleLazyObject): + """Lazy dict initialization.""" + def __getitem__(self, name): + if self._wrapped is empty: + self._setup() + return self._wrapped[name] + + def __setitem__(self, name, value): + if self._wrapped is empty: + self._setup() + self._wrapped[name] = value + + +def backends(request): + """Load Social Auth current user data to context under the key 'backends'. + Will return the output of social_core.backends.utils.user_backends_data.""" + return {'backends': LazyDict(lambda: user_backends_data(request.user, + BACKENDS, + Storage))} + + +def login_redirect(request): + """Load current redirect to context.""" + value = request.method == 'POST' and \ + request.POST.get(REDIRECT_FIELD_NAME) or \ + request.GET.get(REDIRECT_FIELD_NAME) + if value: + value = urlquote(value) + querystring = REDIRECT_FIELD_NAME + '=' + value + else: + querystring = '' + + return { + 'REDIRECT_FIELD_NAME': REDIRECT_FIELD_NAME, + 'REDIRECT_FIELD_VALUE': value, + 'REDIRECT_QUERYSTRING': querystring + } diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/fields.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/fields.py new file mode 100644 index 0000000000000000000000000000000000000000..225e381c260d4a128656bc2e4a129b5d96677e2a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/fields.py @@ -0,0 +1,71 @@ +import json +import six + +from django.core.exceptions import ValidationError +from django.conf import settings +from django.db import models +from django.utils.encoding import force_text + +from social_core.utils import setting_name + +if getattr(settings, setting_name('POSTGRES_JSONFIELD'), False): + from django.contrib.postgres.fields import JSONField as JSONFieldBase +else: + JSONFieldBase = models.TextField + + +class JSONField(JSONFieldBase): + """Simple JSON field that stores python structures as JSON strings + on database. + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('default', dict) + super(JSONField, self).__init__(*args, **kwargs) + + def from_db_value(self, value, *args, **kwargs): + return self.to_python(value) + + def to_python(self, value): + """ + Convert the input JSON value into python structures, raises + django.core.exceptions.ValidationError if the data can't be converted. + """ + if self.blank and not value: + return {} + value = value or '{}' + if isinstance(value, six.binary_type): + value = six.text_type(value, 'utf-8') + if isinstance(value, six.string_types): + try: + return json.loads(value) + except Exception as err: + raise ValidationError(str(err)) + else: + return value + + def validate(self, value, model_instance): + """Check value is a valid JSON string, raise ValidationError on + error.""" + if isinstance(value, six.string_types): + super(JSONField, self).validate(value, model_instance) + try: + json.loads(value) + except Exception as err: + raise ValidationError(str(err)) + + def get_prep_value(self, value): + """Convert value to JSON string before save""" + try: + return json.dumps(value) + except Exception as err: + raise ValidationError(str(err)) + + def value_to_string(self, obj): + """Return value from object converted to string properly""" + return force_text(self.value_from_object(obj)) + + def value_from_object(self, obj): + """Return value dumped to string.""" + orig_val = super(JSONField, self).value_from_object(obj) + return self.get_prep_value(orig_val) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9f46a3dedb83e17620bb68e0571a53110556748 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6927051a3018984b20bf1f9014f815025cc81b60 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/clearsocial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/clearsocial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d2252b0dd83ef9f331f2f60605ff6012f94a67a Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/__pycache__/clearsocial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/clearsocial.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/clearsocial.py new file mode 100644 index 0000000000000000000000000000000000000000..fa1533334d698cb412bca8524a1915d65f86ec59 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/management/commands/clearsocial.py @@ -0,0 +1,35 @@ +from datetime import timedelta + +from django.core.management.base import BaseCommand +from django.utils import timezone + +from social_django.models import Code, Partial + + +class Command(BaseCommand): + help = 'removes old not used verification codes and partials' + + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument( + '--age', + action='store', + type=int, + dest='age', + default=14, + help='how long to keep unused data (in days, defaults to 14)' + ) + + def handle(self, *args, **options): + age = timezone.now() - timedelta(days=options['age']) + + # Delete old not verified codes + Code.objects.filter( + verified=False, + timestamp__lt=age + ).delete() + + # Delete old partial data + Partial.objects.filter( + timestamp__lt=age + ).delete() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/managers.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/managers.py new file mode 100644 index 0000000000000000000000000000000000000000..1fa91b68f77a11dd53bcafb8a2ee4590daceefc6 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/managers.py @@ -0,0 +1,15 @@ +from django.db import models + + +class UserSocialAuthManager(models.Manager): + """Manager for the UserSocialAuth django model.""" + + class Meta: + app_label = "social_django" + + def get_social_auth(self, provider, uid): + try: + return self.select_related('user').get(provider=provider, + uid=uid) + except self.model.DoesNotExist: + return None diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/middleware.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/middleware.py new file mode 100644 index 0000000000000000000000000000000000000000..6d5d7f572d1df8a0ebb76611f2c5edc88a77186f --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/middleware.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +import six + +from django.apps import apps +from django.conf import settings +from django.contrib import messages +from django.contrib.messages.api import MessageFailure +from django.shortcuts import redirect +from django.utils.http import urlquote + +from social_core.exceptions import SocialAuthBaseException +from social_core.utils import social_logger +from .compat import MiddlewareMixin + + +class SocialAuthExceptionMiddleware(MiddlewareMixin): + """Middleware that handles Social Auth AuthExceptions by providing the user + with a message, logging an error, and redirecting to some next location. + + By default, the exception message itself is sent to the user and they are + redirected to the location specified in the SOCIAL_AUTH_LOGIN_ERROR_URL + setting. + + This middleware can be extended by overriding the get_message or + get_redirect_uri methods, which each accept request and exception. + """ + def process_exception(self, request, exception): + strategy = getattr(request, 'social_strategy', None) + if strategy is None or self.raise_exception(request, exception): + return + + if isinstance(exception, SocialAuthBaseException): + backend = getattr(request, 'backend', None) + backend_name = getattr(backend, 'name', 'unknown-backend') + + message = self.get_message(request, exception) + url = self.get_redirect_uri(request, exception) + + if apps.is_installed('django.contrib.messages'): + social_logger.info(message) + try: + messages.error(request, message, + extra_tags='social-auth ' + backend_name) + except MessageFailure: + if url: + url += ('?' in url and '&' or '?') + \ + 'message={0}&backend={1}'.format(urlquote(message), + backend_name) + else: + social_logger.error(message) + + if url: + return redirect(url) + + def raise_exception(self, request, exception): + strategy = getattr(request, 'social_strategy', None) + if strategy is not None: + return strategy.setting('RAISE_EXCEPTIONS') or settings.DEBUG + + def get_message(self, request, exception): + return six.text_type(exception) + + def get_redirect_uri(self, request, exception): + strategy = getattr(request, 'social_strategy', None) + return strategy.setting('LOGIN_ERROR_URL') diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0001_initial.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..dacdd726c54d5efa2a2463cc5c486d925794e196 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0001_initial.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + +from social_core.utils import setting_name + +from ..fields import JSONField +from ..storage import DjangoAssociationMixin, DjangoCodeMixin, \ + DjangoNonceMixin, DjangoUserMixin + +USER_MODEL = getattr(settings, setting_name('USER_MODEL'), None) or \ + getattr(settings, 'AUTH_USER_MODEL', None) or \ + 'auth.User' +UID_LENGTH = getattr(settings, setting_name('UID_LENGTH'), 255) +NONCE_SERVER_URL_LENGTH = getattr( + settings, setting_name('NONCE_SERVER_URL_LENGTH'), 255 +) +ASSOCIATION_SERVER_URL_LENGTH = getattr( + settings, setting_name('ASSOCIATION_SERVER_URL_LENGTH'), 255 +) +ASSOCIATION_HANDLE_LENGTH = getattr( + settings, setting_name('ASSOCIATION_HANDLE_LENGTH'), 255 +) + + +class Migration(migrations.Migration): + replaces = [ + ('default', '0001_initial'), + ('social_auth', '0001_initial') + ] + + dependencies = [ + migrations.swappable_dependency(USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Association', + fields=[ + ('id', models.AutoField( + verbose_name='ID', serialize=False, auto_created=True, + primary_key=True)), + ('server_url', + models.CharField(max_length=ASSOCIATION_SERVER_URL_LENGTH)), + ('handle', + models.CharField(max_length=ASSOCIATION_HANDLE_LENGTH)), + ('secret', models.CharField(max_length=255)), + ('issued', models.IntegerField()), + ('lifetime', models.IntegerField()), + ('assoc_type', models.CharField(max_length=64)), + ], + options={ + 'db_table': 'social_auth_association', + }, + bases=( + models.Model, DjangoAssociationMixin + ), + ), + migrations.CreateModel( + name='Code', + fields=[ + ('id', models.AutoField( + verbose_name='ID', serialize=False, auto_created=True, + primary_key=True)), + ('email', models.EmailField(max_length=75)), + ('code', models.CharField(max_length=32, db_index=True)), + ('verified', models.BooleanField(default=False)), + ], + options={ + 'db_table': 'social_auth_code', + }, + bases=(models.Model, DjangoCodeMixin), + ), + migrations.CreateModel( + name='Nonce', + fields=[ + ('id', models.AutoField( + verbose_name='ID', serialize=False, auto_created=True, + primary_key=True + )), + ('server_url', + models.CharField(max_length=NONCE_SERVER_URL_LENGTH)), + ('timestamp', models.IntegerField()), + ('salt', models.CharField(max_length=65)), + ], + options={ + 'db_table': 'social_auth_nonce', + }, + bases=(models.Model, DjangoNonceMixin), + ), + migrations.CreateModel( + name='UserSocialAuth', + fields=[ + ('id', models.AutoField( + verbose_name='ID', serialize=False, auto_created=True, + primary_key=True)), + ('provider', models.CharField(max_length=32)), + ('uid', models.CharField(max_length=UID_LENGTH)), + ('extra_data', JSONField(default='{}')), + ('user', models.ForeignKey( + related_name='social_auth', to=USER_MODEL, on_delete=models.CASCADE)), + ], + options={ + 'db_table': 'social_auth_usersocialauth', + }, + bases=(models.Model, DjangoUserMixin), + ), + migrations.AlterUniqueTogether( + name='usersocialauth', + unique_together={('provider', 'uid')}, + ), + migrations.AlterUniqueTogether( + name='code', + unique_together={('email', 'code')}, + ), + migrations.AlterUniqueTogether( + name='nonce', + unique_together={('server_url', 'timestamp', 'salt')}, + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0002_add_related_name.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0002_add_related_name.py new file mode 100644 index 0000000000000000000000000000000000000000..90653ba63c3818d43f9fdbb6e145709ce8aeea7e --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0002_add_related_name.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + +from social_core.utils import setting_name + +USER_MODEL = getattr(settings, setting_name('USER_MODEL'), None) or \ + getattr(settings, 'AUTH_USER_MODEL', None) or \ + 'auth.User' + + +class Migration(migrations.Migration): + replaces = [ + ('default', '0002_add_related_name'), + ('social_auth', '0002_add_related_name') + ] + + dependencies = [ + ('social_django', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='usersocialauth', + name='user', + field=models.ForeignKey( + related_name='social_auth', to=USER_MODEL, on_delete=models.CASCADE, + ) + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0003_alter_email_max_length.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0003_alter_email_max_length.py new file mode 100644 index 0000000000000000000000000000000000000000..ba4e8c1d95747102a3e25634135ce5c89401c2ed --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0003_alter_email_max_length.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import models, migrations + +from social_core.utils import setting_name + +EMAIL_LENGTH = getattr(settings, setting_name('EMAIL_LENGTH'), 254) + + +class Migration(migrations.Migration): + replaces = [ + ('default', '0003_alter_email_max_length'), + ('social_auth', '0003_alter_email_max_length') + ] + + dependencies = [ + ('social_django', '0002_add_related_name'), + ] + + operations = [ + migrations.AlterField( + model_name='code', + name='email', + field=models.EmailField(max_length=EMAIL_LENGTH), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0004_auto_20160423_0400.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0004_auto_20160423_0400.py new file mode 100644 index 0000000000000000000000000000000000000000..8636ad180dd77ed4bb2c4c2cc05af5b354f8dae9 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0004_auto_20160423_0400.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + +from ..fields import JSONField + + +class Migration(migrations.Migration): + replaces = [ + ('default', '0004_auto_20160423_0400'), + ('social_auth', '0004_auto_20160423_0400') + ] + + dependencies = [ + ('social_django', '0003_alter_email_max_length'), + ] + + operations = [ + migrations.AlterField( + model_name='usersocialauth', + name='extra_data', + field=JSONField(default=dict), + ) + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0005_auto_20160727_2333.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0005_auto_20160727_2333.py new file mode 100644 index 0000000000000000000000000000000000000000..67241a5a4cc35293832bf4530b9103ca1f170696 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0005_auto_20160727_2333.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2016-07-28 02:33 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + replaces = [ + ('social_auth', '0005_auto_20160727_2333') + ] + + dependencies = [ + ('social_django', '0004_auto_20160423_0400'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='association', + unique_together=set([('server_url', 'handle')]), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0006_partial.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0006_partial.py new file mode 100644 index 0000000000000000000000000000000000000000..4805fd2af42cda60521a10a745f9010106403592 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0006_partial.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2017-01-02 11:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import social_django.fields +import social_django.storage + + +class Migration(migrations.Migration): + + dependencies = [ + ('social_django', '0005_auto_20160727_2333'), + ] + + operations = [ + migrations.CreateModel( + name='Partial', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('token', models.CharField(db_index=True, max_length=32)), + ('next_step', models.PositiveSmallIntegerField(default=0)), + ('backend', models.CharField(max_length=32)), + ('data', social_django.fields.JSONField(default=dict)), + ], + options={ + 'db_table': 'social_auth_partial', + }, + bases=(models.Model, social_django.storage.DjangoPartialMixin), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0007_code_timestamp.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0007_code_timestamp.py new file mode 100644 index 0000000000000000000000000000000000000000..099975e7a5d2ba3c4e7dbba205a1d5c6d731292b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0007_code_timestamp.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-06-08 06:54 +from __future__ import unicode_literals + +from django.db import migrations, models + +from django.utils import timezone + + +class Migration(migrations.Migration): + dependencies = [ + ('social_django', '0006_partial'), + ] + + operations = [ + migrations.AddField( + model_name='code', + name='timestamp', + field=models.DateTimeField(auto_now_add=True, + db_index=True, + default=timezone.now), + preserve_default=False + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0008_partial_timestamp.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0008_partial_timestamp.py new file mode 100644 index 0000000000000000000000000000000000000000..659457a606a3e290bc2747ec5db1c7d7cc7b6d75 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0008_partial_timestamp.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-06-08 06:57 +from __future__ import unicode_literals + +from django.db import migrations, models + +from django.utils import timezone + + +class Migration(migrations.Migration): + dependencies = [ + ('social_django', '0007_code_timestamp'), + ] + + operations = [ + migrations.AddField( + model_name='partial', + name='timestamp', + field=models.DateTimeField(auto_now_add=True, + db_index=True, + default=timezone.now), + preserve_default=False, + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0009_auto_20191118_0520.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0009_auto_20191118_0520.py new file mode 100644 index 0000000000000000000000000000000000000000..a7bc55f44140d5f244027cd6c15d41a9cc9d881a --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0009_auto_20191118_0520.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2.7 on 2019-11-18 05:20 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('social_django', '0008_partial_timestamp'), + ] + + operations = [ + migrations.AddField( + model_name='usersocialauth', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='usersocialauth', + name='modified', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0010_uid_db_index.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0010_uid_db_index.py new file mode 100644 index 0000000000000000000000000000000000000000..ecc452932ec00622d991eae7125a9a4168227911 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/0010_uid_db_index.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import models, migrations + +from social_core.utils import setting_name + +UID_LENGTH = getattr(settings, setting_name('UID_LENGTH'), 255) + + +class Migration(migrations.Migration): + dependencies = [ + ('social_django', '0009_auto_20191118_0520'), + ] + + operations = [ + migrations.AlterField( + model_name='usersocialauth', + name='uid', + field=models.CharField(max_length=UID_LENGTH, db_index=True), + ), + ] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0001_initial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..818e17a949bb49809dabc6af65a50e7eed428dfd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0002_add_related_name.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0002_add_related_name.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1229d8521b913f1dc773a9f1de8f704cd4927106 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0002_add_related_name.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0003_alter_email_max_length.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0003_alter_email_max_length.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d11054953d7242c36c88344e2ff8c4b5fdded29 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0003_alter_email_max_length.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0004_auto_20160423_0400.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0004_auto_20160423_0400.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fa604e299d131e039af127c2ec43f121118d0b9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0004_auto_20160423_0400.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0005_auto_20160727_2333.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0005_auto_20160727_2333.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc9716d49a0754ffc6a0cac7188b7514cd64314d Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0005_auto_20160727_2333.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0006_partial.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0006_partial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2acacdf50fed375d6168a88caa7a8d4e83f474e1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0006_partial.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0007_code_timestamp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0007_code_timestamp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db3229050c1cc974477d0c2f472deab99852797e Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0007_code_timestamp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0008_partial_timestamp.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0008_partial_timestamp.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ec2c73aef2020224e6a4e98b5a5a069fc71c878 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0008_partial_timestamp.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0009_auto_20191118_0520.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0009_auto_20191118_0520.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d730da9f13da4a87b83e4259c268c75b77bf1232 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0009_auto_20191118_0520.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0010_uid_db_index.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0010_uid_db_index.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..640b53ac17a9293edc86d498c1f8a89d2422351f Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/0010_uid_db_index.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8c465caf04c71e669e9386db23ec78cfa47a7f3 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/social_django/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/models.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/models.py new file mode 100644 index 0000000000000000000000000000000000000000..24ab60a3207eac12cba66f6fe46cecbfabf7c842 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/models.py @@ -0,0 +1,141 @@ +"""Django ORM models for Social Auth""" +import six + +from django.db import models +from django.conf import settings +from django.db.utils import IntegrityError + +from social_core.utils import setting_name + +from .compat import get_rel_model +from .storage import DjangoUserMixin, DjangoAssociationMixin, \ + DjangoNonceMixin, DjangoCodeMixin, \ + DjangoPartialMixin, BaseDjangoStorage +from .fields import JSONField +from .managers import UserSocialAuthManager + + +USER_MODEL = getattr(settings, setting_name('USER_MODEL'), None) or \ + getattr(settings, 'AUTH_USER_MODEL', None) or \ + 'auth.User' +UID_LENGTH = getattr(settings, setting_name('UID_LENGTH'), 255) +EMAIL_LENGTH = getattr(settings, setting_name('EMAIL_LENGTH'), 254) +NONCE_SERVER_URL_LENGTH = getattr( + settings, setting_name('NONCE_SERVER_URL_LENGTH'), 255) +ASSOCIATION_SERVER_URL_LENGTH = getattr( + settings, setting_name('ASSOCIATION_SERVER_URL_LENGTH'), 255) +ASSOCIATION_HANDLE_LENGTH = getattr( + settings, setting_name('ASSOCIATION_HANDLE_LENGTH'), 255) + + +class AbstractUserSocialAuth(models.Model, DjangoUserMixin): + """Abstract Social Auth association model""" + user = models.ForeignKey(USER_MODEL, related_name='social_auth', + on_delete=models.CASCADE) + provider = models.CharField(max_length=32) + uid = models.CharField(max_length=UID_LENGTH, db_index=True) + extra_data = JSONField() + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + objects = UserSocialAuthManager() + + def __str__(self): + return str(self.user) + + class Meta: + app_label = "social_django" + abstract = True + + @classmethod + def get_social_auth(cls, provider, uid): + try: + return cls.objects.select_related('user').get(provider=provider, + uid=uid) + except cls.DoesNotExist: + return None + + @classmethod + def username_max_length(cls): + username_field = cls.username_field() + field = cls.user_model()._meta.get_field(username_field) + return field.max_length + + @classmethod + def user_model(cls): + user_model = get_rel_model(field=cls._meta.get_field('user')) + return user_model + + +class UserSocialAuth(AbstractUserSocialAuth): + """Social Auth association model""" + + class Meta: + """Meta data""" + app_label = "social_django" + unique_together = ('provider', 'uid') + db_table = 'social_auth_usersocialauth' + + +class Nonce(models.Model, DjangoNonceMixin): + """One use numbers""" + server_url = models.CharField(max_length=NONCE_SERVER_URL_LENGTH) + timestamp = models.IntegerField() + salt = models.CharField(max_length=65) + + class Meta: + app_label = "social_django" + unique_together = ('server_url', 'timestamp', 'salt') + db_table = 'social_auth_nonce' + + +class Association(models.Model, DjangoAssociationMixin): + """OpenId account association""" + server_url = models.CharField(max_length=ASSOCIATION_SERVER_URL_LENGTH) + handle = models.CharField(max_length=ASSOCIATION_HANDLE_LENGTH) + secret = models.CharField(max_length=255) # Stored base64 encoded + issued = models.IntegerField() + lifetime = models.IntegerField() + assoc_type = models.CharField(max_length=64) + + class Meta: + app_label = "social_django" + db_table = 'social_auth_association' + unique_together = ( + ('server_url', 'handle',) + ) + + +class Code(models.Model, DjangoCodeMixin): + email = models.EmailField(max_length=EMAIL_LENGTH) + code = models.CharField(max_length=32, db_index=True) + verified = models.BooleanField(default=False) + timestamp = models.DateTimeField(auto_now_add=True, db_index=True) + + class Meta: + app_label = "social_django" + db_table = 'social_auth_code' + unique_together = ('email', 'code') + + +class Partial(models.Model, DjangoPartialMixin): + token = models.CharField(max_length=32, db_index=True) + next_step = models.PositiveSmallIntegerField(default=0) + backend = models.CharField(max_length=32) + data = JSONField() + timestamp = models.DateTimeField(auto_now_add=True, db_index=True) + + class Meta: + app_label = "social_django" + db_table = 'social_auth_partial' + + +class DjangoStorage(BaseDjangoStorage): + user = UserSocialAuth + nonce = Nonce + association = Association + code = Code + partial = Partial + + @classmethod + def is_integrity_error(cls, exception): + return exception.__class__ is IntegrityError diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/storage.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/storage.py new file mode 100644 index 0000000000000000000000000000000000000000..9a00615404f356a3b28fc4260bda175bcf9ad3d2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/storage.py @@ -0,0 +1,224 @@ +"""Django ORM models for Social Auth""" +import base64 +import six +import sys +from django.core.exceptions import FieldDoesNotExist +from django.db import transaction, router +from django.db.utils import IntegrityError + +from social_core.storage import UserMixin, AssociationMixin, NonceMixin, \ + CodeMixin, PartialMixin, BaseStorage + + +class DjangoUserMixin(UserMixin): + """Social Auth association model""" + @classmethod + def changed(cls, user): + user.save() + + def set_extra_data(self, extra_data=None): + if super(DjangoUserMixin, self).set_extra_data(extra_data): + self.save() + + @classmethod + def allowed_to_disconnect(cls, user, backend_name, association_id=None): + if association_id is not None: + qs = cls.objects.exclude(id=association_id) + else: + qs = cls.objects.exclude(provider=backend_name) + qs = qs.filter(user=user) + + if hasattr(user, 'has_usable_password'): + valid_password = user.has_usable_password() + else: + valid_password = True + return valid_password or qs.count() > 0 + + @classmethod + def disconnect(cls, entry): + entry.delete() + + @classmethod + def username_field(cls): + return getattr(cls.user_model(), 'USERNAME_FIELD', 'username') + + @classmethod + def user_exists(cls, *args, **kwargs): + """ + Return True/False if a User instance exists with the given arguments. + Arguments are directly passed to filter() manager method. + """ + if 'username' in kwargs: + kwargs[cls.username_field()] = kwargs.pop('username') + return cls.user_model().objects.filter(*args, **kwargs).count() > 0 + + @classmethod + def get_username(cls, user): + return getattr(user, cls.username_field(), None) + + @classmethod + def create_user(cls, *args, **kwargs): + username_field = cls.username_field() + if 'username' in kwargs: + if username_field not in kwargs: + kwargs[username_field] = kwargs.pop('username') + else: + # If username_field is 'email' and there is no field named "username" + # then latest should be removed from kwargs. + try: + cls.user_model()._meta.get_field('username') + except FieldDoesNotExist: + kwargs.pop('username') + try: + if hasattr(transaction, 'atomic'): + # In Django versions that have an "atomic" transaction decorator / context + # manager, there's a transaction wrapped around this call. + # If the create fails below due to an IntegrityError, ensure that the transaction + # stays undamaged by wrapping the create in an atomic. + using = router.db_for_write(cls.user_model()) + with transaction.atomic(using=using): + user = cls.user_model().objects.create_user(*args, **kwargs) + else: + user = cls.user_model().objects.create_user(*args, **kwargs) + except IntegrityError: + # User might have been created on a different thread, try and find them. + # If we don't, re-raise the IntegrityError. + exc_info = sys.exc_info() + # If email comes in as None it won't get found in the get + if kwargs.get('email', True) is None: + kwargs['email'] = '' + try: + user = cls.user_model().objects.get(*args, **kwargs) + except cls.user_model().DoesNotExist: + six.reraise(*exc_info) + return user + + @classmethod + def get_user(cls, pk=None, **kwargs): + if pk: + kwargs = {'pk': pk} + try: + return cls.user_model().objects.get(**kwargs) + except cls.user_model().DoesNotExist: + return None + + @classmethod + def get_users_by_email(cls, email): + user_model = cls.user_model() + email_field = getattr(user_model, 'EMAIL_FIELD', 'email') + return user_model.objects.filter(**{email_field + '__iexact': email}) + + @classmethod + def get_social_auth(cls, provider, uid): + if not isinstance(uid, six.string_types): + uid = str(uid) + try: + return cls.objects.get(provider=provider, uid=uid) + except cls.DoesNotExist: + return None + + @classmethod + def get_social_auth_for_user(cls, user, provider=None, id=None): + qs = cls.objects.filter(user=user) + + if provider: + qs = qs.filter(provider=provider) + + if id: + qs = qs.filter(id=id) + return qs + + @classmethod + def create_social_auth(cls, user, uid, provider): + if not isinstance(uid, six.string_types): + uid = str(uid) + if hasattr(transaction, 'atomic'): + # In Django versions that have an "atomic" transaction decorator / context + # manager, there's a transaction wrapped around this call. + # If the create fails below due to an IntegrityError, ensure that the transaction + # stays undamaged by wrapping the create in an atomic. + using = router.db_for_write(cls) + with transaction.atomic(using=using): + social_auth = cls.objects.create(user=user, uid=uid, provider=provider) + else: + social_auth = cls.objects.create(user=user, uid=uid, provider=provider) + return social_auth + + +class DjangoNonceMixin(NonceMixin): + @classmethod + def use(cls, server_url, timestamp, salt): + return cls.objects.get_or_create(server_url=server_url, + timestamp=timestamp, + salt=salt)[1] + + @classmethod + def get(cls, server_url, salt): + return cls.objects.get( + server_url=server_url, + salt=salt, + ) + + @classmethod + def delete(cls, nonce): + nonce.delete() + + +class DjangoAssociationMixin(AssociationMixin): + @classmethod + def store(cls, server_url, association): + # Don't use get_or_create because issued cannot be null + try: + assoc = cls.objects.get(server_url=server_url, + handle=association.handle) + except cls.DoesNotExist: + assoc = cls(server_url=server_url, + handle=association.handle) + + try: + assoc.secret = base64.encodebytes(association.secret).decode() + except AttributeError: + assoc.secret = base64.encodestring(association.secret).decode() + assoc.issued = association.issued + assoc.lifetime = association.lifetime + assoc.assoc_type = association.assoc_type + assoc.save() + + @classmethod + def get(cls, *args, **kwargs): + return cls.objects.filter(*args, **kwargs) + + @classmethod + def remove(cls, ids_to_delete): + cls.objects.filter(pk__in=ids_to_delete).delete() + + +class DjangoCodeMixin(CodeMixin): + @classmethod + def get_code(cls, code): + try: + return cls.objects.get(code=code) + except cls.DoesNotExist: + return None + + +class DjangoPartialMixin(PartialMixin): + @classmethod + def load(cls, token): + try: + return cls.objects.get(token=token) + except cls.DoesNotExist: + return None + + @classmethod + def destroy(cls, token): + partial = cls.load(token) + if partial: + partial.delete() + + +class BaseDjangoStorage(BaseStorage): + user = DjangoUserMixin + nonce = DjangoNonceMixin + association = DjangoAssociationMixin + code = DjangoCodeMixin diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/strategy.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/strategy.py new file mode 100644 index 0000000000000000000000000000000000000000..d5d8d1bc48f61915c87ca8b752d38ea5b3063565 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/strategy.py @@ -0,0 +1,157 @@ +# coding=utf-8 +from django.conf import settings +from django.http import HttpResponse, HttpRequest +from django.db.models import Model +from django.contrib.contenttypes.models import ContentType +from django.contrib.auth import authenticate +from django.shortcuts import redirect, resolve_url +from django.template import TemplateDoesNotExist, loader, engines +from django.utils.crypto import get_random_string +from django.utils.encoding import force_text +from django.utils.functional import Promise +from django.utils.translation import get_language + +from social_core.strategy import BaseStrategy, BaseTemplateStrategy +from .compat import get_request_port + + +def render_template_string(request, html, context=None): + """Take a template in the form of a string and render it for the + given context""" + template = engines['django'].from_string(html) + return template.render(context=context, request=request) + + +class DjangoTemplateStrategy(BaseTemplateStrategy): + def render_template(self, tpl, context): + template = loader.get_template(tpl) + return template.render(context=context, request=self.strategy.request) + + def render_string(self, html, context): + return render_template_string(self.strategy.request, html, context) + + +class DjangoStrategy(BaseStrategy): + DEFAULT_TEMPLATE_STRATEGY = DjangoTemplateStrategy + + def __init__(self, storage, request=None, tpl=None): + self.request = request + self.session = request.session if request else {} + super(DjangoStrategy, self).__init__(storage, tpl) + + def get_setting(self, name): + value = getattr(settings, name) + # Force text on URL named settings that are instance of Promise + if name.endswith('_URL'): + if isinstance(value, Promise): + value = force_text(value) + value = resolve_url(value) + return value + + def request_data(self, merge=True): + if not self.request: + return {} + if merge: + data = self.request.GET.copy() + data.update(self.request.POST) + elif self.request.method == 'POST': + data = self.request.POST + else: + data = self.request.GET + return data + + def request_host(self): + if self.request: + return self.request.get_host() + + def request_is_secure(self): + """Is the request using HTTPS?""" + return self.request.is_secure() + + def request_path(self): + """path of the current request""" + return self.request.path + + def request_port(self): + """Port in use for this request""" + return get_request_port(request=self.request) + + def request_get(self): + """Request GET data""" + return self.request.GET.copy() + + def request_post(self): + """Request POST data""" + return self.request.POST.copy() + + def redirect(self, url): + return redirect(url) + + def html(self, content): + return HttpResponse(content, content_type='text/html;charset=UTF-8') + + def render_html(self, tpl=None, html=None, context=None): + if not tpl and not html: + raise ValueError('Missing template or html parameters') + context = context or {} + try: + template = loader.get_template(tpl) + return template.render(context=context, request=self.request) + except (TypeError, TemplateDoesNotExist): + return render_template_string(self.request, html, context) + + def authenticate(self, backend, *args, **kwargs): + kwargs['strategy'] = self + kwargs['storage'] = self.storage + kwargs['backend'] = backend + return authenticate(*args, **kwargs) + + def clean_authenticate_args(self, request, *args, **kwargs): + # pipelines don't want a positional request argument + kwargs['request'] = request + return args, kwargs + + def session_get(self, name, default=None): + return self.session.get(name, default) + + def session_set(self, name, value): + self.session[name] = value + if hasattr(self.session, 'modified'): + self.session.modified = True + + def session_pop(self, name): + return self.session.pop(name, None) + + def session_setdefault(self, name, value): + return self.session.setdefault(name, value) + + def build_absolute_uri(self, path=None): + if self.request: + return self.request.build_absolute_uri(path) + else: + return path + + def random_string(self, length=12, chars=BaseStrategy.ALLOWED_CHARS): + return get_random_string(length, chars) + + def to_session_value(self, val): + """Converts values that are instance of Model to a dictionary + with enough information to retrieve the instance back later.""" + if isinstance(val, Model): + val = { + 'pk': val.pk, + 'ctype': ContentType.objects.get_for_model(val).pk + } + return val + + def from_session_value(self, val): + """Converts back the instance saved by self._ctype function.""" + if isinstance(val, dict) and 'pk' in val and 'ctype' in val: + ctype = ContentType.objects.get_for_id(val['ctype']) + ModelClass = ctype.model_class() + val = ModelClass.objects.get(pk=val['pk']) + return val + + def get_language(self): + """Return current language""" + return get_language() diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/urls.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..68a07c7273906d2f94236d634d0ed0eac9ba91c0 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/urls.py @@ -0,0 +1,24 @@ +"""URLs module""" +from django.conf import settings +from django.conf.urls import url + +from social_core.utils import setting_name +from . import views + + +extra = getattr(settings, setting_name('TRAILING_SLASH'), True) and '/' or '' + +app_name = 'social' + +urlpatterns = [ + # authentication / association + url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth, + name='begin'), + url(r'^complete/(?P<backend>[^/]+){0}$'.format(extra), views.complete, + name='complete'), + # disconnection + url(r'^disconnect/(?P<backend>[^/]+){0}$'.format(extra), views.disconnect, + name='disconnect'), + url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>\d+){0}$' + .format(extra), views.disconnect, name='disconnect_individual'), +] diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/utils.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..281bdd49f6e26f1b1251a7a53dd597c15ef550a5 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/utils.py @@ -0,0 +1,51 @@ +# coding=utf-8 +from functools import wraps + +from django.conf import settings +from django.http import Http404 + +from social_core.utils import setting_name, module_member, get_strategy +from social_core.exceptions import MissingBackend +from social_core.backends.utils import get_backend +from .compat import reverse + + +BACKENDS = settings.AUTHENTICATION_BACKENDS +STRATEGY = getattr(settings, setting_name('STRATEGY'), + 'social_django.strategy.DjangoStrategy') +STORAGE = getattr(settings, setting_name('STORAGE'), + 'social_django.models.DjangoStorage') +Strategy = module_member(STRATEGY) +Storage = module_member(STORAGE) + + +def load_strategy(request=None): + return get_strategy(STRATEGY, STORAGE, request) + + +def load_backend(strategy, name, redirect_uri): + Backend = get_backend(BACKENDS, name) + return Backend(strategy, redirect_uri) + + +def psa(redirect_uri=None, load_strategy=load_strategy): + def decorator(func): + @wraps(func) + def wrapper(request, backend, *args, **kwargs): + uri = redirect_uri + if uri and not uri.startswith('/'): + uri = reverse(redirect_uri, args=(backend,)) + request.social_strategy = load_strategy(request) + # backward compatibility in attribute name, only if not already + # defined + if not hasattr(request, 'strategy'): + request.strategy = request.social_strategy + + try: + request.backend = load_backend(request.social_strategy, + backend, uri) + except MissingBackend: + raise Http404('Backend not found') + return func(request, backend, *args, **kwargs) + return wrapper + return decorator diff --git a/Latest_Group_Project/.venv/Lib/site-packages/social_django/views.py b/Latest_Group_Project/.venv/Lib/site-packages/social_django/views.py new file mode 100644 index 0000000000000000000000000000000000000000..30db2f1bb691529fcc00b2ded11593ed7278d88b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/social_django/views.py @@ -0,0 +1,129 @@ +from django.conf import settings +from django.contrib.auth import login, REDIRECT_FIELD_NAME +from django.contrib.auth.decorators import login_required +from django.views.decorators.csrf import csrf_exempt, csrf_protect +from django.views.decorators.http import require_POST +from django.views.decorators.cache import never_cache + +from social_core.utils import setting_name +from social_core.actions import do_auth, do_complete, do_disconnect +from .utils import psa + + +NAMESPACE = getattr(settings, setting_name('URL_NAMESPACE'), None) or 'social' + +# Calling `session.set_expiry(None)` results in a session lifetime equal to +# platform default session lifetime. +DEFAULT_SESSION_TIMEOUT = None + + +@never_cache +@psa('{0}:complete'.format(NAMESPACE)) +def auth(request, backend): + return do_auth(request.backend, redirect_name=REDIRECT_FIELD_NAME) + + +@never_cache +@csrf_exempt +@psa('{0}:complete'.format(NAMESPACE)) +def complete(request, backend, *args, **kwargs): + """Authentication complete view""" + return do_complete(request.backend, _do_login, user=request.user, + redirect_name=REDIRECT_FIELD_NAME, request=request, + *args, **kwargs) + + +@never_cache +@login_required +@psa() +@require_POST +@csrf_protect +def disconnect(request, backend, association_id=None): + """Disconnects given backend from current logged in user.""" + return do_disconnect(request.backend, request.user, association_id, + redirect_name=REDIRECT_FIELD_NAME) + + +def get_session_timeout(social_user, enable_session_expiration=False, + max_session_length=None): + if enable_session_expiration: + # Retrieve an expiration date from the social user who just finished + # logging in; this value was set by the social auth backend, and was + # typically received from the server. + expiration = social_user.expiration_datetime() + + # We've enabled session expiration. Check to see if we got + # a specific expiration time from the provider for this user; + # if not, use the platform default expiration. + if expiration: + received_expiration_time = expiration.total_seconds() + else: + received_expiration_time = DEFAULT_SESSION_TIMEOUT + + # Check to see if the backend set a value as a maximum length + # that a session may be; if they did, then we should use the minimum + # of that and the received session expiration time, if any, to + # set the session length. + if received_expiration_time is None and max_session_length is None: + # We neither received an expiration length, nor have a maximum + # session length. Use the platform default. + session_expiry = DEFAULT_SESSION_TIMEOUT + elif received_expiration_time is None and max_session_length is not None: + # We only have a maximum session length; use that. + session_expiry = max_session_length + elif received_expiration_time is not None and max_session_length is None: + # We only have an expiration time received by the backend + # from the provider, with no set maximum. Use that. + session_expiry = received_expiration_time + else: + # We received an expiration time from the backend, and we also + # have a set maximum session length. Use the smaller of the two. + session_expiry = min(received_expiration_time, max_session_length) + else: + # If there's an explicitly-set maximum session length, use that + # even if we don't want to retrieve session expiry times from + # the backend. If there isn't, then use the platform default. + if max_session_length is None: + session_expiry = DEFAULT_SESSION_TIMEOUT + else: + session_expiry = max_session_length + + return session_expiry + + +def _do_login(backend, user, social_user): + user.backend = '{0}.{1}'.format(backend.__module__, + backend.__class__.__name__) + # Get these details early to avoid any issues involved in the + # session switch that happens when we call login(). + enable_session_expiration = backend.setting('SESSION_EXPIRATION', False) + max_session_length_setting = backend.setting('MAX_SESSION_LENGTH', None) + + # Log the user in, creating a new session. + login(backend.strategy.request, user) + + # Make sure that the max_session_length value is either an integer or + # None. Because we get this as a setting from the backend, it can be set + # to whatever the backend creator wants; we want to be resilient against + # unexpected types being presented to us. + try: + max_session_length = int(max_session_length_setting) + except (TypeError, ValueError): + # We got a response that doesn't look like a number; use the default. + max_session_length = None + + # Get the session expiration length based on the maximum session length + # setting, combined with any session length received from the backend. + session_expiry = get_session_timeout( + social_user, + enable_session_expiration=enable_session_expiration, + max_session_length=max_session_length, + ) + + try: + # Set the session length to our previously determined expiry length. + backend.strategy.request.session.set_expiry(session_expiry) + except OverflowError: + # The timestamp we used wasn't in the range of values supported by + # Django for session length; use the platform default. We tried. + backend.strategy.request.session.set_expiry(DEFAULT_SESSION_TIMEOUT) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b69bce45ae66b63ed282a0d5de1f8514375d4883 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/mail.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/mail.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93075910448b57e73d516a8d684e46bd18431f7b Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/__pycache__/mail.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/mail.py b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/mail.py new file mode 100644 index 0000000000000000000000000000000000000000..43d18d0ad1bb23ff7f5e574e25f29dbfba1fec7b --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/templated_mail/mail.py @@ -0,0 +1,90 @@ +from django.conf import settings +from django.contrib.sites.shortcuts import get_current_site +from django.core import mail +from django.template.context import make_context +from django.template.loader import get_template +from django.views.generic.base import ContextMixin + + +class BaseEmailMessage(mail.EmailMultiAlternatives, ContextMixin): + _node_map = { + 'subject': 'subject', + 'text_body': 'body', + 'html_body': 'html', + } + template_name = None + + def __init__(self, request=None, context=None, template_name=None, + *args, **kwargs): + super(BaseEmailMessage, self).__init__(*args, **kwargs) + + self.request = request + self.context = {} if context is None else context + self.html = None + + if template_name is not None: + self.template_name = template_name + + def get_context_data(self, **kwargs): + ctx = super(BaseEmailMessage, self).get_context_data(**kwargs) + context = dict(ctx, **self.context) + if self.request: + site = get_current_site(self.request) + domain = context.get('domain') or ( + getattr(settings, 'DOMAIN', '') or site.domain + ) + protocol = context.get('protocol') or ( + 'https' if self.request.is_secure() else 'http' + ) + site_name = context.get('site_name') or ( + getattr(settings, 'SITE_NAME', '') or site.name + ) + user = context.get('user') or self.request.user + else: + domain = context.get('domain') or getattr(settings, 'DOMAIN', '') + protocol = context.get('protocol') or 'http' + site_name = context.get('site_name') or getattr( + settings, 'SITE_NAME', '' + ) + user = context.get('user') + + context.update({ + 'domain': domain, + 'protocol': protocol, + 'site_name': site_name, + 'user': user + }) + return context + + def render(self): + context = make_context(self.get_context_data(), request=self.request) + template = get_template(self.template_name) + with context.bind_template(template.template): + for node in template.template.nodelist: + self._process_node(node, context) + self._attach_body() + + def send(self, to, *args, **kwargs): + self.render() + + self.to = to + self.cc = kwargs.pop('cc', []) + self.bcc = kwargs.pop('bcc', []) + self.reply_to = kwargs.pop('reply_to', []) + self.from_email = kwargs.pop( + 'from_email', settings.DEFAULT_FROM_EMAIL + ) + + super(BaseEmailMessage, self).send(*args, **kwargs) + + def _process_node(self, node, context): + attr = self._node_map.get(getattr(node, 'name', '')) + if attr is not None: + setattr(self, attr, node.render(context).strip()) + + def _attach_body(self): + if self.body and self.html: + self.attach_alternative(self.html, 'text/html') + elif self.html: + self.body = self.html + self.content_subtype = 'html' diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/INSTALLER b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/INSTALLER new file mode 100644 index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/LICENSE b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..41c87e7cf26b0f948798e79b1b882a0940fbcb32 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/LICENSE @@ -0,0 +1,3 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to uritemplate are +made under the terms of *both* these licenses. diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/METADATA b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/METADATA new file mode 100644 index 0000000000000000000000000000000000000000..97001a25579e955552a9d8999d70f4308b450fe4 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/METADATA @@ -0,0 +1,92 @@ +Metadata-Version: 2.1 +Name: uritemplate +Version: 4.1.1 +Summary: Implementation of RFC 6570 URI Templates +Home-page: https://uritemplate.readthedocs.org +Author: Ian Stapleton Cordasco +Author-email: graffatcolmingov@gmail.com +License: BSD 3-Clause License or Apache License, Version 2.0 +Keywords: rfc 6570 uri template +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 :: Implementation :: CPython +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE + +uritemplate +=========== + +Documentation_ -- GitHub_ -- Travis-CI_ + +Simple python library to deal with `URI Templates`_. The API looks like + +.. code-block:: python + + from uritemplate import URITemplate, expand + + # NOTE: URI params must be strings not integers + + gist_uri = 'https://api.github.com/users/sigmavirus24/gists{/gist_id}' + t = URITemplate(gist_uri) + print(t.expand(gist_id='123456')) + # => https://api.github.com/users/sigmavirus24/gists/123456 + + # or + print(expand(gist_uri, gist_id='123456')) + + # also + t.expand({'gist_id': '123456'}) + print(expand(gist_uri, {'gist_id': '123456'})) + +Where it might be useful to have a class + +.. code-block:: python + + import requests + + class GitHubUser(object): + url = URITemplate('https://api.github.com/user{/login}') + def __init__(self, name): + self.api_url = url.expand(login=name) + response = requests.get(self.api_url) + if response.status_code == 200: + self.__dict__.update(response.json()) + +When the module containing this class is loaded, ``GitHubUser.url`` is +evaluated and so the template is created once. It's often hard to notice in +Python, but object creation can consume a great deal of time and so can the +``re`` module which uritemplate relies on. Constructing the object once should +reduce the amount of time your code takes to run. + +Installing +---------- + +:: + + pip install uritemplate + +License +------- + +Modified BSD license_ + + +.. _Documentation: https://uritemplate.readthedocs.io/ +.. _GitHub: https://github.com/python-hyper/uritemplate +.. _Travis-CI: https://travis-ci.org/python-hyper/uritemplate +.. _URI Templates: https://tools.ietf.org/html/rfc6570 +.. _license: https://github.com/python-hyper/uritemplate/blob/master/LICENSE + + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/RECORD b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/RECORD new file mode 100644 index 0000000000000000000000000000000000000000..0de1e3b8c7c59d7f695945cdca183cf406b80b19 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/RECORD @@ -0,0 +1,17 @@ +uritemplate-4.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +uritemplate-4.1.1.dist-info/LICENSE,sha256=PPyfAc3uySkA8ijPVnf_pX5-0wTEJjUyvK2cvZlp5Gw,196 +uritemplate-4.1.1.dist-info/METADATA,sha256=rotEEWL5rUie3gKyYHhxXqjdpYw16kLCT0Aw0bvta9o,2882 +uritemplate-4.1.1.dist-info/RECORD,, +uritemplate-4.1.1.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 +uritemplate-4.1.1.dist-info/top_level.txt,sha256=WJzkFEINWbgwuzuUEP8kD8Sk2fFHYQzBgrjO3viyubE,12 +uritemplate/__init__.py,sha256=toWdtJeaNWsftVzhDASD_2wwxkd84HdXg22rFwMkVkc,816 +uritemplate/__pycache__/__init__.cpython-310.pyc,, +uritemplate/__pycache__/api.cpython-310.pyc,, +uritemplate/__pycache__/orderedset.cpython-310.pyc,, +uritemplate/__pycache__/template.cpython-310.pyc,, +uritemplate/__pycache__/variable.cpython-310.pyc,, +uritemplate/api.py,sha256=eQ3DdgNNDlnoedSE-rQ5AQv8JvMzdljPX8l-187myfI,2305 +uritemplate/orderedset.py,sha256=4Z8u8uw339D_RWvbUslv5d6EnA2wxQC66317oTLzp0o,3367 +uritemplate/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uritemplate/template.py,sha256=qXcNZxcGPGxgQnaRDIafaKsrTnvBzplOBBPAM8Hbq7g,4774 +uritemplate/variable.py,sha256=HixfLuF7R3f7zwIQohB9cFVRVZsN_8Y2RIZDRHpNg40,12870 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/WHEEL b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/WHEEL new file mode 100644 index 0000000000000000000000000000000000000000..b733a60d379c60aef4921d7e42a113fdc28300dc --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/top_level.txt b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d76f010c2c1a70f504859f8ddd0ac637a8622d8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate-4.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +uritemplate diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__init__.py b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..65015c1a619acbe8461c06b35fa5e07babed6ac8 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__init__.py @@ -0,0 +1,35 @@ +""" + +uritemplate +=========== + +URI templates implemented as close to :rfc:`6570` as possible + +See http://uritemplate.rtfd.org/ for documentation + +:copyright: + (c) 2013 Ian Stapleton Cordasco +:license: + Modified BSD Apache License (Version 2.0), see LICENSE for more details + and either LICENSE.BSD or LICENSE.APACHE for the details of those specific + licenses + +""" + +__title__ = "uritemplate" +__author__ = "Ian Stapleton Cordasco" +__license__ = "Modified BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2013 Ian Stapleton Cordasco" +__version__ = "4.1.1" +__version_info__ = tuple( + int(i) for i in __version__.split(".") if i.isdigit() +) + +from uritemplate.api import ( + URITemplate, + expand, + partial, + variables, +) + +__all__ = ("URITemplate", "expand", "partial", "variables") diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/__init__.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23eb4b4024e416bf95244228b301fd78440ab393 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/__init__.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/api.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/api.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f548d10ce0110304369394792c933f3e25b43f1 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/api.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/orderedset.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/orderedset.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65743a3ffa6e39e6886d19414cc26a3cf3cd9ebb Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/orderedset.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/template.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/template.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05bdc493645acf814e766f788a210ebef5eb18b9 Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/template.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/variable.cpython-310.pyc b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/variable.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0846e58a76c2a70daae3d51da78353534a73fccd Binary files /dev/null and b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/__pycache__/variable.cpython-310.pyc differ diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/api.py b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/api.py new file mode 100644 index 0000000000000000000000000000000000000000..ac75473dd1510e4e4c443759bf541348db62aeae --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/api.py @@ -0,0 +1,85 @@ +""" + +uritemplate.api +=============== + +This module contains the very simple API provided by uritemplate. + +""" +import typing as t + +from uritemplate import variable +from uritemplate.orderedset import OrderedSet +from uritemplate.template import URITemplate + +__all__ = ("OrderedSet", "URITemplate", "expand", "partial", "variables") + + +def expand( + uri: str, + var_dict: t.Optional[variable.VariableValueDict] = None, + **kwargs: variable.VariableValue, +) -> str: + """Expand the template with the given parameters. + + :param str uri: The templated URI to expand + :param dict var_dict: Optional dictionary with variables and values + :param kwargs: Alternative way to pass arguments + :returns: str + + Example:: + + expand('https://api.github.com{/end}', {'end': 'users'}) + expand('https://api.github.com{/end}', end='gists') + + .. note:: Passing values by both parts, may override values in + ``var_dict``. For example:: + + expand('https://{var}', {'var': 'val1'}, var='val2') + + ``val2`` will be used instead of ``val1``. + + """ + return URITemplate(uri).expand(var_dict, **kwargs) + + +def partial( + uri: str, + var_dict: t.Optional[variable.VariableValueDict] = None, + **kwargs: variable.VariableValue, +) -> URITemplate: + """Partially expand the template with the given parameters. + + If all of the parameters for the template are not given, return a + partially expanded template. + + :param dict var_dict: Optional dictionary with variables and values + :param kwargs: Alternative way to pass arguments + :returns: :class:`URITemplate` + + Example:: + + t = URITemplate('https://api.github.com{/end}') + t.partial() # => URITemplate('https://api.github.com{/end}') + + """ + return URITemplate(uri).partial(var_dict, **kwargs) + + +def variables(uri: str) -> OrderedSet: + """Parse the variables of the template. + + This returns all of the variable names in the URI Template. + + :returns: Set of variable names + :rtype: set + + Example:: + + variables('https://api.github.com{/end}) + # => {'end'} + variables('https://api.github.com/repos{/username}{/repository}') + # => {'username', 'repository'} + + """ + return OrderedSet(URITemplate(uri).variable_names) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/orderedset.py b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/orderedset.py new file mode 100644 index 0000000000000000000000000000000000000000..dd7cd1a5867d472fdae1cd065b7586c2f17a22c2 --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/orderedset.py @@ -0,0 +1,92 @@ +# From: https://github.com/ActiveState/code/blob/master/recipes/Python/576696_OrderedSet_with_Weakrefs/ # noqa +import typing as t +import weakref + + +class Link: + """Representation of one item in a doubly-linked list.""" + + __slots__ = ("prev", "next", "key", "__weakref__") + prev: "Link" + next: "Link" + key: str + + +class OrderedSet(t.MutableSet[str]): + """A set that remembers the order in which items were added.""" + + # Big-O running times for all methods are the same as for regular sets. + # The internal self.__map dictionary maps keys to links in a doubly linked + # list. The circular doubly linked list starts and ends with a sentinel + # element. The sentinel element never gets deleted (this simplifies the + # algorithm). The prev/next links are weakref proxies (to prevent circular + # references). Individual links are kept alive by the hard reference in + # self.__map. Those hard references disappear when a key is deleted from + # an OrderedSet. + + def __init__(self, iterable: t.Optional[t.Iterable[str]] = None): + self.__root = root = Link() # sentinel node for doubly linked list + root.prev = root.next = root + self.__map: t.MutableMapping[str, Link] = {} # key --> link + if iterable is not None: + self |= iterable # type: ignore + + def __len__(self) -> int: + return len(self.__map) + + def __contains__(self, key: object) -> bool: + return key in self.__map + + def add(self, key: str) -> None: + # Store new key in a new link at the end of the linked list + if key not in self.__map: + self.__map[key] = link = Link() + root = self.__root + last = root.prev + link.prev, link.next, link.key = last, root, key + last.next = root.prev = weakref.proxy(link) + + def discard(self, key: str) -> None: + # Remove an existing item using self.__map to find the link which is + # then removed by updating the links in the predecessor and successors. + if key in self.__map: + link = self.__map.pop(key) + link.prev.next = link.next + link.next.prev = link.prev + + def __iter__(self) -> t.Generator[str, None, None]: + # Traverse the linked list in order. + root = self.__root + curr = root.next + while curr is not root: + yield curr.key + curr = curr.next + + def __reversed__(self) -> t.Generator[str, None, None]: + # Traverse the linked list in reverse order. + root = self.__root + curr = root.prev + while curr is not root: + yield curr.key + curr = curr.prev + + def pop(self, last: bool = True) -> str: + if not self: + raise KeyError("set is empty") + key = next(reversed(self)) if last else next(iter(self)) + self.discard(key) + return key + + def __repr__(self) -> str: + if not self: + return f"{self.__class__.__name__}()" + return f"{self.__class__.__name__}({list(self)!r})" + + def __str__(self) -> str: + return self.__repr__() + + def __eq__(self, other: object) -> bool: + if isinstance(other, OrderedSet): + return len(self) == len(other) and list(self) == list(other) + other = t.cast(t.Iterable[str], other) + return not self.isdisjoint(other) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/py.typed b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/template.py b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/template.py new file mode 100644 index 0000000000000000000000000000000000000000..73ef89c93ca169c60fa6b4029ea5e5b4c6db05bb --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/template.py @@ -0,0 +1,169 @@ +""" + +uritemplate.template +==================== + +This module contains the essential inner workings of uritemplate. + +What treasures await you: + +- URITemplate class + +You see a treasure chest of knowledge in front of you. +What do you do? +> + +""" +import re +import typing as t + +from uritemplate import orderedset +from uritemplate import variable + +template_re = re.compile("{([^}]+)}") + + +def _merge( + var_dict: t.Optional[variable.VariableValueDict], + overrides: variable.VariableValueDict, +) -> variable.VariableValueDict: + if var_dict: + opts = var_dict.copy() + opts.update(overrides) + return opts + return overrides + + +class URITemplate: + + """This parses the template and will be used to expand it. + + This is the most important object as the center of the API. + + Example:: + + from uritemplate import URITemplate + import requests + + + t = URITemplate( + 'https://api.github.com/users/sigmavirus24/gists{/gist_id}' + ) + uri = t.expand(gist_id=123456) + resp = requests.get(uri) + for gist in resp.json(): + print(gist['html_url']) + + Please note:: + + str(t) + # 'https://api.github.com/users/sigmavirus24/gists{/gistid}' + repr(t) # is equivalent to + # URITemplate(str(t)) + # Where str(t) is interpreted as the URI string. + + Also, ``URITemplates`` are hashable so they can be used as keys in + dictionaries. + + """ + + def __init__(self, uri: str): + #: The original URI to be parsed. + self.uri: str = uri + #: A list of the variables in the URI. They are stored as + #: :class:`~uritemplate.variable.URIVariable`\ s + self.variables: t.List[variable.URIVariable] = [ + variable.URIVariable(m.groups()[0]) + for m in template_re.finditer(self.uri) + ] + #: A set of variable names in the URI. + self.variable_names = orderedset.OrderedSet() + for var in self.variables: + for name in var.variable_names: + self.variable_names.add(name) + + def __repr__(self) -> str: + return 'URITemplate("%s")' % self + + def __str__(self) -> str: + return self.uri + + def __eq__(self, other: object) -> bool: + if not isinstance(other, URITemplate): + return NotImplemented + return self.uri == other.uri + + def __hash__(self) -> int: + return hash(self.uri) + + def _expand( + self, var_dict: variable.VariableValueDict, replace: bool + ) -> str: + if not self.variables: + return self.uri + + expansion = var_dict + expanded: t.Dict[str, str] = {} + for v in self.variables: + expanded.update(v.expand(expansion)) + + def replace_all(match: "re.Match[str]") -> str: + return expanded.get(match.groups()[0], "") + + def replace_partial(match: "re.Match[str]") -> str: + match_group = match.groups()[0] + var = "{%s}" % match_group + return expanded.get(match_group) or var + + replace_func = replace_partial if replace else replace_all + + return template_re.sub(replace_func, self.uri) + + def expand( + self, + var_dict: t.Optional[variable.VariableValueDict] = None, + **kwargs: variable.VariableValue, + ) -> str: + """Expand the template with the given parameters. + + :param dict var_dict: Optional dictionary with variables and values + :param kwargs: Alternative way to pass arguments + :returns: str + + Example:: + + t = URITemplate('https://api.github.com{/end}') + t.expand({'end': 'users'}) + t.expand(end='gists') + + .. note:: Passing values by both parts, may override values in + ``var_dict``. For example:: + + expand('https://{var}', {'var': 'val1'}, var='val2') + + ``val2`` will be used instead of ``val1``. + + """ + return self._expand(_merge(var_dict, kwargs), False) + + def partial( + self, + var_dict: t.Optional[variable.VariableValueDict] = None, + **kwargs: variable.VariableValue, + ) -> "URITemplate": + """Partially expand the template with the given parameters. + + If all of the parameters for the template are not given, return a + partially expanded template. + + :param dict var_dict: Optional dictionary with variables and values + :param kwargs: Alternative way to pass arguments + :returns: :class:`URITemplate` + + Example:: + + t = URITemplate('https://api.github.com{/end}') + t.partial() # => URITemplate('https://api.github.com{/end}') + + """ + return URITemplate(self._expand(_merge(var_dict, kwargs), True)) diff --git a/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/variable.py b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/variable.py new file mode 100644 index 0000000000000000000000000000000000000000..da406cab262cf6065dd32e1ca2ebd2dde231823d --- /dev/null +++ b/Latest_Group_Project/.venv/Lib/site-packages/uritemplate/variable.py @@ -0,0 +1,419 @@ +""" + +uritemplate.variable +==================== + +This module contains the URIVariable class which powers the URITemplate class. + +What treasures await you: + +- URIVariable class + +You see a hammer in front of you. +What do you do? +> + +""" +import collections.abc +import typing as t +import urllib.parse + +ScalarVariableValue = t.Union[int, float, complex, str] +VariableValue = t.Union[ + t.Sequence[ScalarVariableValue], + t.Mapping[str, ScalarVariableValue], + t.Tuple[str, ScalarVariableValue], + ScalarVariableValue, +] +VariableValueDict = t.Dict[str, VariableValue] + + +class URIVariable: + + """This object validates everything inside the URITemplate object. + + It validates template expansions and will truncate length as decided by + the template. + + Please note that just like the :class:`URITemplate <URITemplate>`, this + object's ``__str__`` and ``__repr__`` methods do not return the same + information. Calling ``str(var)`` will return the original variable. + + This object does the majority of the heavy lifting. The ``URITemplate`` + object finds the variables in the URI and then creates ``URIVariable`` + objects. Expansions of the URI are handled by each ``URIVariable`` + object. ``URIVariable.expand()`` returns a dictionary of the original + variable and the expanded value. Check that method's documentation for + more information. + + """ + + operators = ("+", "#", ".", "/", ";", "?", "&", "|", "!", "@") + reserved = ":/?#[]@!$&'()*+,;=" + + def __init__(self, var: str): + #: The original string that comes through with the variable + self.original: str = var + #: The operator for the variable + self.operator: str = "" + #: List of safe characters when quoting the string + self.safe: str = "" + #: List of variables in this variable + self.variables: t.List[ + t.Tuple[str, t.MutableMapping[str, t.Any]] + ] = [] + #: List of variable names + self.variable_names: t.List[str] = [] + #: List of defaults passed in + self.defaults: t.MutableMapping[str, ScalarVariableValue] = {} + # Parse the variable itself. + self.parse() + self.post_parse() + + def __repr__(self) -> str: + return "URIVariable(%s)" % self + + def __str__(self) -> str: + return self.original + + def parse(self) -> None: + """Parse the variable. + + This finds the: + - operator, + - set of safe characters, + - variables, and + - defaults. + + """ + var_list_str = self.original + if self.original[0] in URIVariable.operators: + self.operator = self.original[0] + var_list_str = self.original[1:] + + if self.operator in URIVariable.operators[:2]: + self.safe = URIVariable.reserved + + var_list = var_list_str.split(",") + + for var in var_list: + default_val = None + name = var + if "=" in var: + name, default_val = tuple(var.split("=", 1)) + + explode = False + if name.endswith("*"): + explode = True + name = name[:-1] + + prefix: t.Optional[int] = None + if ":" in name: + name, prefix_str = tuple(name.split(":", 1)) + prefix = int(prefix_str) + + if default_val: + self.defaults[name] = default_val + + self.variables.append( + (name, {"explode": explode, "prefix": prefix}) + ) + + self.variable_names = [varname for (varname, _) in self.variables] + + def post_parse(self) -> None: + """Set ``start``, ``join_str`` and ``safe`` attributes. + + After parsing the variable, we need to set up these attributes and it + only makes sense to do it in a more easily testable way. + """ + self.safe = "" + self.start = self.join_str = self.operator + if self.operator == "+": + self.start = "" + if self.operator in ("+", "#", ""): + self.join_str = "," + if self.operator == "#": + self.start = "#" + if self.operator == "?": + self.start = "?" + self.join_str = "&" + + if self.operator in ("+", "#"): + self.safe = URIVariable.reserved + + def _query_expansion( + self, + name: str, + value: VariableValue, + explode: bool, + prefix: t.Optional[int], + ) -> t.Optional[str]: + """Expansion method for the '?' and '&' operators.""" + if value is None: + return None + + tuples, items = is_list_of_tuples(value) + + safe = self.safe + if list_test(value) and not tuples: + if not value: + return None + value = t.cast(t.Sequence[ScalarVariableValue], value) + if explode: + return self.join_str.join( + f"{name}={quote(v, safe)}" for v in value + ) + else: + value = ",".join(quote(v, safe) for v in value) + return f"{name}={value}" + + if dict_test(value) or tuples: + if not value: + return None + value = t.cast(t.Mapping[str, ScalarVariableValue], value) + items = items or sorted(value.items()) + if explode: + return self.join_str.join( + f"{quote(k, safe)}={quote(v, safe)}" for k, v in items + ) + else: + value = ",".join( + f"{quote(k, safe)},{quote(v, safe)}" for k, v in items + ) + return f"{name}={value}" + + if value: + value = t.cast(t.Text, value) + value = value[:prefix] if prefix else value + return f"{name}={quote(value, safe)}" + return name + "=" + + def _label_path_expansion( + self, + name: str, + value: VariableValue, + explode: bool, + prefix: t.Optional[int], + ) -> t.Optional[str]: + """Label and path expansion method. + + Expands for operators: '/', '.' + + """ + join_str = self.join_str + safe = self.safe + + if value is None or ( + not isinstance(value, (str, int, float, complex)) + and len(value) == 0 + ): + return None + + tuples, items = is_list_of_tuples(value) + + if list_test(value) and not tuples: + if not explode: + join_str = "," + + value = t.cast(t.Sequence[ScalarVariableValue], value) + fragments = [quote(v, safe) for v in value if v is not None] + return join_str.join(fragments) if fragments else None + + if dict_test(value) or tuples: + value = t.cast(t.Mapping[str, ScalarVariableValue], value) + items = items or sorted(value.items()) + format_str = "%s=%s" + if not explode: + format_str = "%s,%s" + join_str = "," + + expanded = join_str.join( + format_str % (quote(k, safe), quote(v, safe)) + for k, v in items + if v is not None + ) + return expanded if expanded else None + + value = t.cast(t.Text, value) + value = value[:prefix] if prefix else value + return quote(value, safe) + + def _semi_path_expansion( + self, + name: str, + value: VariableValue, + explode: bool, + prefix: t.Optional[int], + ) -> t.Optional[str]: + """Expansion method for ';' operator.""" + join_str = self.join_str + safe = self.safe + + if value is None: + return None + + if self.operator == "?": + join_str = "&" + + tuples, items = is_list_of_tuples(value) + + if list_test(value) and not tuples: + value = t.cast(t.Sequence[ScalarVariableValue], value) + if explode: + expanded = join_str.join( + f"{name}={quote(v, safe)}" for v in value if v is not None + ) + return expanded if expanded else None + else: + value = ",".join(quote(v, safe) for v in value) + return f"{name}={value}" + + if dict_test(value) or tuples: + value = t.cast(t.Mapping[str, ScalarVariableValue], value) + items = items or sorted(value.items()) + + if explode: + return join_str.join( + f"{quote(k, safe)}={quote(v, safe)}" + for k, v in items + if v is not None + ) + else: + expanded = ",".join( + f"{quote(k, safe)},{quote(v, safe)}" + for k, v in items + if v is not None + ) + return f"{name}={expanded}" + + value = t.cast(t.Text, value) + value = value[:prefix] if prefix else value + if value: + return f"{name}={quote(value, safe)}" + + return name + + def _string_expansion( + self, + name: str, + value: VariableValue, + explode: bool, + prefix: t.Optional[int], + ) -> t.Optional[str]: + if value is None: + return None + + tuples, items = is_list_of_tuples(value) + + if list_test(value) and not tuples: + value = t.cast(t.Sequence[ScalarVariableValue], value) + return ",".join(quote(v, self.safe) for v in value) + + if dict_test(value) or tuples: + value = t.cast(t.Mapping[str, ScalarVariableValue], value) + items = items or sorted(value.items()) + format_str = "%s=%s" if explode else "%s,%s" + + return ",".join( + format_str % (quote(k, self.safe), quote(v, self.safe)) + for k, v in items + ) + + value = t.cast(t.Text, value) + value = value[:prefix] if prefix else value + return quote(value, self.safe) + + def expand( + self, var_dict: t.Optional[VariableValueDict] = None + ) -> t.Mapping[str, str]: + """Expand the variable in question. + + Using ``var_dict`` and the previously parsed defaults, expand this + variable and subvariables. + + :param dict var_dict: dictionary of key-value pairs to be used during + expansion + :returns: dict(variable=value) + + Examples:: + + # (1) + v = URIVariable('/var') + expansion = v.expand({'var': 'value'}) + print(expansion) + # => {'/var': '/value'} + + # (2) + v = URIVariable('?var,hello,x,y') + expansion = v.expand({'var': 'value', 'hello': 'Hello World!', + 'x': '1024', 'y': '768'}) + print(expansion) + # => {'?var,hello,x,y': + # '?var=value&hello=Hello%20World%21&x=1024&y=768'} + + """ + return_values = [] + if var_dict is None: + return {self.original: self.original} + + for name, opts in self.variables: + value = var_dict.get(name, None) + if not value and value != "" and name in self.defaults: + value = self.defaults[name] + + if value is None: + continue + + expanded = None + if self.operator in ("/", "."): + expansion = self._label_path_expansion + elif self.operator in ("?", "&"): + expansion = self._query_expansion + elif self.operator == ";": + expansion = self._semi_path_expansion + else: + expansion = self._string_expansion + + expanded = expansion(name, value, opts["explode"], opts["prefix"]) + + if expanded is not None: + return_values.append(expanded) + + value = "" + if return_values: + value = self.start + self.join_str.join(return_values) + return {self.original: value} + + +def is_list_of_tuples( + value: t.Any, +) -> t.Tuple[bool, t.Optional[t.Sequence[t.Tuple[str, ScalarVariableValue]]]]: + if ( + not value + or not isinstance(value, (list, tuple)) + or not all(isinstance(t, tuple) and len(t) == 2 for t in value) + ): + return False, None + + return True, value + + +def list_test(value: t.Any) -> bool: + return isinstance(value, (list, tuple)) + + +def dict_test(value: t.Any) -> bool: + return isinstance(value, (dict, collections.abc.MutableMapping)) + + +def _encode(value: t.AnyStr, encoding: str = "utf-8") -> bytes: + if isinstance(value, str): + return value.encode(encoding) + return value + + +def quote(value: t.Any, safe: str) -> str: + if not isinstance(value, (str, bytes)): + value = str(value) + return urllib.parse.quote(_encode(value), safe) diff --git a/Latest_Group_Project/Booking_System/__pycache__/forms.cpython-310.pyc b/Latest_Group_Project/Booking_System/__pycache__/forms.cpython-310.pyc index 800efc75e82026b5706eb6ab6d05dd7687f866e1..f1f077323363400423501e052fa1662d6438e02f 100644 Binary files a/Latest_Group_Project/Booking_System/__pycache__/forms.cpython-310.pyc and b/Latest_Group_Project/Booking_System/__pycache__/forms.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/__pycache__/models.cpython-310.pyc b/Latest_Group_Project/Booking_System/__pycache__/models.cpython-310.pyc index 3be9cec29a127e51ae34d9c2426aa79e3da2d847..52aeba6034118f02981f957cde72aa8100acee9b 100644 Binary files a/Latest_Group_Project/Booking_System/__pycache__/models.cpython-310.pyc and b/Latest_Group_Project/Booking_System/__pycache__/models.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/__pycache__/permissions.cpython-310.pyc b/Latest_Group_Project/Booking_System/__pycache__/permissions.cpython-310.pyc index 13e33c8acacf7e80f75ead5205239b28b9331149..4db2d5af5694ba9528138327569720a9650cab41 100644 Binary files a/Latest_Group_Project/Booking_System/__pycache__/permissions.cpython-310.pyc and b/Latest_Group_Project/Booking_System/__pycache__/permissions.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/__pycache__/urls.cpython-310.pyc b/Latest_Group_Project/Booking_System/__pycache__/urls.cpython-310.pyc index d269193b509a25beba23ad3ff832e17fbcf315a2..0525d997efe6fc9a36d147f828e50f62062de137 100644 Binary files a/Latest_Group_Project/Booking_System/__pycache__/urls.cpython-310.pyc and b/Latest_Group_Project/Booking_System/__pycache__/urls.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/__pycache__/views.cpython-310.pyc b/Latest_Group_Project/Booking_System/__pycache__/views.cpython-310.pyc index 9ebb34d842c56d33b063eefb64ee3b651ec0d200..810d48651b690f153350df9a08e92c23488f8a83 100644 Binary files a/Latest_Group_Project/Booking_System/__pycache__/views.cpython-310.pyc and b/Latest_Group_Project/Booking_System/__pycache__/views.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/forms.py b/Latest_Group_Project/Booking_System/forms.py index dd87a914856e82ffe43e2aa6868fdfd7b89e5af8..3ac6a82feee12e5721de5200c62a2ce310e2bc85 100644 --- a/Latest_Group_Project/Booking_System/forms.py +++ b/Latest_Group_Project/Booking_System/forms.py @@ -9,7 +9,7 @@ import datetime from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType - +from django.db.models import Q def check_screen_limit(value, screen): date = value.date() @@ -46,8 +46,6 @@ class ClubLoginForm(AuthenticationForm): } - - class StudentRegisterForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = CustomUser @@ -72,8 +70,6 @@ class FilmForm(forms.ModelForm): 'image': forms.ClearableFileInput(attrs={'class': 'form-control-file'}), } - - class ShowTimeForm(forms.ModelForm): film = forms.ModelChoiceField(queryset=Film.objects.all()) @@ -137,13 +133,20 @@ class EditScreenForm(forms.ModelForm): model = Screen fields = ['screen_number', 'seats'] +class EditShowingForm(forms.ModelForm): + class Meta: + model = ShowTime + fields = ['start_time','end_time', 'film', 'screen'] + widgets = { + 'film': forms.Select(attrs={'class': 'custom-select'}), + 'screen': forms.Select(attrs={'class': 'custom-select'}), + } class PaymentForm(forms.Form): cardholder_name = forms.CharField(max_length=100) card_number = forms.CharField(max_length=12) expiration_date = forms.CharField(max_length=7) cvv = forms.CharField(max_length=3) - amount = forms.DecimalField(max_digits=5, decimal_places=2, validators=[MinValueValidator(0), MaxValueValidator(100)]) def clean_card_number(self): card_number = self.cleaned_data['card_number'] @@ -200,7 +203,7 @@ class ContactForm(forms.ModelForm): class RepresentativeForm(forms.ModelForm): - password = forms.CharField(widget=forms.PasswordInput) + # password = forms.CharField(widget=forms.PasswordInput) class Meta: model = Representative @@ -218,8 +221,13 @@ class CreateStatementAccountForm(forms.ModelForm): def __init__(self, user, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['user'] = forms.ModelChoiceField(queryset=User.objects.filter(user_type__in=[3, 4]), initial=user) + self.fields['user'] = forms.ModelChoiceField(queryset=User.objects.filter(user_type__in=[3, 4]), initial=user, validators=[self.validate_user_has_no_accounts]) + def validate_user_has_no_accounts(self, value): + if Account.objects.filter(Q(student__user=value) | Q(club_rep__user=value)).exists(): + raise forms.ValidationError("This user already has an account.") + return value + def save(self, commit=True): account = super().save(commit=False) user = self.cleaned_data['user'] @@ -236,6 +244,7 @@ class CreateStatementAccountForm(forms.ModelForm): return account + class EditStatementAccountForm(forms.ModelForm): account_holder_name = forms.ChoiceField(choices=[], required=True) @@ -253,5 +262,6 @@ class EditStatementAccountForm(forms.ModelForm): class GuestTicketBookingForm(forms.Form): + child_tickets = forms.IntegerField(initial=0, min_value=0) adult_tickets = forms.IntegerField(initial=0, min_value=0) senior_tickets = forms.IntegerField(initial=0, min_value=0) \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/migrations/0001_initial.py b/Latest_Group_Project/Booking_System/migrations/0001_initial.py index 5d8fb1429190306d533c533fc6388884bf0b3815..7d45859f1967268b79f33944857767d0a2ad1fd6 100644 --- a/Latest_Group_Project/Booking_System/migrations/0001_initial.py +++ b/Latest_Group_Project/Booking_System/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.1.7 on 2023-03-25 18:49 +# Generated by Django 4.1.7 on 2023-03-27 20:15 from django.conf import settings import django.contrib.auth.models @@ -79,13 +79,23 @@ class Migration(migrations.Migration): ('title', models.CharField(max_length=200)), ('release_date', models.DateField()), ('description', models.TextField()), - ('age_rating', models.DecimalField(decimal_places=1, max_digits=3)), + ('age_rating', models.CharField(max_length=5)), ('image', models.ImageField(blank=True, null=True, upload_to='film_images/')), ('now_showing', models.BooleanField(default=True)), ('cast', models.ManyToManyField(blank=True, null=True, to='Booking_System.cast')), ('directors', models.ManyToManyField(blank=True, null=True, to='Booking_System.director')), ], ), + migrations.CreateModel( + name='Representative', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('date_of_birth', models.DateField()), + ('rep_number', models.CharField(blank=True, max_length=50, unique=True)), + ], + ), migrations.CreateModel( name='Screen', fields=[ @@ -153,17 +163,6 @@ class Migration(migrations.Migration): 'unique_together': {('screen', 'seat_number')}, }, ), - migrations.CreateModel( - name='Representative', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('first_name', models.CharField(max_length=50)), - ('last_name', models.CharField(max_length=50)), - ('date_of_birth', models.DateField()), - ('rep_number', models.CharField(blank=True, max_length=50, unique=True)), - ('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), migrations.CreateModel( name='PaymentDetail', fields=[ diff --git a/Latest_Group_Project/Booking_System/migrations/0002_alter_film_age_rating.py b/Latest_Group_Project/Booking_System/migrations/0002_alter_film_age_rating.py deleted file mode 100644 index ff9ba5f008b930ec06ad96f3689b7bb760587a5a..0000000000000000000000000000000000000000 --- a/Latest_Group_Project/Booking_System/migrations/0002_alter_film_age_rating.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.1.7 on 2023-03-25 19:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('Booking_System', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='film', - name='age_rating', - field=models.IntegerField(), - ), - ] diff --git a/Latest_Group_Project/Booking_System/migrations/0003_alter_film_age_rating.py b/Latest_Group_Project/Booking_System/migrations/0003_alter_film_age_rating.py deleted file mode 100644 index 2f035909e4bd81d9cbc692a767d5bb293a902f4a..0000000000000000000000000000000000000000 --- a/Latest_Group_Project/Booking_System/migrations/0003_alter_film_age_rating.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.1.7 on 2023-03-25 19:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('Booking_System', '0002_alter_film_age_rating'), - ] - - operations = [ - migrations.AlterField( - model_name='film', - name='age_rating', - field=models.CharField(max_length=5), - ), - ] diff --git a/Latest_Group_Project/Booking_System/migrations/__pycache__/0001_initial.cpython-310.pyc b/Latest_Group_Project/Booking_System/migrations/__pycache__/0001_initial.cpython-310.pyc index 98dd06e3083edbd005f82770513edcd5224f066f..6bd4256d8008506898ffe09fa854eb8282d1176b 100644 Binary files a/Latest_Group_Project/Booking_System/migrations/__pycache__/0001_initial.cpython-310.pyc and b/Latest_Group_Project/Booking_System/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/migrations/__pycache__/0004_remove_representative_user.cpython-310.pyc b/Latest_Group_Project/Booking_System/migrations/__pycache__/0004_remove_representative_user.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..183bf77d5baeaf39feedabb8beaca7ebbac27cea Binary files /dev/null and b/Latest_Group_Project/Booking_System/migrations/__pycache__/0004_remove_representative_user.cpython-310.pyc differ diff --git a/Latest_Group_Project/Booking_System/models.py b/Latest_Group_Project/Booking_System/models.py index 4f034d73aad873082ea1ecce560b3d1719563783..7b4aae855dd1a7758cb8cfe6d42bbc07d648b41f 100644 --- a/Latest_Group_Project/Booking_System/models.py +++ b/Latest_Group_Project/Booking_System/models.py @@ -101,7 +101,7 @@ class Representative(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) date_of_birth = models.DateField() - user = models.OneToOneField('CustomUser', on_delete=models.CASCADE, null=True) + # user = models.OneToOneField('CustomUser', on_delete=models.CASCADE, null=True) rep_number = models.CharField(max_length=50, unique=True, blank=True) def __str__(self): @@ -127,15 +127,21 @@ class CustomUser(AbstractUser): REQUIRED_FIELDS = ['email', 'password', 'user_type', 'first_name', 'last_name'] def get_account(self): - """ - Get the account associated with this user. Returns None if no account is found. - """ if self.user_type == 3: - return self.student.accounts.first() + account = self.student.accounts.first() elif self.user_type == 4: - return self.club_rep.club.account + if self.club_rep.accounts.exists(): + account = self.club_rep.accounts.first() + else: + # create a new account for the club rep + account_title = f"{self.club_rep.representative.first_name} {self.club_rep.representative.last_name} Account" + account = Account.objects.create(account_title=account_title, club_rep=self.club_rep) else: - return None + account = None + + print(f"Account: {account}") + + return account class Club(models.Model): @@ -163,11 +169,8 @@ class ClubRep(models.Model): return self.user.first_name + ' ' + self.user.last_name @property - def account(self): - if self.pk: - return Account.objects.get(content_type=ContentType.objects.get_for_model(self), object_id=self.pk) - else: - return None + def club_account(self): + return self.club.account class Student(models.Model): Student_id = models.AutoField(primary_key=True) @@ -201,6 +204,19 @@ class Account(models.Model): self.account_holder_name = self.club_rep.user.username super(Account, self).save(*args, **kwargs) +class PaymentDetail(models.Model): + account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='payment_details') + # student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='payment_details') + account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='payment_details') + cardholder_name = models.CharField(max_length=100) + card_number = models.CharField(max_length=16) + expiration_month = models.CharField(max_length=2) + expiration_year = models.CharField(max_length=4) + cvv = models.CharField(max_length=3) + + def __str__(self): + return f"{self.account.content_object.user.username} - {self.card_number[-4:]}" + class Booking(models.Model): film = models.ForeignKey(Film, on_delete=models.CASCADE) screen = models.ForeignKey(Screen, on_delete=models.CASCADE) @@ -219,14 +235,3 @@ class Booking(models.Model): -class PaymentDetail(models.Model): - # student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='payment_details') - account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='payment_details') - cardholder_name = models.CharField(max_length=100) - card_number = models.CharField(max_length=16) - expiration_month = models.CharField(max_length=2) - expiration_year = models.CharField(max_length=4) - cvv = models.CharField(max_length=3) - - def __str__(self): - return f"{self.account.content_object.user.username} - {self.card_number[-4:]}" \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/permissions.py b/Latest_Group_Project/Booking_System/permissions.py index f6e08115c4a376ad51b8a83a15b6e54abb60ffaa..bda1ac9f797c90f1d67a20eea4e2dc907b0b04fc 100644 --- a/Latest_Group_Project/Booking_System/permissions.py +++ b/Latest_Group_Project/Booking_System/permissions.py @@ -3,9 +3,6 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied def User_in_group(group_name): - """ - Decorator factory to check if a user belongs to a specific group. - """ def decorator(view_func): def _wrapped_view(request, *args, **kwargs): if request.user.groups.filter(name=group_name).exists(): diff --git a/Latest_Group_Project/Booking_System/serializers.py b/Latest_Group_Project/Booking_System/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..43516870a8f504eef47556839fbb64b8702520b7 --- /dev/null +++ b/Latest_Group_Project/Booking_System/serializers.py @@ -0,0 +1,10 @@ +from djoser.serializers import UserCreateSerializer as BaseUserCreateSerializer + + +class UserCreateSerializer(BaseUserCreateSerializer): + class Meta(BaseUserCreateSerializer.Meta): + fields = ("id", "username", "email", + "password", "first_name", "last_name") + + + diff --git a/Latest_Group_Project/Booking_System/static/Booking_System/site.css b/Latest_Group_Project/Booking_System/static/Booking_System/site.css index 755213b7a1b8793a3a7fafddf90f56f5f0ad01fb..9436908551145d5837043a38d67efad3e036256b 100644 --- a/Latest_Group_Project/Booking_System/static/Booking_System/site.css +++ b/Latest_Group_Project/Booking_System/static/Booking_System/site.css @@ -322,11 +322,23 @@ input[type=text], input[type=password], input[type=email] { } .alert { + padding: 20px; + /* background-color: #03CF7B; */ + color: white; +} + +.alert.success { padding: 20px; background-color: #03CF7B; color: white; } - + +.alert.error { + padding: 20px; + background-color: red; + color: white; +} + .closebtn { margin-left: 15px; color: white; @@ -431,7 +443,7 @@ thead { } th, td { - padding: 10px; + padding: 20px; text-align: left; vertical-align: middle; } @@ -558,6 +570,36 @@ border-bottom: 2px solid #2acec0; border-top: none; } +.topup-container { + display: flex; + flex-direction: column; + align-items: center; + max-width: 500px; + margin: 0 auto; +} + +.topup-container h2 { + margin-bottom: 1rem; +} + +.topup-container h4 { + margin-bottom: 1rem; +} + +.topup-container .topup-button { + background-color: #007bff; + border: 1px solid #007bff; + color: #fff; + cursor: pointer; + font-size: 1.25rem; + margin: 0.5rem; + padding: 0.75rem 1.5rem; +} + +.topup-container .topup-button:hover { + background-color: #0069d9; + border-color: #0062cc; +} @media screen and (max-width: 768px) { .navigation { diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_film.html b/Latest_Group_Project/Booking_System/templates/Booking_System/add_showtime.html similarity index 77% rename from Latest_Group_Project/Booking_System/templates/Booking_System/manage_film.html rename to Latest_Group_Project/Booking_System/templates/Booking_System/add_showtime.html index 0c460dc17b1f278e9b215bfbab7464babfd4be80..b4c52c897dc0cfecbd2ad2a3f08e70cede8b4a27 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_film.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/add_showtime.html @@ -7,7 +7,7 @@ Manage Film {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> @@ -23,7 +23,7 @@ Manage Film </form> <h2>Show Times</h2> - <table> + <table class="table table-striped"> <thead> <tr> <th>Film Schedule</th> @@ -33,7 +33,7 @@ Manage Film <tr> <td> {% for showtime in showtimes %} - <p>{{ showtime.film.title }} - {{ showtime.start_time }} to {{ showtime.end_time }} in Screen {{ showtime.screen.screen_number }} </p> + <p>{{ showtime.film.title }} : Starting: {{ showtime.start_time }} to {{ showtime.end_time }} in Screen {{ showtime.screen.screen_number }} </p> {% endfor %} </td> </tr> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/booking_history.html b/Latest_Group_Project/Booking_System/templates/Booking_System/booking_history.html index 8d0c4646ab3e32a11e06a51142f7832fa90efec4..6a97d709e8a21a8918b73d7fcf4e3661e4658937 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/booking_history.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/booking_history.html @@ -7,7 +7,7 @@ Booking History {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/choose_seats.html b/Latest_Group_Project/Booking_System/templates/Booking_System/choose_seats.html deleted file mode 100644 index b13f9ea4fb4dbbbff1ba415d34e76c4778b8a3a2..0000000000000000000000000000000000000000 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/choose_seats.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "Booking_System/layout.html" %} -{% block title %} -Choose Seats -{% endblock %} - -{% block content %} -<p>Choose Seats</p> -{% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/choose_ticket_amounts.html b/Latest_Group_Project/Booking_System/templates/Booking_System/choose_ticket_amounts.html deleted file mode 100644 index 2a8ec2b3a61fca256390eebc63be67e363ece5a4..0000000000000000000000000000000000000000 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/choose_ticket_amounts.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "Booking_System/layout.html" %} -{% block title %} -Choose Ticket Amounts -{% endblock %} - -{% block content %} -<p>Choose Ticket Amounts</p> -{% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/create_statement_account.html b/Latest_Group_Project/Booking_System/templates/Booking_System/create_statement_account.html index 8bf47c427e9916ea2cb416480a98efa0b82c7b4c..68f770f7f6edddd44cac55b1a01ba7235e37e73d 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/create_statement_account.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/create_statement_account.html @@ -4,22 +4,28 @@ Create Account {% endblock %} {% block content %} + +{% if messages %} +<div class="messages"> + {% for message in messages %} + <div class="alert {{ message.tags }}"> + <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> + <strong>{{ message }}</strong> + </div> + {% endfor %} +</div> +{% endif %} + <div class="container"> <h2>Creating a New Statement Account</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} + <h2>Payment Card Details:</h2> + {{ payment_form.as_p }} <button class="enter_button" type="submit">Create Statement Account</button> </form> - - {% if messages %} - <div class="messages"> - {% for message in messages %} - <div class="{{ message.tags }}" style="color: red;">{{ message }}</div> - {% endfor %} - </div> - {% endif %} </div> {% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/display_all_clubs.html b/Latest_Group_Project/Booking_System/templates/Booking_System/display_all_clubs.html index 96393484c4a09ed74ce88931671d4fb7a918b1b5..d074c1b25938bba8a4ef3de90a0271bc83108d2d 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/display_all_clubs.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/display_all_clubs.html @@ -8,7 +8,7 @@ Display All Clubs <div class="container"> <h1>All Clubs</h1> - <table> + <table class="table table-striped"> <thead> <tr> <th>Name</th> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/display_films.html b/Latest_Group_Project/Booking_System/templates/Booking_System/display_films.html index 3c112af20e2e53c3f29441d13c54f0f76f24b810..77d73042586a5661b28a8304bdde4fd289cad008 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/display_films.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/display_films.html @@ -6,7 +6,7 @@ {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> @@ -30,7 +30,7 @@ <p class="card-text font-weight-bold">Description: {{ film.description }}</p> <p class="card-text font-weight-bold">Cast: {{ film.cast.all|join:', ' }}</p> <p class="card-text font-weight-bold">Director: {{ film.directors.all|join:', ' }}</p> - <p class="card-text font-weight-bold">Rating: {{ film.rating }}</p> + <p class="card-text font-weight-bold">Age Rating: {{ film.age_rating }}</p> <strong class="text-muted mb-2 mr-2">Release Date:{{ film.release_date }}</strong> <br> <br> @@ -47,7 +47,7 @@ </form> </div> <div class="btn-group mt-2"> - <button type="button" onclick="location.href='{% url 'manage_film' %}'" class="btn btn-primary">Add to Showing</button> + <button type="button" onclick="location.href='{% url 'add_showtime' %}'" class="btn btn-primary">Add to Showing</button> <form method="post" action="{% url 'remove_showing' film.film_id %}"> {% csrf_token %} <button type="submit" class="btn btn-sm btn-outline-secondary btn-delete but align-self-center">Remove from Showing</button> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/edit_showing.html b/Latest_Group_Project/Booking_System/templates/Booking_System/edit_showing.html new file mode 100644 index 0000000000000000000000000000000000000000..6845d2b73e1b331115899932f58d2ef9523bcda6 --- /dev/null +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/edit_showing.html @@ -0,0 +1,16 @@ +{% extends "Booking_System/layout.html" %} +{% block title %} +Edit Showing +{% endblock %} + +{% block content %} + +<div class="container"> + <h1>Edit Showing</h1> + <form method="post"> + {% csrf_token %} + {{ form.as_p }} + <button type="submit" class="btn btn-primary">Save Changes</button> + </form> +</div> +{% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/home.html b/Latest_Group_Project/Booking_System/templates/Booking_System/home.html index 7ed3f6aa1136a5ae012ee2859e4c99672878e6c5..65cf510b277516ba172b49888af7038ace9a17fe 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/home.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/home.html @@ -9,7 +9,7 @@ Home {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> @@ -51,19 +51,17 @@ Home <p class="card-text font-weight-bold">Age Rating: {{ film.age_rating }}</p> <p class="card-text font-weight-bold">Available Time:</p> <ul class="list-group list-group-flush text-dark"> - - {% for show_time in film.showtime_set.all|dictsort:"start_time"|slice:":2" %} + + {% for show_time in film.showtime_set.all|dictsort:"start_time"|slice:":2" %} + {% if show_time %} <li class="list-group-item text-dark">{{ show_time.start_time|date:"l" }}: <span class="time-box"><a href="{% url 'ticket_selection_booking' %}" style="text-decoration:none;color:white;"> {{ show_time.start_time|date:"H:i A" }} </a></span></li> - {% endfor %} - + {% else %} + <span class="time-box"><p style = "color:black;">No Showing Available</p></span></li> + {% endif %} + {% endfor %} </ul> - {% comment %} <div class="d-flex justify-content-between align-items-center"> - <div class="btn-group mt-2"> - <button type="button" class="btn btn-sm btn-outline-secondary btn-black">Book</button> - </div> - </div> {% endcomment %} </div> </div> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/layout.html b/Latest_Group_Project/Booking_System/templates/Booking_System/layout.html index 9a5c3f759ebff82c08b0f4e1ca308b89261ce837..e24518025b797f1c1fb3565cc02ed769e55b0b70 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/layout.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/layout.html @@ -50,34 +50,23 @@ <form class="search-form" role="search"> {% if request.user.user_type == 0 %} <div class="no-search-bar"> - <p class="welcome">Welcome, Super User!</p> + <p class="welcome">Welcome, Super User {{ request.user.username}}!</p> </div> - {% comment %} <div class="form-group navbar-form"> - <form class="search-form" method="get" action="{% url 'search_film' %}" role="search"> - <input type="text" class="search-input" name="search" placeholder="Search for Films..." value="{{ request.GET.search }}"> - </form> - </div> {% endcomment %} {% elif request.user.user_type == 1 %} <div class="no-search-bar"> - <p class="welcome">Welcome, Cinema Manager!</p> - - - {% comment %} <form method="GET" action="{% url 'search_film' %}"> - <input type="text" name="query" placeholder="Search films..." required> - <input type="submit" value="Search"> - </form> {% endcomment %} + <p class="welcome">Welcome, Cinema Manager {{ request.user.username}}!</p> </div> {% elif request.user.user_type == 2%} <div class="no-search-bar"> - <p class="welcome">Welcome, Account Manager!</p> + <p class="welcome">Welcome, Account Manager {{ request.user.username}}!</p> </div> {% elif request.user.user_type == 3%} <div class="no-search-bar"> - <p class="welcome">Welcome, Student!</p> + <p class="welcome">Welcome, Student {{ request.user.username}}!</p> </div> {% elif request.user.user_type == 4%} <div class="no-search-bar"> - <p class="welcome">Welcome, Club Representative!</p> + <p class="welcome">Welcome, Club Representative {{ request.user.username}} !</p> </div> {% else %} <div class="no-search-bar"> @@ -96,7 +85,8 @@ {% if request.user.user_type == 0 %} <a style="text-decoration:none;" href="{% url 'add_film' %}">Add Film</a> <a style="text-decoration:none;" href="{% url 'manage_screen' %}">Manage Screens</a> - <a style="text-decoration:none;" href="{% url 'manage_film' %}">Manage Film</a> + <a style="text-decoration:none;" href="{% url 'add_showtime' %}">Add Show Times</a> + <a style="text-decoration:none;" href="{% url 'manage_showing' %}">Manage Showings</a> <a style="text-decoration:none;" href="{% url 'display_film' %}">Display Film</a> <a style="text-decoration:none;" href="{% url 'register_student' %}">Create an Account</a> <a style="text-decoration:none;" href="{% url 'manage_student_account' %}">View Student Accounts</a> @@ -106,7 +96,8 @@ {% elif request.user.user_type == 1 %} <a style="text-decoration:none;" href="{% url 'add_film' %}">Add Film</a> <a style="text-decoration:none;" href="{% url 'manage_screen' %}">Manage Screens</a> - <a style="text-decoration:none;" href="{% url 'manage_film' %}">Manage Show Times</a> + <a style="text-decoration:none;" href="{% url 'add_showtime' %}">Add Show Times</a> + <a style="text-decoration:none;" href="{% url 'manage_showing' %}">Manage Showings</a> <a style="text-decoration:none;" href="{% url 'display_film' %}">Display Film</a> <a style="text-decoration:none;" href="{% url 'register_club' %}">Register a New club</a> <a style="text-decoration:none;" href="{% url 'display_all_clubs' %}">Display All Club</a> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/login.html b/Latest_Group_Project/Booking_System/templates/Booking_System/login.html index f674863c7db0fca33e282cf0fed025417b4d4027..07f5fdb0b2cfb837b0c6cefa124cb30c47b9d070 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/login.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/login.html @@ -12,7 +12,7 @@ Log In <h2>Login</h2> <div class="login-toggle"> <button class="toggle-btn active" onclick="toggleLogin('user')">User</button> - <button class="toggle-btn" onclick="toggleLogin('club', this)" label="Club">Club</button> + <button class="toggle-btn" onclick="toggleLogin('club', this)" label="Club">Club</button> </div> @@ -45,7 +45,7 @@ Log In {% endif %} <button class="enter_button" type="submit">Login</button> </form> - </div> + </div> {% if messages %} <div class="messages"> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_booking.html b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_booking.html index e136411a5493eac24290bc30a611f93a3362ca05..8a2a0b86a93b7a532eeb245e0bbed9cf714ff597 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_booking.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_booking.html @@ -6,7 +6,7 @@ Manage Booking {% block content %} <div class="container"> <h2>Manage Booking</h2> - <table> + <table class="table table-striped"> <thead> <tr> <th>Booking Number</th> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_screen.html b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_screen.html index 8a67a56a5c5fb7e3e4a11b18d276cabefeb4bfc1..9f518f95d7f7c652507d9db26183bbb4ff0cc548 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_screen.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_screen.html @@ -7,7 +7,7 @@ Manage Screen {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/manage_showing.html b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_showing.html new file mode 100644 index 0000000000000000000000000000000000000000..2dd56db681c0cfa00751e42d4053929c517ba2f7 --- /dev/null +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/manage_showing.html @@ -0,0 +1,52 @@ +{% extends "Booking_System/layout.html" %} +{% block title %} +Manage Showing +{% endblock %} + +{% block content %} +{% if messages %} +<div class="messages"> + {% for message in messages %} + <div class="alert {{ message.tags }}"> + <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> + <strong>{{ message }}</strong> + </div> + {% endfor %} +</div> +{% endif %} + +<div class="container"> + <h1>All Showings</h1> + <table class="table table-striped"> + <thead> + <tr> + <th>Start Time</th> + <th>End Time</th> + <th>Film</th> + <th>Screen</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + {% if showings %} + {% for showing in showings %} + <tr> + <td>{{ showing.start_time }}</td> + <td>{{ showing.end_time }}</td> + <td>{{ showing.film.title }}</td> + <td>{{ showing.screen.screen_number }}</td> + <td> + <a href="{% url 'edit_showing' showing.id %}" class="btn btn-primary">Edit</a> + <a href="{% url 'delete_showing' showing.id %}" class="btn btn-danger">Remove Showing</a> + {% comment %} <a href="{% url 'booking_history' %}" class="btn btn-warning">View History</a> {% endcomment %} + {% comment %} <a href="{% url 'account_statement' account.user.id %}" class="btn btn-info">View Statement</a> {% endcomment %} + </td> + </tr> + {% endfor %} + {% else %} + <td>You have currently no showings recorded.</td> + {% endif %} + </tbody> + </table> +</div> +{% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/now_showing.html b/Latest_Group_Project/Booking_System/templates/Booking_System/now_showing.html index 9525c33ab060408b9a6a2010f72d06b848735c8b..085b421712f0c6c06547f3ebd994be90270925b9 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/now_showing.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/now_showing.html @@ -4,57 +4,6 @@ Now Showing {% endblock %} {% block content %} -{% comment %} <div class="container "> - - <div class="tab-bar" id="tab-bar"> - {% for day in days_of_week %} - <div class="tab"> - <button id="{{ day|lower }}" data-day="{{ day|lower }}" onclick="filterFilms(event)">{{ day }}</button> - </div> - {% endfor %} - </div> - - <table class="showing-table"> - <thead> - <tr> - <th id="title-row" colspan="7">Now Showing</th> - </tr> - </thead> - <tbody> - {% if films %} - {% for film in films %} - <tr class="film" data-showing-on="{{ film.showtime.all.0.start_time|date:'l'|lower }}"> - <td class="showing-date">{{ film.showtime.all.0.start_time|date:"Y-m-d" }}</td> - <td>{{ film.showtime.all.0.start_time|date:"l, F d, Y" }}</td> - <td> - <div class="film-info"> - <div class="film-title">{{ film.title }}</div> - <img class="now-showing-img" src="{{ film.image.url }}" alt="{{ film.title }} Image"> - </div> - </td> - <td> - <ul class="list-group"> - {% for show_time in show_times %} - {% if show_time.film == film %} - <li class="list-group-item text-dark"> - {{ show_time.start_time|date:"l" }}: - <span class="time-box">{{ show_time.start_time|date:"H:i A" }}</span> - </li> - {% endif %} - {% endfor %} - </ul> - </td> - </tr> - {% endfor %} - {% else %} - <tr> - <td colspan="4">No showing today.</td> - </tr> - {% endif %} - </tbody> - </table> - -</div> {% endcomment %} <div class="container "> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/payment.html b/Latest_Group_Project/Booking_System/templates/Booking_System/payment.html index 8dc167f444be544b37d3237ae44282a6fcd21727..227412ad9d4e600ee33274edb5c97880242e6cf7 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/payment.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/payment.html @@ -4,7 +4,19 @@ Payment {% endblock %} {% block content %} -<div class="container"> + <div class="container"> + <div class="topup-container"> + <h2>Top Up Credits</h2> + <form method="post"> + {% csrf_token %} + <h4>Choose a top-up amount:</h4> + {% for amount in amounts %} + <button type="submit" name="topup_amount" value="{{ amount }}" class="topup-button">£{{ amount }}</button> + {% endfor %} + </form> + </div> + </div> +{% comment %} <div class="container"> <h1>Top Up Credits</h1> <h3>Payment Details:</h3> <form method="POST"> @@ -59,5 +71,5 @@ Payment {% endif %} -</div> +</div> {% endcomment %} {% endblock %} \ No newline at end of file diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/search_film.html b/Latest_Group_Project/Booking_System/templates/Booking_System/search_film.html index b7d9b2f4ead80152dc57d52e7157fcb114beb3e8..d8ef7adfcb66daafd385c2a5be1dc5473e4b9843 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/search_film.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/search_film.html @@ -1,49 +1,45 @@ {% extends "Booking_System/layout.html" %} {% block title %} -Films +Search Films {% endblock %} {% block content %} -{% if messages %} -<div class="messages"> - {% for message in messages %} - <div class="alert"> - <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> - <strong>{{ message }}</strong> - </div> - {% endfor %} -</div> -{% endif %} -<div class="container"> - <h1>Search Films</h1> - <form method="GET" action="{% url 'search_film' %}"> - <input type="text" name="query" placeholder="Search films..." value="{{ query }}" required> - <input type="submit" value="Search" class="btn btn-primary"> - </form> - {% if film %} - <h2>{{ film.title }}</h2> - <img src="{{ film.image.url }}" alt="{{ film.title }}" style="max-width: 200px"> - <p><strong>Release Date:</strong> {{ film.release_date }}</p> - <p><strong>Rating:</strong> {{ film.rating }}</p> - <p><strong>Directors:</strong> {{ film.directors.all|join:", " }}</p> - <p><strong>Cast:</strong> {{ film.cast.all|join:", " }}</p> - <p>{{ film.description }}</p> - <form method="POST" action="{% url 'add_film' %}"> - {% csrf_token %} - <input type="hidden" name="title" value="{{ film.title }}"> - <input type="hidden" name="release_date" value="{{ film.release_date }}"> - <input type="hidden" name="rating" value="{{ film.rating }}"> - <input type="hidden" name="description" value="{{ film.description }}"> - <input type="hidden" name="image" value="{{ film.image.url }}"> - <input type="hidden" name="directors" value="{{ film.directors.all|join:',' }}"> - <input type="hidden" name="cast" value="{{ film.cast.all|join:',' }}"> - <input type="submit" value="Add to Database" class="btn btn-primary"> + {% if messages %} + <div class="messages"> + {% for message in messages %} + <div class="alert {{ message.tags }}"> + <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> + <strong>{{ message }}</strong> + </div> + {% endfor %} + </div> + {% endif %} + + <div class="container"> + <h1>Search Films</h1> + <form method="GET" action="{% url 'search_film' %}"> + <input type="text" name="query" placeholder="Search films..." value="{{ query }}" required> + <input type="submit" value="Search" class="btn btn-primary"> </form> - {% else %} - {% if query %} - <p>No films found for "{{ query }}".</p> + {% if film %} + <h2>{{ film.title }}</h2> + <img src="https://image.tmdb.org/t/p/w300{{ film.poster_path }}" alt="{{ film.title }}"> + <p><strong>Release Date:</strong> {{ film.release_date }}</p> + <p><strong>Rating:</strong> {{ film.age_rating }}</p> + <p><strong>Director:</strong> {{ film.director }}</p> + <p><strong>Cast:</strong> {{ film.cast|join:", " }}</p> + <p>{{ film.description }}</p> + <form method="POST" action="{% url 'add_film_api' %}"> + {% csrf_token %} + <input type="hidden" name="film_id" value="{{ film_id }}"> + <input type="submit" value="Add to Database" class="btn btn-primary"> + </form> + {% else %} + {% if query %} + <p>No films found for "{{ query }}".</p> + {% endif %} {% endif %} - {% endif %} -</div> + </div> + {% endblock %} diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/ticket_booking.html b/Latest_Group_Project/Booking_System/templates/Booking_System/ticket_booking.html index 7ef67e560ceef3a2a43be2db2d1fa8641a6b6c7a..32d7b645f430a7467cb1d02a5b8b6dc0d24597a8 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/ticket_booking.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/ticket_booking.html @@ -8,6 +8,15 @@ Payment <h1>Select Tickets:</h1> <form method="POST"> {% csrf_token %} + <div class="quantity"> + <label>Child:</label> + <div class="input-group"> + <button type="button" class="btn minus-btn" data-type="adult" onclick="decrementValue('adult')">-</button> + <input type="number" name="adults" value="0" min="0" max="100" oninput="this.value=this.value.replace(/[^0-9]/g,'');" /> + <button type="button" class="btn plus-btn" data-type="adult" onclick="incrementValue('adult')">+</button> + </div> + </div> + <div class="quantity"> <label>Adult:</label> <div class="input-group"> diff --git a/Latest_Group_Project/Booking_System/templates/Booking_System/view_all_account.html b/Latest_Group_Project/Booking_System/templates/Booking_System/view_all_account.html index b0dbe34cb980f3e4d16d60914607e55476553b35..871b104eef71cd5bda186138e660bad67f6b15a8 100644 --- a/Latest_Group_Project/Booking_System/templates/Booking_System/view_all_account.html +++ b/Latest_Group_Project/Booking_System/templates/Booking_System/view_all_account.html @@ -7,7 +7,7 @@ View Statement Account {% if messages %} <div class="messages"> {% for message in messages %} - <div class="alert"> + <div class="alert {{ message.tags }}"> <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> <strong>{{ message }}</strong> </div> diff --git a/Latest_Group_Project/Booking_System/urls.py b/Latest_Group_Project/Booking_System/urls.py index 4ef2f74c6436097e12f16f4b445eaa38f87ee340..62b172952a6d5511e270a352a35777c2662193cf 100644 --- a/Latest_Group_Project/Booking_System/urls.py +++ b/Latest_Group_Project/Booking_System/urls.py @@ -7,8 +7,6 @@ from django.urls import path, include urlpatterns = [ path("", views.home, name="home"), - path("films/", views.films, name="films"), - path("manage_film/", views.manage_film, name="manage_film"), path("login_view/", views.login_view, name="login_view"), path("register_student/", views.register_student, name="register_student"), path("logout_view/", views.logout_view, name="logout_view"), @@ -16,22 +14,26 @@ urlpatterns = [ path("add_film/", views.add_film, name="add_film"), path("edit_film/<int:film_id>", views.edit_film, name="edit_film"), path("display_film/", views.display_film, name="display_film"), - path('manage_film/', views.manage_film, name='manage_film'), + path('add_showtime/', views.add_showtime, name='add_showtime'), path('showtime/<int:showing_id>/remove_showing/', views.remove_showing, name='remove_showing'), path('now_showing/', views.now_showing, name='now_showing'), path('manage_booking/', views.manage_booking, name='manage_booking'), path('manage_student_account/', views.manage_student_account, name='manage_student_account'), path('manage_screen/', views.manage_screen, name='manage_screen'), + path('manage_showing/', views.manage_showing, name='manage_showing'), path('film/<int:film_id>/remove_showing/', views.remove_showing, name='remove_showing'), path('view_all_account/', views.view_all_account, name='view_all_account'), path('edit_account/<int:student_id>/', views.edit_account, name='edit_account'), path('delete_account/<int:student_id>/', views.delete_account, name='delete_account'), path('edit_screen/<int:screen_id>/', views.edit_screen, name='edit_screen'), + path('edit_showing/<int:showing_id>/', views.edit_showing, name='edit_showing'), path('delete_screen/<int:screen_id>/', views.delete_screen, name='delete_screen'), + path('delete_showing/<int:showing_id>/', views.delete_showing, name='delete_showing'), path('film/<int:film_id>/delete/', views.delete_film, name='delete_film'), path('topup/', views.topup, name='topup'), path('booking/<int:booking_id>/cancel/', cancel_booking, name='cancel_booking'), path('search_film/', views.search_film, name='search_film'), + path('add_film_api/', views.add_film_api, name='add_film_api'), path('provide_discount/<int:student_id>/', views.provide_discount, name='provide_discount'), path('remove_discount/<int:student_id>/', views.remove_discount, name='remove_discount'), path('booking_history/', views.booking_history, name='booking_history'), diff --git a/Latest_Group_Project/Booking_System/views.py b/Latest_Group_Project/Booking_System/views.py index 0df41b5dfa1fef2131a6b94fc160a4bde5fa73a9..ba1e67da335c6d8e0c1d46d8ff1eaa15d7fee3e8 100644 --- a/Latest_Group_Project/Booking_System/views.py +++ b/Latest_Group_Project/Booking_System/views.py @@ -20,6 +20,9 @@ import uuid from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.core.files.uploadedfile import InMemoryUploadedFile +from django.contrib.auth.hashers import make_password +import secrets, string +from django.contrib.sessions.models import Session User = get_user_model() @@ -34,9 +37,6 @@ def home(request): return render(request, 'Booking_System/home.html', {'now_showing_films': now_showing_films, 'film_images': film_images, 'today':week_today[0]}) -def films(request): - return render(request, "Booking_System/films.html") - @transaction.atomic def remove_showing(request, showing_id): @@ -56,17 +56,17 @@ def login_view(request): if form.is_valid(): user = form.get_user() login(request, user) - messages.success(request, 'Login Successful.') + messages.success(request, 'Logged In Successfully.') return redirect('home') elif club_form.is_valid(): user = club_form.get_user() if user.user_type == 4: login(request, user) - messages.success(request, 'Login Successful.') + messages.success(request, 'Logged In Successfully.') return redirect('home') else: - messages.error(request, 'Invalid Login2 Credentials.') + messages.error(request, 'Invalid Login Credentials.') return redirect('login_view') else: @@ -113,15 +113,22 @@ def register_club(request): club.save() # representative.rep_number = uuid.uuid4().hex[:10] + + characters = string.ascii_letters + string.digits + password = ''.join(secrets.choice(characters) for i in range(9)) + # hashed_password = + print('Password for club rep:', password) # Create new CustomUser for Club Representative user = CustomUser.objects.create( username=representative.rep_number, email=contact.email, first_name=representative.first_name, last_name=representative.last_name, + password=make_password(password), + # password=password, user_type=4, # Club Representative user type ) - user.set_password(representative_form.cleaned_data['password']) + # user.set_password(representative_form.cleaned_data['password']) user.save() # representative.user = user @@ -212,10 +219,19 @@ def edit_film(request, film_id): @login_required def delete_film(request, film_id): film = get_object_or_404(Film, pk=film_id) + + # Check if any showings are related to this film + still_showing = ShowTime.objects.filter(film=film).exists() + if request.method == 'POST': - film.delete() - messages.success(request, 'Film Deleted Successfully.') - return redirect('display_film') + if not still_showing: + film.delete() + messages.success(request, 'Film Deleted Successfully.') + return redirect('display_film') + else: + messages.error(request, 'This Film is still in showing, Cannot Delete.') + return redirect('display_film') + return redirect('home') @login_required @@ -225,6 +241,7 @@ def remove_showing(request, film_id): show_times.delete() film.now_showing = False film.save() + messages.success(request, 'Film Showing Removed Successfully.') return redirect('home') @login_required @@ -233,7 +250,7 @@ def display_film(request): return render(request, 'Booking_System/display_films.html', {'films': films}) @login_required -def manage_film(request): +def add_showtime(request): if request.method == 'POST': form = ShowTimeForm(request.POST) if form.is_valid(): @@ -248,12 +265,12 @@ def manage_film(request): film.now_showing = True film.save() messages.success(request, 'Film Showtime Added') - return redirect('manage_film') + return redirect('add_showtime') else: form = ShowTimeForm() showtimes = ShowTime.objects.all().order_by('start_time') - return render(request, 'Booking_System/manage_film.html', {'form': form, 'showtimes': showtimes}) + return render(request, 'Booking_System/add_showtime.html', {'form': form, 'showtimes': showtimes}) @login_required def manage_screen(request): @@ -276,6 +293,12 @@ def manage_screen(request): return render(request, 'Booking_System/manage_screen.html', {'form': form, 'screens': screens}) +def manage_showing(request): + showings = ShowTime.objects.all() + return render(request, 'Booking_System/manage_showing.html', {'showings': showings}) + + + def now_showing(request): today = datetime.now().date() selected_day_str = request.GET.get('day') @@ -371,6 +394,7 @@ def delete_account(request, student_id): messages.success(request, 'Account Deleted Successfully') return redirect('manage_account') + @login_required def edit_screen(request, screen_id): try: @@ -395,7 +419,29 @@ def edit_screen(request, screen_id): return render(request, 'Booking_System/edit_screen.html', {'form': form}) - +@login_required +def edit_showing(request, showing_id): + try: + showings = ShowTime.objects.all() + showing = ShowTime.objects.get(id=showing_id) + + if request.method == 'POST': + form = EditShowingForm(request.POST, instance=showing) + if form.is_valid(): + form.save() + messages.success(request, 'Showing Updated Successfully') + return redirect('manage_showing') + else: + form = EditShowingForm(instance=showing) + context = {'form': form} + + return render(request, 'Booking_System/edit_showing.html', context) + + except Screen.DoesNotExist: + messages.error(request, 'No Showing Recorded Yet') + return redirect('home') + + return render(request, 'Booking_System/edit_showing.html', {'form': form}) @login_required def delete_screen(request, screen_id): @@ -404,6 +450,15 @@ def delete_screen(request, screen_id): messages.success(request, 'Screen Deleted Successfully') return redirect('manage_screen') +@login_required +def delete_showing(request, showing_id): + showing = ShowTime.objects.get(id=showing_id) + film = showing.film + film.now_showing = False + film.save() + showing.delete() + messages.success(request, 'Showing Removed Successfully') + return redirect('manage_showing') @login_required def view_all_account(request): @@ -440,43 +495,60 @@ def edit_account_statement(request, account_id): @login_required def topup(request): if request.method == 'POST': - form = PaymentForm(request.POST) - if form.is_valid(): - # get the current student - student = request.user.student - - # create a new Account object with foreign key to the student - account = Account( - credit_left=form.cleaned_data['amount'], - discount_rate=0, - content_type=ContentType.objects.get_for_model(Student), - object_id=student.pk, - ) - account.save() - - # create a new PaymentDetail object with foreign key to the account - payment = PaymentDetail( - account=account, - cardholder_name=form.cleaned_data['cardholder_name'], - card_number=form.cleaned_data['card_number'], - expiration_month=form.cleaned_data['expiration_date'][:2], - expiration_year=form.cleaned_data['expiration_date'][-4:], - cvv=form.cleaned_data['cvv'] - ) - payment.save() - - messages.success(request, f'Top-up successful! You have added {form.cleaned_data["amount"]} credits to your account.') - - return redirect('home') + amount = int(request.POST.get('topup_amount')) + account = request.user.get_account() + account.credit_left += amount + account.save() + messages.success(request, f"You've topped up £{amount}. Your new balance is £{account.credit_left}.") + return redirect('home') else: - form = PaymentForm() - return render(request, 'Booking_System/payment.html', {'form': form}) + amounts = [1, 5, 10, 50, 100] + return render(request, 'Booking_System/payment.html', {'amounts': amounts}) + # if request.method == 'POST': + # form = PaymentForm(request.POST) + # if form.is_valid(): + # # get the current student + # student = request.user.student + + # # create a new Account object with foreign key to the student + # account = Account( + # credit_left=form.cleaned_data['amount'], + # discount_rate=0, + # content_type=ContentType.objects.get_for_model(Student), + # object_id=student.pk, + # ) + # account.save() + + # # create a new PaymentDetail object with foreign key to the account + # payment = PaymentDetail( + # account=account, + # cardholder_name=form.cleaned_data['cardholder_name'], + # card_number=form.cleaned_data['card_number'], + # expiration_month=form.cleaned_data['expiration_date'][:2], + # expiration_year=form.cleaned_data['expiration_date'][-4:], + # cvv=form.cleaned_data['cvv'] + # ) + # payment.save() + + # messages.success(request, f'Top-up successful! You have added {form.cleaned_data["amount"]} credits to your account.') + + # return redirect('home') + # else: + # form = PaymentForm() + # return render(request, 'Booking_System/payment.html', {'form': form}) @login_required def create_statement_account(request): if request.method == 'POST': form = CreateStatementAccountForm(user=request.user, data=request.POST) - if form.is_valid(): + payment_form = PaymentForm(request.POST) + + account_title = request.POST.get('account_title') + if Account.objects.filter(account_title=account_title).exists(): + messages.error(request, 'Account title already exists. Please choose a different title.') + return redirect('create_statement_account') + + if form.is_valid() and payment_form.is_valid(): account = form.save() account.user = request.user @@ -493,6 +565,16 @@ def create_statement_account(request): elif account.club_rep is not None: # Add account to the club rep's account list account.club_rep.accounts.add(account) + + payment = PaymentDetail( + account=account, + cardholder_name=payment_form.cleaned_data['cardholder_name'], + card_number=payment_form.cleaned_data['card_number'], + expiration_month=payment_form.cleaned_data['expiration_date'][:2], + expiration_year=payment_form.cleaned_data['expiration_date'][-4:], + cvv=payment_form.cleaned_data['cvv'] + ) + payment.save() # Do something with the newly created account object messages.success(request, 'Statement Account Created Successfully') @@ -500,7 +582,8 @@ def create_statement_account(request): return redirect('home') else: form = CreateStatementAccountForm(user=request.user) - return render(request, 'Booking_System/create_statement_account.html', {'form': form}) + payment_form = PaymentForm() + return render(request, 'Booking_System/create_statement_account.html', {'form': form, 'payment_form': payment_form}) @login_required def delete_statement_account(request, account_id): @@ -519,9 +602,17 @@ def cancel_booking(request, booking_id): def fetch_film_data(film_id, api_key): - film_url = f'https://api.themoviedb.org/3/movie/{film_id}?api_key={api_key}&append_to_response=credits' + film_url = f'https://api.themoviedb.org/3/movie/{film_id}?api_key={api_key}&append_to_response=credits,release_dates' response = requests.get(film_url) film_data = response.json() + + # Getting the age rating (certification) + certification = None + for release in film_data['release_dates']['results']: + if release['iso_3166_1'] == 'US': + certification = release['release_dates'][0]['certification'] + break + return { 'title': film_data['title'], 'release_date': film_data['release_date'], @@ -529,7 +620,8 @@ def fetch_film_data(film_id, api_key): 'rating': film_data['vote_average'], 'poster_path': film_data['poster_path'], 'director': film_data['credits']['crew'][0]['name'], - 'cast': [cast['name'] for cast in film_data['credits']['cast'][:5]] + 'cast': [cast['name'] for cast in film_data['credits']['cast'][:5]], + 'age_rating': certification } @login_required @@ -541,162 +633,67 @@ def search_film(request): if query: search_url = f'https://api.themoviedb.org/3/search/movie?api_key={api_key}&query={query}' response = requests.get(search_url) - print(response.content) # Add this line to print the response's content + search_data = response.json() search_results = search_data['results'] if search_results: film_id = search_results[0]['id'] - film_data = fetch_film_data(film_id, api_key) + film = fetch_film_data(film_id, api_key) - # Check if film with the same title already exists in the database - if Film.objects.filter(title=film_data['title']).exists(): - messages.warning(request, 'A film with this title already exists.') - return redirect('search_film') - - # Save the film's image to the image field - response = requests.get(f'https://image.tmdb.org/t/p/w200{film_data["poster_path"]}') - image_file = io.BytesIO(response.content) - image_filename = f'{film_data["title"]}.jpg' - film_image = InMemoryUploadedFile( - image_file, - None, - image_filename, - 'image/jpeg', - len(response.content), - None - ) - - # Create new Film instance and save to database - film = Film.objects.create( - title=film_data['title'], - release_date=datetime.strptime(film_data['release_date'], '%Y-%m-%d').date(), - description=film_data['overview'], - age_rating=int(film_data['age_rating']), - image=film_image - ) - - # Add directors to the film - director_names = [film_data['director']] - directors = [Director.objects.get_or_create(name=name)[0] for name in director_names] - film.directors.set(directors) - - # Add cast to the film - cast_names = film_data['cast'] - cast = [Cast.objects.get_or_create(name=name)[0] for name in cast_names] - film.cast.set(cast) - - messages.success(request, 'Film added successfully.') - - context = {'film': film, 'query': query} + context = {'film': film, 'query': query, 'film_id': film_id if film else None} return render(request, 'Booking_System/search_film.html', context) -# def fetch_film_data(film_id, api_key): -# film_url = f'https://api.themoviedb.org/3/movie/{film_id}?api_key={api_key}&append_to_response=credits' -# response = requests.get(film_url) -# film_data = response.json() -# return { -# 'title': film_data['title'], -# 'release_date': film_data['release_date'], -# 'overview': film_data['overview'], -# 'rating': film_data['vote_average'], -# 'poster_path': film_data['poster_path'], -# 'director': film_data['credits']['crew'][0]['name'], -# 'cast': [cast['name'] for cast in film_data['credits']['cast'][:5]] -# } - - -# def search_film(request): -# query = request.GET.get('query') -# search_url = f'https://api.themoviedb.org/3/search/movie?api_key=YOUR_API_KEY&query={query}' - -# try: -# response = requests.get(search_url) -# search_data = response.json() -# search_results = search_data['results'] -# # Handle case where no search results were found -# if not search_results: -# message = f"No results found for '{query}'" -# return render(request, 'search_results.html', {'message': message}) - -# # Process search results and render them in the template -# context = {'search_results': search_results} -# return render(request, 'search_results.html', context) -# except ConnectionError: -# message = "Could not connect to the movie database. Please try again later." -# return render(request, 'search_results.html', {'message': message}) - - -# def add_search_film(request, film_id): -# api_key = settings.TMDB_API_KEY - -# # Fetch film data from TMDB API -# film_data = fetch_film_data(film_id, api_key) - -# # Check if film with the same title already exists in the database -# if Film.objects.filter(title=film_data['title']).exists(): -# messages.warning(request, 'A film with this title already exists.') -# return redirect('search_film') - -# # Save the film's image to the image field -# response = requests.get(f'https://image.tmdb.org/t/p/w200{film_data["poster_path"]}') -# image_file = io.BytesIO(response.content) -# image_filename = f'{film_data["title"]}.jpg' -# film_image = InMemoryUploadedFile( -# image_file, -# None, -# image_filename, -# 'image/jpeg', -# len(response.content), -# None -# ) - -# # Create new Film instance and save to database -# film = Film.objects.create( -# title=film_data['title'], -# release_date=datetime.strptime(film_data['release_date'], '%Y-%m-%d').date(), -# description=film_data['overview'], -# rating=float(film_data['rating']), -# image=film_image -# ) - -# # Add directors to the film -# director_names = [film_data['director']] -# directors = [Director.objects.get_or_create(name=name)[0] for name in director_names] -# film.directors.set(directors) - -# # Add cast to the film -# cast_names = film_data['cast'] -# cast = [Cast.objects.get_or_create(name=name)[0] for name in cast_names] -# film.cast.set(cast) - -# messages.success(request, 'Film added successfully.') -# return redirect('search_film') - -# def fetch_film_data(film_id, api_key): -# film_url = f'https://api.themoviedb.org/3/movie/{film_id}?api_key={api_key}&append_to_response=credits' -# response = requests.get(film_url) -# film_data = response.json() - -# # Extract relevant film data from API response -# return { -# 'title': film_data['title'], -# 'release_date': film_data['release_date'], -# 'overview': film_data['overview'], -# 'rating': film_data['vote_average'], -# 'director': get_director(film_data['credits']['crew']), -# 'cast': get_cast(film_data['credits']['cast']), -# 'poster_path': film_data['poster_path'], -# } - - -# def get_director(crew): -# for member in crew: -# if member['job'] == 'Director': -# return member['name'] -# return 'Unknown Director' +@login_required +def add_film_api(request): + film_id = request.POST.get('film_id') + api_key = '9ca66987cac35cb481faa3f84b01cf97' + + if film_id: + film_data = fetch_film_data(film_id, api_key) + + # Check if film with the same title already exists in the database + if Film.objects.filter(title=film_data['title']).exists(): + messages.error(request, 'A film with this title already exists.') + return redirect('search_film') + + # Save the film's image to the image field + response = requests.get(f'https://image.tmdb.org/t/p/w200{film_data["poster_path"]}') + image_file = io.BytesIO(response.content) + image_filename = f'{film_data["title"]}.jpg' + film_image = InMemoryUploadedFile( + image_file, + None, + image_filename, + 'image/jpeg', + len(response.content), + None + ) + + # Create new Film instance and save to database + film = Film.objects.create( + title=film_data['title'], + release_date=datetime.strptime(film_data['release_date'], '%Y-%m-%d').date(), + description=film_data['overview'], + age_rating=film_data['age_rating'], + image=film_image + ) + + # Add directors to the film + director_names = [film_data['director']] + directors = [Director.objects.get_or_create(name=name)[0] for name in director_names] + film.directors.set(directors) + + # Add cast to the film + cast_names = film_data['cast'] + cast = [Cast.objects.get_or_create(name=name)[0] for name in cast_names] + film.cast.set(cast) + + messages.success(request, 'Film added successfully.') + + return redirect('search_film') def is_superuser(user): diff --git a/Latest_Group_Project/Group_Project/__pycache__/settings.cpython-310.pyc b/Latest_Group_Project/Group_Project/__pycache__/settings.cpython-310.pyc index b91a57375668375a8a172fd6b430bda8d56da702..b1d016448e7731d4b47e46c5267f498b8f19db56 100644 Binary files a/Latest_Group_Project/Group_Project/__pycache__/settings.cpython-310.pyc and b/Latest_Group_Project/Group_Project/__pycache__/settings.cpython-310.pyc differ diff --git a/Latest_Group_Project/Group_Project/settings.py b/Latest_Group_Project/Group_Project/settings.py index dab237d6e01d3c62f9f6eb9dad8cc93159f93b0c..fff3ea2a141fd7dc1a17e46a4e2b56d3336845b7 100644 --- a/Latest_Group_Project/Group_Project/settings.py +++ b/Latest_Group_Project/Group_Project/settings.py @@ -39,6 +39,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'Booking_System', + 'djoser', ] MIDDLEWARE = [ diff --git a/Latest_Group_Project/film_images/film_images/creed3__sEHYHf5.jpg b/Latest_Group_Project/film_images/film_images/creed3__sEHYHf5.jpg deleted file mode 100644 index 2fc373f8e6fced9fe457cfa5a87de1abe20b0827..0000000000000000000000000000000000000000 Binary files a/Latest_Group_Project/film_images/film_images/creed3__sEHYHf5.jpg and /dev/null differ